ec69fd3b68c8ee84c39edde4e58207adb771b5bd
[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             // FIXME: Make this block providing more information.
153             throw new DeserializationException(e);
154         }
155     }
156
157     private def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
158         for (entry : map.entrySet) {
159             val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
160
161             //LOG.info("{} : {}",entry.key,entry.value.fullyQualifiedName)
162             if (schemaNode != null) {
163                 typeToSchemaNode.put(entry.value, schemaNode);
164                 typeToDefinition.put(entry.value, entry.value);
165                 updatePromisedSchemas(entry.value, schemaNode);
166             }
167         }
168     }
169
170     public def void start(BundleContext ctx) {
171         binding = new TransformerGenerator(pool);
172         registry = new LazyGeneratedCodecRegistry()
173         registry.generator = binding
174
175         //binding.staticFieldsInitializer = registry
176         binding.listener = registry
177         binding.typeToDefinition = typeToDefinition
178         binding.typeToSchemaNode = typeToSchemaNode
179         binding.typeDefinitions = typeDefinitions
180         if (ctx !== null) {
181             listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable<String, String>());
182         }
183     }
184
185     private def getTypeDefinition(Type type) {
186         val typeDef = typeToDefinition.get(type);
187         if (typeDef !== null) {
188             return typeDef;
189         }
190         return type.getTypeDefInFuture.get();
191     }
192
193     private def Future<GeneratedTypeBuilder> getTypeDefInFuture(Type type) {
194         val future = SettableFuture.<GeneratedTypeBuilder>create()
195         promisedTypeDefinitions.put(type, future);
196         return future;
197     }
198
199     private def void updatePromisedTypeDefinitions(GeneratedTypeBuilder builder) {
200         val futures = promisedTypeDefinitions.get(builder);
201         if (futures === null || futures.empty) {
202             return;
203         }
204         for (future : futures) {
205             future.set(builder);
206         }
207         promisedTypeDefinitions.removeAll(builder);
208     }
209
210     private def getSchemaWithRetry(Type type) {
211         val typeDef = typeToSchemaNode.get(type);
212         if (typeDef !== null) {
213             return typeDef;
214         }
215         return type.getSchemaInFuture.get();
216     }
217
218     private def Future<SchemaNode> getSchemaInFuture(Type type) {
219         val future = SettableFuture.<SchemaNode>create()
220         promisedSchemas.put(type, future);
221         return future;
222     }
223
224     private def void updatePromisedSchemas(Type builder, SchemaNode schema) {
225         val ref = new ReferencedTypeImpl(builder.packageName, builder.name);
226         val futures = promisedSchemas.get(ref);
227         if (futures === null || futures.empty) {
228             return;
229         }
230         for (future : futures) {
231             future.set(schema);
232         }
233         promisedSchemas.removeAll(builder);
234     }
235
236     override close() throws Exception {
237         listenerRegistration?.unregister();
238     }
239
240 }