package org.opendaylight.controller.sal.binding.dom.serializer.impl import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator import javassist.ClassPool import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl import java.util.Map import org.opendaylight.yangtools.sal.binding.model.api.Type import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder import org.opendaylight.yangtools.yang.model.api.SchemaNode import java.util.concurrent.ConcurrentHashMap import org.opendaylight.yangtools.yang.data.api.CompositeNode import org.opendaylight.yangtools.yang.binding.DataObject import org.opendaylight.yangtools.yang.binding.InstanceIdentifier import java.util.Map.Entry import java.util.AbstractMap.SimpleEntry import org.opendaylight.yangtools.yang.model.api.SchemaPath import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil import java.util.ArrayList import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.binding.DataContainer import static com.google.common.base.Preconditions.*; import java.util.List import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl import org.opendaylight.yangtools.concepts.Delegator import java.util.concurrent.ConcurrentMap import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType import org.opendaylight.yangtools.yang.binding.BindingCodec import com.google.common.collect.HashMultimap import com.google.common.util.concurrent.SettableFuture import java.util.concurrent.Future import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl import org.opendaylight.controller.sal.binding.dom.serializer.impl.LazyGeneratedCodecRegistry import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec import org.opendaylight.yangtools.binding.generator.util.Types class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener { @Property ClassPool pool; private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl); @Property extension TransformerGenerator binding; @Property extension LazyGeneratedCodecRegistry registry; @Property val ConcurrentMap typeDefinitions = new ConcurrentHashMap(); @Property val ConcurrentMap typeToDefinition = new ConcurrentHashMap(); @Property val ConcurrentMap typeToSchemaNode = new ConcurrentHashMap(); val promisedTypeDefinitions = HashMultimap.>create; val promisedSchemas = HashMultimap.>create; override onGlobalContextUpdated(SchemaContext arg0) { recreateBindingContext(arg0); registry.onGlobalContextUpdated(arg0); } def recreateBindingContext(SchemaContext schemaContext) { val newBinding = new BindingGeneratorImpl(); newBinding.generateTypes(schemaContext); for (entry : newBinding.moduleContexts.entrySet) { registry.onModuleContextAdded(schemaContext, entry.key, entry.value); //val module = entry.key; val context = entry.value; updateBindingFor(context.childNodes, schemaContext); updateBindingFor(context.cases, schemaContext); val typedefs = context.typedefs; for (typedef : typedefs.values) { binding.typeDefinitions.put(typedef, typedef as GeneratedType); } val augmentations = context.augmentations; for (augmentation : augmentations) { binding.typeToDefinition.put(augmentation, augmentation); } binding.typeToAugmentation.putAll(context.typeToAugmentation); } } override CompositeNode toDataDom(DataObject data) { toCompositeNodeImpl(data); } override Entry toDataDom( Entry, DataObject> entry) { val key = toDataDom(entry.key) val data = toCompositeNodeImpl(entry.value); return new SimpleEntry(key, data); } private def CompositeNode toCompositeNodeImpl(DataObject object) { val cls = object.implementedInterface; waitForSchema(cls); val codec = registry.getCodecForDataObject(cls) as DataContainerCodec; val ret = codec.serialize(new ValueWithQName(null, object)); return ret as CompositeNode; } private def waitForSchema(Class class1) { val ref = Types.typeForClass(class1); getSchemaWithRetry(ref); } override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom( InstanceIdentifier path) { for (arg : path.path) { waitForSchema(arg.type); } return registry.instanceIdentifierCodec.serialize(path); } override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode node) { if (node == null) { return null; } val targetType = path.targetType val transformer = registry.getCodecForDataObject(targetType); val ret = transformer.deserialize(node)?.value as DataObject; return ret; } private def void updateBindingFor(Map map, SchemaContext module) { for (entry : map.entrySet) { val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key); //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName) if (schemaNode != null) { typeToSchemaNode.put(entry.value, schemaNode); typeToDefinition.put(entry.value, entry.value); updatePromisedSchemas(entry.value, schemaNode); } } } public def void start() { binding = new TransformerGenerator(pool); registry = new LazyGeneratedCodecRegistry() registry.generator = binding //binding.staticFieldsInitializer = registry binding.listener = registry binding.typeToDefinition = typeToDefinition binding.typeToSchemaNode = typeToSchemaNode binding.typeDefinitions = typeDefinitions } private def getTypeDefinition(Type type) { val typeDef = typeToDefinition.get(type); if (typeDef !== null) { return typeDef; } return type.getTypeDefInFuture.get(); } private def Future getTypeDefInFuture(Type type) { val future = SettableFuture.create() promisedTypeDefinitions.put(type, future); return future; } private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) { val futures = promisedTypeDefinitions.get(builder); if (futures === null || futures.empty) { return; } for (future : futures) { future.set(builder); } promisedTypeDefinitions.removeAll(builder); } private def getSchemaWithRetry(Type type) { val typeDef = typeToSchemaNode.get(type); if (typeDef !== null) { return typeDef; } return type.getSchemaInFuture.get(); } private def Future getSchemaInFuture(Type type) { val future = SettableFuture.create() promisedSchemas.put(type, future); return future; } private def void updatePromisedSchemas(Type builder, SchemaNode schema) { val ref = new ReferencedTypeImpl(builder.packageName, builder.name); val futures = promisedSchemas.get(ref); if (futures === null || futures.empty) { return; } for (future : futures) { future.set(schema); } promisedSchemas.removeAll(builder); } }