1 package org.opendaylight.controller.sal.binding.dom.serializer.impl
3 import org.opendaylight.controller.sal.binding.dom.serializer.impl.TransformerGenerator
4 import javassist.ClassPool
5 import org.opendaylight.yangtools.yang.model.api.SchemaContext
6 import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener
7 import org.opendaylight.yangtools.sal.binding.generator.impl.BindingGeneratorImpl
9 import org.opendaylight.yangtools.sal.binding.model.api.Type
10 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
11 import org.opendaylight.yangtools.yang.model.api.SchemaNode
12 import java.util.concurrent.ConcurrentHashMap
13 import org.opendaylight.yangtools.yang.data.api.CompositeNode
14 import org.opendaylight.yangtools.yang.binding.DataObject
15 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
16 import java.util.Map.Entry
17 import java.util.AbstractMap.SimpleEntry
18 import org.opendaylight.yangtools.yang.model.api.SchemaPath
19 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
20 import org.opendaylight.yangtools.yang.binding.DataContainer
21 import java.util.concurrent.ConcurrentMap
22 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
23 import com.google.common.collect.HashMultimap
24 import com.google.common.util.concurrent.SettableFuture
25 import java.util.concurrent.Future
26 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
27 import org.opendaylight.controller.sal.binding.dom.serializer.impl.LazyGeneratedCodecRegistry
28 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService
29 import org.slf4j.LoggerFactory
30 import org.opendaylight.controller.sal.binding.dom.serializer.api.ValueWithQName
31 import org.opendaylight.controller.sal.binding.dom.serializer.api.DataContainerCodec
32 import org.opendaylight.yangtools.binding.generator.util.Types
33 import org.osgi.framework.BundleContext
34 import java.util.Hashtable
35 import org.osgi.framework.ServiceRegistration
36 import org.opendaylight.controller.sal.binding.impl.connect.dom.DeserializationException
37 import java.util.concurrent.Callable
38 import org.opendaylight.yangtools.yang.binding.Augmentation
39 import org.opendaylight.controller.sal.binding.impl.util.YangSchemaUtils
40 import org.opendaylight.controller.sal.binding.dom.serializer.api.AugmentationCodec
41 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
42 import java.util.ArrayList
43 import org.opendaylight.yangtools.yang.data.api.Node
44 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
45 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
47 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
52 private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl);
55 extension TransformerGenerator binding;
58 extension LazyGeneratedCodecRegistry registry;
61 val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
64 val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
67 val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
69 val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
71 val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
73 ServiceRegistration<SchemaServiceListener> listenerRegistration
75 override onGlobalContextUpdated(SchemaContext arg0) {
76 recreateBindingContext(arg0);
77 registry.onGlobalContextUpdated(arg0);
80 def recreateBindingContext(SchemaContext schemaContext) {
81 val newBinding = new BindingGeneratorImpl();
82 newBinding.generateTypes(schemaContext);
84 for (entry : newBinding.moduleContexts.entrySet) {
86 registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
87 binding.pathToType.putAll(entry.value.childNodes)
88 //val module = entry.key;
89 val context = entry.value;
90 updateBindingFor(context.childNodes, schemaContext);
91 updateBindingFor(context.cases, schemaContext);
93 val typedefs = context.typedefs;
94 for (typedef : typedefs.entrySet) {
95 val typeRef = new ReferencedTypeImpl(typedef.value.packageName,typedef.value.name)
96 binding.typeDefinitions.put(typeRef, typedef.value as GeneratedType);
97 val schemaNode = YangSchemaUtils.findTypeDefinition(schemaContext,typedef.key);
98 if(schemaNode != null) {
100 binding.typeToSchemaNode.put(typeRef,schemaNode);
102 LOG.error("Type definition for {} is not available",typedef.value);
106 val augmentations = context.augmentations;
107 for (augmentation : augmentations) {
108 binding.typeToDefinition.put(augmentation, augmentation);
111 binding.typeToAugmentation.putAll(context.typeToAugmentation);
115 override CompositeNode toDataDom(DataObject data) {
116 toCompositeNodeImpl(data);
119 override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
120 Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
123 val key = toDataDom(entry.key)
124 var CompositeNode data;
125 if(Augmentation.isAssignableFrom(entry.key.targetType)) {
126 data = toCompositeNodeImpl(key,entry.value);
128 data = toCompositeNodeImpl(entry.value);
130 return new SimpleEntry(key, data);
132 } catch (Exception e) {
133 LOG.error("Error during serialization for {}.", entry.key,e);
138 private def CompositeNode toCompositeNodeImpl(DataObject object) {
139 val cls = object.implementedInterface;
141 val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
142 val ret = codec.serialize(new ValueWithQName(null, object));
143 return ret as CompositeNode;
147 private def CompositeNode toCompositeNodeImpl(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier identifier,DataObject object) {
149 //val cls = object.implementedInterface;
150 //waitForSchema(cls);
151 val last = identifier.path.last;
152 val codec = registry.getCodecForAugmentation(object.implementedInterface as Class) as AugmentationCodec;
153 val ret = codec.serialize(new ValueWithQName(last.nodeType, object));
154 if(last instanceof NodeIdentifierWithPredicates) {
155 val predicates = last as NodeIdentifierWithPredicates;
156 val newNodes = new ArrayList<Node<?>>(predicates.keyValues.size);
157 for(predicate : predicates.keyValues.entrySet) {
158 newNodes.add(new SimpleNodeTOImpl(predicate.key,null,predicate.value));
160 newNodes.addAll(ret.children);
161 return new CompositeNodeTOImpl(last.nodeType,null,newNodes);
163 return ret as CompositeNode;
166 private def void waitForSchema(Class<? extends DataContainer> class1) {
167 if(Augmentation.isAssignableFrom(class1)) {
168 /* FIXME: We should wait also for augmentations. Currently YANGTools does not provide correct
169 * mapping between java Augmentation classes and augmentations.
173 if(registry.isCodecAvailable(class1)) {
176 val ref = Types.typeForClass(class1);
177 getSchemaWithRetry(ref);
180 override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
181 InstanceIdentifier<? extends DataObject> path) {
182 for (arg : path.path) {
183 waitForSchema(arg.type);
185 return registry.instanceIdentifierCodec.serialize(path);
188 override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
189 return tryDeserialization[ |
193 val targetType = path.targetType
194 val transformer = registry.getCodecForDataObject(targetType);
195 val ret = transformer.deserialize(node)?.value as DataObject;
200 override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
201 return tryDeserialization[ |
202 registry.instanceIdentifierCodec.deserialize(entry);
206 private static def <T> T tryDeserialization(Callable<T> deserializationBlock) throws DeserializationException {
208 deserializationBlock.call()
209 } catch (Exception e) {
211 // FIXME: Make this block providing more information.
212 throw new DeserializationException(e);
216 private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
218 for (entry : map.entrySet) {
219 val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
221 //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
222 val typeRef = new ReferencedTypeImpl(entry.value.packageName,entry.value.name)
223 typeToDefinition.put(typeRef, entry.value);
224 if (schemaNode != null) {
225 typeToSchemaNode.put(typeRef, schemaNode);
226 updatePromisedSchemas(typeRef, schemaNode);
232 public def void start(BundleContext ctx) {
233 binding = new TransformerGenerator(pool);
234 registry = new LazyGeneratedCodecRegistry()
235 registry.generator = binding
237 //binding.staticFieldsInitializer = registry
238 binding.listener = registry
239 binding.typeToDefinition = typeToDefinition
240 binding.typeToSchemaNode = typeToSchemaNode
241 binding.typeDefinitions = typeDefinitions
243 listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
247 private def getSchemaWithRetry(Type type) {
248 val typeDef = typeToSchemaNode.get(type);
249 if (typeDef !== null) {
252 LOG.info("Thread blocked waiting for schema for: {}",type.fullyQualifiedName)
253 return type.getSchemaInFuture.get();
256 private def Future<SchemaNode> getSchemaInFuture(Type type) {
257 val future = SettableFuture.<SchemaNode>create()
258 promisedSchemas.put(type, future);
262 private def void updatePromisedSchemas(Type builder, SchemaNode schema) {
263 val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
264 val futures = promisedSchemas.get(ref);
265 if (futures === null || futures.empty) {
268 for (future : futures) {
271 promisedSchemas.removeAll(builder);
274 override close() throws Exception {
275 listenerRegistration?.unregister();