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