0da7aec480e2c4f3d470cc9b02ad4c386f8f101f
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / dom / serializer / impl / RuntimeGeneratedMappingServiceImpl.xtend
1 package org.opendaylight.controller.sal.binding.dom.serializer.impl
2
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
8 import java.util.Map
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
39 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable {
40
41     @Property
42     ClassPool pool;
43
44     private static val LOG = LoggerFactory.getLogger(RuntimeGeneratedMappingServiceImpl);
45
46     @Property
47     extension TransformerGenerator binding;
48
49     @Property
50     extension LazyGeneratedCodecRegistry registry;
51
52     @Property
53     val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
54
55     @Property
56     val ConcurrentMap<Type, GeneratedTypeBuilder> typeToDefinition = new ConcurrentHashMap();
57
58     @Property
59     val ConcurrentMap<Type, SchemaNode> typeToSchemaNode = new ConcurrentHashMap();
60
61     val promisedTypeDefinitions = HashMultimap.<Type, SettableFuture<GeneratedTypeBuilder>>create;
62
63     val promisedSchemas = HashMultimap.<Type, SettableFuture<SchemaNode>>create;
64
65     ServiceRegistration<SchemaServiceListener> listenerRegistration
66
67     override onGlobalContextUpdated(SchemaContext arg0) {
68         recreateBindingContext(arg0);
69         registry.onGlobalContextUpdated(arg0);
70     }
71
72     def recreateBindingContext(SchemaContext schemaContext) {
73         val newBinding = new BindingGeneratorImpl();
74         newBinding.generateTypes(schemaContext);
75
76         for (entry : newBinding.moduleContexts.entrySet) {
77
78             registry.onModuleContextAdded(schemaContext, entry.key, entry.value);
79
80             //val module = entry.key;
81             val context = entry.value;
82             updateBindingFor(context.childNodes, schemaContext);
83             updateBindingFor(context.cases, schemaContext);
84
85             val typedefs = context.typedefs;
86             for (typedef : typedefs.values) {
87                 binding.typeDefinitions.put(typedef, typedef as GeneratedType);
88             }
89             val augmentations = context.augmentations;
90             for (augmentation : augmentations) {
91                 binding.typeToDefinition.put(augmentation, augmentation);
92             }
93
94             binding.typeToAugmentation.putAll(context.typeToAugmentation);
95         }
96     }
97
98     override CompositeNode toDataDom(DataObject data) {
99         toCompositeNodeImpl(data);
100     }
101
102     override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
103         Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
104         val key = toDataDom(entry.key)
105         val data = toCompositeNodeImpl(entry.value);
106         return new SimpleEntry(key, data);
107     }
108
109     private def CompositeNode toCompositeNodeImpl(DataObject object) {
110         val cls = object.implementedInterface;
111         waitForSchema(cls);
112         val codec = registry.getCodecForDataObject(cls) as DataContainerCodec<DataObject>;
113         val ret = codec.serialize(new ValueWithQName(null, object));
114         return ret as CompositeNode;
115     }
116
117     private def waitForSchema(Class<? extends DataContainer> class1) {
118         val ref = Types.typeForClass(class1);
119         getSchemaWithRetry(ref);
120     }
121
122     override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
123         InstanceIdentifier<? extends DataObject> path) {
124         for (arg : path.path) {
125             waitForSchema(arg.type);
126         }
127         return registry.instanceIdentifierCodec.serialize(path);
128     }
129
130     override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode node) {
131         return tryDeserialization[ |
132             if (node == null) {
133                 return null;
134             }
135             val targetType = path.targetType
136             val transformer = registry.getCodecForDataObject(targetType);
137             val ret = transformer.deserialize(node)?.value as DataObject;
138             return ret;
139         ]
140     }
141
142     override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) {
143         return tryDeserialization[ |
144             registry.instanceIdentifierCodec.deserialize(entry);
145         ]
146     }
147
148     private static def <T> T tryDeserialization(Callable<T> deserializationBlock) throws DeserializationException {
149         try {
150             deserializationBlock.call()
151         } catch (Exception e) {
152
153             // FIXME: Make this block providing more information.
154             throw new DeserializationException(e);
155         }
156     }
157
158     private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
159         for (entry : map.entrySet) {
160             val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
161
162             //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
163             if (schemaNode != null) {
164                 typeToSchemaNode.put(entry.value, schemaNode);
165                 typeToDefinition.put(entry.value, entry.value);
166                 updatePromisedSchemas(entry.value, schemaNode);
167             }
168         }
169     }
170
171     public def void start(BundleContext ctx) {
172         binding = new TransformerGenerator(pool);
173         registry = new LazyGeneratedCodecRegistry()
174         registry.generator = binding
175
176         //binding.staticFieldsInitializer = registry
177         binding.listener = registry
178         binding.typeToDefinition = typeToDefinition
179         binding.typeToSchemaNode = typeToSchemaNode
180         binding.typeDefinitions = typeDefinitions
181         if (ctx !== null) {
182             listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
183         }
184     }
185
186     private def getTypeDefinition(Type type) {
187         val typeDef = typeToDefinition.get(type);
188         if (typeDef !== null) {
189             return typeDef;
190         }
191         return type.getTypeDefInFuture.get();
192     }
193
194     private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
195         val future = SettableFuture.<GeneratedTypeBuilder>create()
196         promisedTypeDefinitions.put(type, future);
197         return future;
198     }
199
200     private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
201         val futures = promisedTypeDefinitions.get(builder);
202         if (futures === null || futures.empty) {
203             return;
204         }
205         for (future : futures) {
206             future.set(builder);
207         }
208         promisedTypeDefinitions.removeAll(builder);
209     }
210
211     private def getSchemaWithRetry(Type type) {
212         val typeDef = typeToSchemaNode.get(type);
213         if (typeDef !== null) {
214             return typeDef;
215         }
216         return type.getSchemaInFuture.get();
217     }
218
219     private def Future<SchemaNode> getSchemaInFuture(Type type) {
220         val future = SettableFuture.<SchemaNode>create()
221         promisedSchemas.put(type, future);
222         return future;
223     }
224
225     private def void updatePromisedSchemas(Type builder, SchemaNode schema) {
226         val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
227         val futures = promisedSchemas.get(ref);
228         if (futures === null || futures.empty) {
229             return;
230         }
231         for (future : futures) {
232             future.set(schema);
233         }
234         promisedSchemas.removeAll(builder);
235     }
236
237     override close() throws Exception {
238         listenerRegistration?.unregister();
239     }
240
241 }