Fixed performance issues with implementation of BA-to-BI mapping
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / connect / dom / RuntimeGeneratedMappingServiceImpl.xtend
1 package org.opendaylight.controller.sal.binding.impl.connect.dom
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.HashMap
13 import java.util.concurrent.ConcurrentHashMap
14 import org.opendaylight.yangtools.yang.data.api.CompositeNode
15 import org.opendaylight.yangtools.yang.binding.DataObject
16 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
17 import java.util.Map.Entry
18 import java.util.AbstractMap.SimpleEntry
19 import org.opendaylight.yangtools.yang.model.api.SchemaPath
20 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil
21 import java.util.ArrayList
22 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem
24 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
25 import org.opendaylight.yangtools.binding.generator.util.Types
26 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
27 import org.opendaylight.yangtools.yang.common.QName
28 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item
30 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
31 import org.opendaylight.yangtools.yang.binding.DataContainer
32 import static com.google.common.base.Preconditions.*;
33 import java.util.List
34 import org.opendaylight.yangtools.yang.data.api.Node
35 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
36 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl
37 import org.opendaylight.yangtools.concepts.Delegator
38 import java.util.concurrent.ConcurrentMap
39 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
40 import org.opendaylight.yangtools.yang.binding.BindingCodec
41
42 class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener {
43
44     ClassPool pool;
45
46     @Property
47     extension TransformerGenerator binding;
48     
49     val ConcurrentMap<Type, Type> typeDefinitions = new ConcurrentHashMap();
50
51     val ConcurrentMap<Class<? extends DataContainer>, TransformerWrapper> domSerializers = 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     override onGlobalContextUpdated(SchemaContext arg0) {
60         recreateBindingContext(arg0);
61     }
62
63     def recreateBindingContext(SchemaContext schemaContext) {
64         val newBinding = new BindingGeneratorImpl();
65         newBinding.generateTypes(schemaContext);
66
67         for (entry : newBinding.moduleContexts.entrySet) {
68
69             //val module = entry.key;
70             val context = entry.value;
71             updateBindingFor(context.childNodes, schemaContext);
72             
73             val typedefs = context.typedefs;
74             for(typedef : typedefs.values) {
75                 binding.typeDefinitions.put(typedef,typedef as GeneratedType);
76             }
77         }
78     }
79
80     override CompositeNode toDataDom(DataObject data) {
81         toCompositeNodeImpl(data);
82     }
83
84     override Entry<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier, CompositeNode> toDataDom(
85         Entry<InstanceIdentifier<? extends DataObject>, DataObject> entry) {
86         val key = toDataDomImpl(entry.key);
87         val data = toCompositeNodeImpl(entry.value);
88         return new SimpleEntry(key, data);
89     }
90
91     private def CompositeNode toCompositeNodeImpl(DataObject object) {
92         val cls = object.implementedInterface;
93         val transformator = resolveTransformator(cls);
94         val ret = transformator.transform(object);
95         return ret;
96     }
97
98     private def resolveTransformator(Class<? extends DataContainer> cls) {
99         val serializer = domSerializers.get(cls);
100         if (serializer !== null) {
101             return serializer;
102         }
103         val transformerClass = binding.transformerFor(cls).newInstance;
104         val wrapper = new TransformerWrapper(transformerClass);
105         domSerializers.putIfAbsent(cls, wrapper);
106         return wrapper;
107     }
108
109     private def org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDomImpl(
110         InstanceIdentifier<? extends DataObject> object) {
111         val pathArguments = object.path;
112         var Class<? extends DataObject> parent;
113         val dataDomArgs = new ArrayList<PathArgument>();
114         for (pathArgument : pathArguments) {
115             dataDomArgs.add(pathArgument.toDataDomPathArgument(parent));
116             parent = pathArgument.type;
117         }
118
119         return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(dataDomArgs);
120     }
121
122     override org.opendaylight.yangtools.yang.data.api.InstanceIdentifier toDataDom(
123         InstanceIdentifier<? extends DataObject> path) {
124         return toDataDomImpl(path);
125     }
126
127     override dataObjectFromDataDom(InstanceIdentifier<? extends DataObject> path, CompositeNode result) {
128         return dataObjectFromDataDomImpl(path, result);
129     }
130
131     def DataObject dataObjectFromDataDomImpl(InstanceIdentifier<? extends DataObject> identifier, CompositeNode node) {
132         val targetType = identifier.targetType
133         val transformer = resolveTransformator(targetType);
134         val ret = transformer.deserialize(node) as DataObject;
135         return ret;
136     }
137
138     def void updateBindingFor(Map<SchemaPath, GeneratedTypeBuilder> map, SchemaContext module) {
139         for (entry : map.entrySet) {
140             val schemaNode = SchemaContextUtil.findDataSchemaNode(module, entry.key);
141             typeToDefinition.put(entry.value, entry.value);
142             typeToSchemaNode.put(entry.value, schemaNode)
143         }
144     }
145
146     private def dispatch PathArgument toDataDomPathArgument(IdentifiableItem argument,
147         Class<? extends DataObject> parent) {
148         val Class<?> rawType = argument.type;
149         val ref = Types.typeForClass(rawType);
150         val schemaType = typeToSchemaNode.get(ref);
151         val qname = schemaType.QName
152
153         val Object key = argument.key;
154         val predicates = key.toPredicates(schemaType as ListSchemaNode);
155
156         return new NodeIdentifierWithPredicates(qname, predicates);
157     }
158
159     private def Map<QName, Object> toPredicates(Object identifier, ListSchemaNode node) {
160         val keyDefinitions = node.keyDefinition;
161         val map = new HashMap<QName, Object>();
162         for (keydef : keyDefinitions) {
163             val keyNode = node.getDataChildByName(keydef) as LeafSchemaNode;
164             val value = BindingMapping.getSimpleValue(identifier, keydef, keyNode.type);
165             map.put(keydef, value.value);
166         }
167         return map;
168     }
169
170     private def dispatch PathArgument toDataDomPathArgument(Item<?> argument, Class<? extends DataObject> parent) {
171         val ref = Types.typeForClass(argument.type);
172         val qname = typeToSchemaNode.get(ref).QName
173         return new NodeIdentifier(qname);
174     }
175
176     public def void start() {
177         pool = new ClassPool()
178         binding = new TransformerGenerator(pool);
179
180         binding.typeToDefinition = typeToDefinition
181         binding.typeToSchemaNode = typeToSchemaNode
182         binding.typeDefinitions = typeDefinitions
183
184     }
185 }
186
187 class TransformerWrapper implements // //
188 Delegator<BindingCodec<Map<QName, Object>, Object>> {
189
190     @Property
191     val BindingCodec<Map<QName, Object>, Object> delegate;
192
193     new(BindingCodec<Map<QName, Object>, Object> delegate) {
194         _delegate = delegate;
195     }
196
197     def CompositeNode transform(DataObject input) {
198         val ret = delegate.serialize(input);
199         val node = toNode(ret)
200         return node as CompositeNode;
201     }
202
203     def deserialize(CompositeNode node) {
204         if (node === null) {
205             return null;
206         }
207         val Map mapCapture = node
208         return delegate.deserialize(mapCapture as Map<QName,Object>);
209     }
210
211     static def Node<?> toNode(Map map) {
212         val nodeMap = map as Map<QName,Object>;
213         checkArgument(map.size == 1);
214         val elem = nodeMap.entrySet.iterator.next;
215         val qname = elem.key;
216         val value = elem.value;
217         toNodeImpl(qname, value);
218     }
219
220     static def dispatch Node<?> toNodeImpl(QName name, List objects) {
221         val values = new ArrayList<Node<?>>(objects.size);
222         for (obj : objects) {
223             values.add(toNode(obj as Map));
224         }
225         return new CompositeNodeTOImpl(name, null, values);
226     }
227
228     static def dispatch Node<?> toNodeImpl(QName name, Map<QName, Object> object) {
229         throw new UnsupportedOperationException("Unsupported node hierarchy.");
230     }
231
232     static def dispatch Node<?> toNodeImpl(QName name, Object object) {
233         return new SimpleNodeTOImpl(name, null, object);
234     }
235 }