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