Revert "BUG-1196: fixed bug in choice case codec."
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / TransformerGenerator.xtend
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.sal.binding.generator.impl
9
10 import com.google.common.base.Joiner
11 import java.io.File
12 import java.security.ProtectionDomain
13 import java.util.AbstractMap.SimpleEntry
14 import java.util.Collection
15 import java.util.Collections
16 import java.util.HashMap
17 import java.util.HashSet
18 import java.util.Iterator
19 import java.util.List
20 import java.util.Map
21 import java.util.Map.Entry
22 import java.util.Set
23 import java.util.TreeSet
24 import javassist.CannotCompileException
25 import javassist.ClassPool
26 import javassist.CtClass
27 import javassist.CtField
28 import javassist.CtMethod
29 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
30 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
31 import org.opendaylight.yangtools.binding.generator.util.Types
32 import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils
33 import org.opendaylight.yangtools.sal.binding.generator.util.CodeGenerationException
34 import org.opendaylight.yangtools.sal.binding.generator.util.XtendHelper
35 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
36 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
37 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
38 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
39 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
40 import org.opendaylight.yangtools.sal.binding.model.api.Type
41 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder
42 import org.opendaylight.yangtools.yang.binding.Augmentation
43 import org.opendaylight.yangtools.yang.binding.BindingCodec
44 import org.opendaylight.yangtools.yang.binding.BindingDeserializer
45 import org.opendaylight.yangtools.yang.binding.BindingMapping
46 import org.opendaylight.yangtools.yang.binding.DataObject
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
48 import org.opendaylight.yangtools.yang.common.QName
49 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
50 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
51 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
52 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
53 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
54 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
55 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
56 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
57 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
58 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
59 import org.opendaylight.yangtools.yang.model.api.SchemaNode
60 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
61 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
62 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit
63 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition
64 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition
65 import org.opendaylight.yangtools.yang.model.util.EnumerationType
66 import org.opendaylight.yangtools.yang.model.util.ExtendedType
67 import org.slf4j.LoggerFactory
68
69 import static com.google.common.base.Preconditions.*
70 import static javassist.Modifier.*
71 import static org.opendaylight.yangtools.sal.binding.generator.impl.CodecMapping.*
72
73 import static extension org.opendaylight.yangtools.sal.binding.generator.util.YangSchemaUtils.*
74
75 class TransformerGenerator extends AbstractTransformerGenerator {
76     private static val LOG = LoggerFactory.getLogger(TransformerGenerator)
77
78     public static val STRING = Types.typeForClass(String);
79     public static val BOOLEAN = Types.typeForClass(Boolean);
80     public static val INTEGER = Types.typeForClass(Integer);
81     public static val INSTANCE_IDENTIFIER = Types.typeForClass(InstanceIdentifier);
82     //public static val DECIMAL = Types.typeForClass(Decimal);
83     public static val LONG = Types.typeForClass(Long);
84     public static val CLASS_TYPE = Types.typeForClass(Class);
85
86     @Property
87     var File classFileCapturePath;
88
89     val CtClass BINDING_CODEC
90     val CtClass ctQName
91
92     public new(TypeResolver typeResolver, ClassPool pool) {
93         super(typeResolver, pool)
94
95         BINDING_CODEC = BindingCodec.asCtClass;
96         ctQName = QName.asCtClass
97     }
98
99     override transformerForImpl(Class inputType) {
100         return runOnClassLoader(inputType.classLoader) [ |
101             val ret = getGeneratedClass(inputType)
102             if (ret !== null) {
103                 listener.onClassProcessed(inputType);
104                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
105             }
106             val ref = Types.typeForClass(inputType)
107             val node = getSchemaNode(ref)
108             createMapping(inputType, node, null)
109             val typeSpecBuilder = getDefinition(ref)
110             checkState(typeSpecBuilder !== null, "Could not find typedefinition for %s", inputType.name);
111             val typeSpec = typeSpecBuilder.toInstance();
112             val newret = generateTransformerFor(inputType, typeSpec, node);
113             listener.onClassProcessed(inputType);
114             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
115         ]
116     }
117
118     def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType, DataSchemaNode node) {
119         return runOnClassLoader(inputType.classLoader) [ |
120             createMapping(inputType, node, null)
121             val ret = getGeneratedClass(inputType)
122             if (ret !== null) {
123                 listener.onClassProcessed(inputType);
124                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
125             }
126             val ref = Types.typeForClass(inputType)
127             var typeSpecBuilder = getDefinition(ref)
128             if (typeSpecBuilder == null) {
129                 typeSpecBuilder = getTypeBuilder(node.path);
130             }
131
132             checkState(typeSpecBuilder !== null, "Could not find TypeDefinition for %s, $s", inputType.name, node);
133             val typeSpec = typeSpecBuilder.toInstance();
134             val newret = generateTransformerFor(inputType, typeSpec, node);
135             listener.onClassProcessed(inputType);
136             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
137         ]
138     }
139
140     override augmentationTransformerForImpl(Class inputType) {
141         return runOnClassLoader(inputType.classLoader) [ |
142
143             val ret = getGeneratedClass(inputType)
144             if (ret !== null) {
145                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
146             }
147             val ref = Types.typeForClass(inputType)
148             val node = getAugmentation(ref)
149             val typeSpecBuilder = getDefinition(ref)
150             val typeSpec = typeSpecBuilder.toInstance();
151             //mappingForNodes(node.childNodes, typeSpec.allProperties, bindingId)
152             val newret = generateAugmentationTransformerFor(inputType, typeSpec, node);
153             listener.onClassProcessed(inputType);
154             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
155         ]
156     }
157
158     override caseCodecForImpl(Class inputType, ChoiceCaseNode node) {
159         return runOnClassLoader(inputType.classLoader) [ |
160             createMapping(inputType, node, null)
161             val ret = getGeneratedClass(inputType)
162             if (ret !== null) {
163                 return ret as Class<? extends BindingCodec<Object, Object>>;
164             }
165             val ref = Types.typeForClass(inputType)
166             val typeSpecBuilder = getDefinition(ref)
167             val typeSpec = typeSpecBuilder.toInstance();
168             val newret = generateCaseCodec(inputType, typeSpec, node);
169             return newret as Class<? extends BindingCodec<Object, Object>>;
170         ]
171     }
172
173     override keyTransformerForIdentifiableImpl(Class parentType) {
174         return runOnClassLoader(parentType.classLoader) [ |
175             val inputName = parentType.name + "Key";
176             val inputType = loadClass(inputName);
177             val ret = getGeneratedClass(inputType)
178             if (ret !== null) {
179                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
180             }
181             val ref = Types.typeForClass(parentType)
182             val node = getSchemaNode(ref) as ListSchemaNode
183             val typeSpecBuilder = getDefinition(ref)
184             val typeSpec = typeSpecBuilder.identifierDefinition;
185             val newret = generateKeyTransformerFor(inputType, typeSpec, node);
186             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
187         ]
188     }
189
190     private def void createMapping(Class<?> inputType, SchemaNode node, InstanceIdentifier<?> parentId) {
191         var ClassLoader cl = inputType.classLoader
192         if (cl === null) {
193             cl = Thread.currentThread.contextClassLoader
194         }
195         ClassLoaderUtils.withClassLoader(cl,
196             [ |
197                 if (!(node instanceof DataNodeContainer)) {
198                     return null
199                 }
200                 var InstanceIdentifier<?> bindingId = getBindingIdentifierByPath(node.path)
201                 if (bindingId != null) {
202                     return null
203                 }
204                 val ref = Types.typeForClass(inputType)
205                 var typeSpecBuilder = getDefinition(ref)
206                 if (typeSpecBuilder == null) {
207                     typeSpecBuilder = getTypeBuilder(node.path);
208                 }
209                 checkState(typeSpecBuilder !== null, "Could not find type definition for %s, $s", inputType.name, node);
210                 val typeSpec = typeSpecBuilder.toInstance();
211                 var InstanceIdentifier<?> parent
212                 if (parentId == null) {
213                     bindingId = InstanceIdentifier.create(inputType as Class)
214                     parent = bindingId
215                     putPathToBindingIdentifier(node.path, bindingId)
216                 } else {
217                     parent = putPathToBindingIdentifier(node.path, parentId, inputType)
218                 }
219                 val Map<String, Type> properties = typeSpec.allProperties
220                 if (node instanceof DataNodeContainer) {
221                     mappingForNodes((node as DataNodeContainer).childNodes, properties, parent)
222                 } else if (node instanceof ChoiceNode) {
223                     mappingForNodes((node as ChoiceNode).cases, properties, parent)
224                 }
225                 return null;
226             ])
227     }
228
229     private def void mappingForNodes(Collection<? extends DataSchemaNode> childNodes, Map<String, Type> properties,
230         InstanceIdentifier<?> parent) {
231         for (DataSchemaNode child : childNodes) {
232             val signature = properties.getFor(child)
233             if (signature != null) {
234                 val Type childType = signature.value
235                 var Class<?> childTypeClass = null;
236                 if (child instanceof ListSchemaNode && childType instanceof ParameterizedType) {
237                     childTypeClass = loadClass((childType as ParameterizedType).actualTypeArguments.get(0))
238                 } else {
239                     childTypeClass = loadClass(childType)
240                 }
241                 createMapping(childTypeClass, child, parent)
242             }
243         }
244     }
245
246     def getIdentifierDefinition(GeneratedTypeBuilder builder) {
247         val inst = builder.toInstance
248         val keyMethod = inst.methodDefinitions.findFirst[name == "getKey"]
249         return keyMethod.returnType as GeneratedTransferObject
250     }
251
252     override keyTransformerForIdentifierImpl(Class inputType) {
253         return runOnClassLoader(inputType.classLoader) [ |
254             val ret = getGeneratedClass(inputType)
255             if (ret !== null) {
256                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
257             }
258             val ref = Types.typeForClass(inputType)
259             val node = getSchemaNode(ref) as ListSchemaNode
260             val typeSpecBuilder = getDefinition(ref)
261             val typeSpec = typeSpecBuilder.toInstance();
262             val newret = generateKeyTransformerFor(inputType, typeSpec, node);
263             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
264         ]
265     }
266
267     private def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
268         return runOnClassLoader(inputType.classLoader) [ |
269             val transformer = getGeneratedClass(inputType)
270             if (transformer != null) {
271                 return transformer;
272             }
273             val newret = generateKeyTransformerFor(inputType, type, schema);
274             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
275         ]
276     }
277
278     private def Class<?> getGeneratedClass(Class<? extends Object> cls) {
279
280         try {
281             return loadClass(cls.codecClassName)
282         } catch (ClassNotFoundException e) {
283             return null;
284         }
285     }
286
287     private def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
288         val cls = loadClass(type.resolvedName + "Key");
289         keyTransformerFor(cls, type, node);
290     }
291
292     private def serializer(Type type, DataSchemaNode node) {
293         val cls = loadClass(type.resolvedName);
294         transformerFor(cls, node);
295     }
296
297     private def Class<?> valueSerializer(GeneratedTransferObject type, TypeDefinition<?> typeDefinition) {
298         val cls = loadClass(type.resolvedName);
299         val transformer = cls.generatedClass;
300         if (transformer !== null) {
301             return transformer;
302         }
303         var baseType = typeDefinition;
304         while (baseType.baseType != null) {
305             baseType = baseType.baseType;
306         }
307         val finalType = baseType;
308         return runOnClassLoader(cls.classLoader) [ |
309             val valueTransformer = generateValueTransformer(cls, type, finalType);
310             return valueTransformer;
311         ]
312     }
313
314     private def Class<?> valueSerializer(Enumeration type, TypeDefinition<?> typeDefinition) {
315         val cls = loadClass(type.resolvedName);
316         val transformer = cls.generatedClass;
317         if (transformer !== null) {
318             return transformer;
319         }
320
321         return runOnClassLoader(cls.classLoader) [ |
322             val valueTransformer = generateValueTransformer(cls, type, typeDefinition);
323             return valueTransformer;
324         ]
325     }
326
327     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
328         try {
329
330             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
331             val properties = typeSpec.allProperties;
332             val ctCls = createClass(inputType.codecClassName) [
333                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
334                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
335                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
336                 staticQNameField(node.QName);
337                 implementsType(BINDING_CODEC)
338                 method(Object, "toDomStatic", #[QName, Object]) [
339                     modifiers = PUBLIC + FINAL + STATIC
340                     bodyChecked = '''
341                         {
342                             «QName.name» _resultName;
343                             if($1 != null) {
344                                 _resultName = «QName.name».create($1,QNAME.getLocalName());
345                             } else {
346                                 _resultName = QNAME;
347                             }
348                             java.util.List _childNodes = new java.util.ArrayList();
349                             «inputType.resolvedName» value = («inputType.name») $2;
350                             «FOR key : node.keyDefinition»
351                                 «val propertyName = key.getterName»
352                                 «val keyDef = node.getDataChildByName(key)»
353                                 «val property = properties.get(propertyName)»
354                                 «serializeProperty(keyDef, property, propertyName)»;
355                             «ENDFOR»
356                             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
357                         }
358                     '''
359                 ]
360                 method(Object, "fromDomStatic", #[QName, Object]) [
361                     modifiers = PUBLIC + FINAL + STATIC
362                     bodyChecked = '''
363                         {
364                             if($2 == null){
365                                 return  null;
366                             }
367                             «QName.name» _localQName = $1;
368                             java.util.Map _compositeNode = (java.util.Map) $2;
369                             boolean _is_empty = true;
370                             «FOR key : node.keyDefinition»
371                                 «val propertyName = key.getterName»
372                                 «val keyDef = node.getDataChildByName(key)»
373                                 «val property = properties.get(propertyName)»
374                                 «deserializeProperty(keyDef, property, propertyName)»;
375                             «ENDFOR»
376                             «inputType.resolvedName» _value = new «inputType.name»(«node.keyDefinition.
377                             keyConstructorList»);
378                             return _value;
379                         }
380                     '''
381                 ]
382                 method(Object, "serialize", Object) [
383                     bodyChecked = '''
384                         {
385                             java.util.Map.Entry _input =  (java.util.Map.Entry) $1;
386                             «QName.name» _localQName = («QName.name») _input.getKey();
387                             «inputType.name» _keyValue = («inputType.name») _input.getValue();
388                             return toDomStatic(_localQName,_keyValue);
389                         }
390                     '''
391                 ]
392                 method(Object, "deserialize", Object) [
393                     bodyChecked = '''
394                         {
395                             «QName.name» _qname = QNAME;
396                             if($1 instanceof java.util.Map.Entry) {
397                                 _qname = («QName.name») ((java.util.Map.Entry) $1).getKey();
398                             }
399                             return fromDomStatic(_qname,$1);
400                         }
401                     '''
402                 ]
403             ]
404             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
405             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
406             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
407         } catch (Exception e) {
408             processException(inputType, e);
409             return null;
410         }
411     }
412
413     private def Class<? extends BindingCodec<Object, Object>> generateCaseCodec(Class<?> inputType, GeneratedType type,
414         ChoiceCaseNode node) {
415         try {
416             //log.info("Generating DOM Codec for {} with {}, TCCL is: {}", inputType, inputType.classLoader,Thread.currentThread.contextClassLoader)
417             val ctCls = createClass(type.codecClassName) [
418                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
419                 implementsType(BINDING_CODEC)
420                 staticQNameField(node.QName);
421                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
422                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
423                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
424                 method(Object, "toDomStatic", #[QName, Object]) [
425                     modifiers = PUBLIC + FINAL + STATIC
426                     bodyChecked = '''
427                         {
428                             «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
429                             java.util.List _childNodes = new java.util.ArrayList();
430                             «type.resolvedName» value = («type.resolvedName») $2;
431                             «transformDataContainerBody(type, type.allProperties, node)»
432                             return ($r) _childNodes;
433                         }
434                     '''
435                 ]
436                 method(Object, "serialize", Object) [
437                     bodyChecked = '''
438                         {
439                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
440                             «QName.name» _localName = QNAME;
441                             if(_input.getKey() != null) {
442                                 _localName = («QName.name») _input.getKey();
443                             }
444                             return toDomStatic(_localName,_input.getValue());
445                         }
446                     '''
447                 ]
448                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
449                     modifiers = PUBLIC + FINAL + STATIC
450                     bodyChecked = deserializeBody(type, node, getBindingIdentifierByPath(node.path))
451                 ]
452                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
453                     bodyChecked = '''
454                         {
455                             //System.out.println("«type.name»#deserialize: " +$1);
456                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
457                             return fromDomStatic((«QName.name»)_input.getKey(),_input.getValue(),$2);
458                         }
459                     '''
460                 ]
461             ]
462
463             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)  as Class<? extends BindingCodec<Object, Object>>
464             listener?.onDataContainerCodecCreated(inputType, ret);
465             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
466             return ret;
467         } catch (Exception e) {
468             processException(inputType, e);
469             return null;
470         }
471     }
472
473     private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
474         Class<?> inputType, GeneratedType typeSpec, SchemaNode node) {
475         try {
476
477             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
478             val ctCls = createClass(typeSpec.codecClassName) [
479                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
480                 staticQNameField(node.QName);
481                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
482                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
483                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
484                 implementsType(BINDING_CODEC)
485
486                 method(Object, "toDomStatic", #[QName, Object]) [
487                     modifiers = PUBLIC + FINAL + STATIC
488                     bodyChecked = serializeBodyFacade(typeSpec, node)
489                 ]
490                 method(Object, "serialize", Object) [
491                     bodyChecked = '''
492                         {
493                             java.util.Map.Entry _input = (java.util.Map.Entry) $1;
494                             «QName.name» _localName = QNAME;
495                             if(_input.getKey() != null) {
496                                 _localName = («QName.name») _input.getKey();
497                             }
498                             return toDomStatic(_localName,_input.getValue());
499                         }
500                     '''
501                 ]
502
503                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
504                     modifiers = PUBLIC + FINAL + STATIC
505                     bodyChecked = deserializeBody(typeSpec, node, getBindingIdentifierByPath(node.path))
506                 ]
507
508                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
509                     bodyChecked = '''
510                         {
511                             «QName.name» _qname = QNAME;
512                             if($1 instanceof java.util.Map.Entry) {
513                                 _qname = («QName.name») ((java.util.Map.Entry) $1).getKey();
514                             }
515                             return fromDomStatic(_qname,$1,$2);
516                         }
517                     '''
518                 ]
519             ]
520
521             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
522             listener?.onDataContainerCodecCreated(inputType, ret);
523             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
524             return ret;
525         } catch (Exception e) {
526             processException(inputType, e);
527             return null;
528         }
529     }
530
531     private def Class<? extends BindingCodec<Map<QName, Object>, Object>> generateAugmentationTransformerFor(
532         Class<?> inputType, GeneratedType type, AugmentationSchema node) {
533         try {
534
535             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
536             val properties = type.allProperties
537             val ctCls = createClass(type.codecClassName) [
538                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
539                 staticQNameField(node.augmentationQName);
540                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
541                 staticField(it, AUGMENTATION_CODEC, BindingCodec)
542                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
543                 implementsType(BINDING_CODEC)
544
545                 method(Object, "toDomStatic", #[QName, Object]) [
546                     modifiers = PUBLIC + FINAL + STATIC
547                     bodyChecked = '''
548                         {
549                             ////System.out.println("Qname " + $1);
550                             ////System.out.println("Value " + $2);
551                             «QName.name» _resultName = «QName.name».create(QNAME,QNAME.getLocalName());
552                             java.util.List _childNodes = new java.util.ArrayList();
553                             «type.resolvedName» value = («type.resolvedName») $2;
554                             «FOR child : node.childNodes»
555                                 «var signature = properties.getFor(child)»
556                                 ////System.out.println("«signature.key»" + value.«signature.key»());
557                                 «serializeProperty(child, signature.value, signature.key)»
558                             «ENDFOR»
559                             return ($r) _childNodes;
560                         }
561                     '''
562                 ]
563                 method(Object, "serialize", Object) [
564                     bodyChecked = '''
565                         {
566                         java.util.Map.Entry _input = (java.util.Map.Entry) $1;
567                         «QName.name» _localName = QNAME;
568                         if(_input.getKey() != null) {
569                             _localName = («QName.name») _input.getKey();
570                         }
571                         return toDomStatic(_localName,_input.getValue());
572                         }
573                     '''
574                 ]
575
576                 method(Object, "fromDomStatic", #[QName, Object, InstanceIdentifier]) [
577                     modifiers = PUBLIC + FINAL + STATIC
578                     bodyChecked = '''
579                         {
580                             «QName.name» _localQName = QNAME;
581
582                             if($2 == null) {
583                             return null;
584                             }
585                             java.util.Map _compositeNode = (java.util.Map) $2;
586                             //System.out.println(_localQName + " " + _compositeNode);
587                             «type.builderName» _builder = new «type.builderName»();
588                             boolean _is_empty = true;
589                             «FOR child : node.childNodes»
590                                 «val signature = properties.getFor(child)»
591                                 «deserializeProperty(child, signature.value, signature.key)»
592                                 _builder.«signature.key.toSetter»(«signature.key»);
593                             «ENDFOR»
594                             if(_is_empty) {
595                             return null;
596                             }
597                             return _builder.build();
598                         }
599                     '''
600                 ]
601
602                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
603                     bodyChecked = '''
604                         return fromDomStatic(QNAME,$1,$2);
605                     '''
606                 ]
607             ]
608
609             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain) as Class<? extends BindingCodec<Map<QName,Object>, Object>>
610             listener?.onDataContainerCodecCreated(inputType, ret);
611             return ret;
612         } catch (Exception e) {
613             processException(inputType, e);
614             return null;
615         }
616     }
617
618     private def dispatch  Class<? extends BindingCodec<Map<QName, Object>, Object>> generateTransformerFor(
619         Class<?> inputType, GeneratedType typeSpec, ChoiceNode node) {
620         try {
621
622             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
623             val ctCls = createClass(typeSpec.codecClassName) [
624                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
625                 //staticQNameField(inputType);
626                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
627                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
628                 staticField(it, CLASS_TO_CASE_MAP, Map)
629                 staticField(it, COMPOSITE_TO_CASE, Map)
630                 //staticField(it,QNAME_TO_CASE_MAP,BindingCodec)
631                 implementsType(BINDING_CODEC)
632                 method(List, "toDomStatic", #[QName, Object]) [
633                     modifiers = PUBLIC + FINAL + STATIC
634                     bodyChecked = '''
635                         {
636                             if($2 == null) {
637                                 return null;
638                             }
639                             «DataObject.name» _baValue = («DataObject.name») $2;
640                             Class _baClass = _baValue.getImplementedInterface();
641                             «BINDING_CODEC.name» _codec =  «CLASS_TO_CASE_MAP».get(_baClass);
642                             if(_codec == null) {
643                                 return null;
644                             }
645                             java.util.Map.Entry _input = new «SimpleEntry.name»($1,_baValue);
646                             Object _ret =  _codec.serialize(_input);
647                             ////System.out.println("«typeSpec.name»#toDomStatic: " + _ret);
648                             return («List.name») _ret;
649                         }
650                     '''
651                 ]
652                 method(Object, "serialize", Object) [
653                     bodyChecked = '''
654                         throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
655                     '''
656                 ]
657                 method(Object, "fromDomStatic", #[QName, Map, InstanceIdentifier]) [
658                     modifiers = PUBLIC + FINAL + STATIC
659                     bodyChecked = '''
660                         {
661                             «BINDING_CODEC.name» _codec = («BINDING_CODEC.name») «COMPOSITE_TO_CASE».get($2);
662                             if(_codec != null) {
663                                 return _codec.deserialize(new «SimpleEntry.name»($1,$2),$3);
664                             }
665                             return null;
666                         }
667                     '''
668                 ]
669                 method(Object, "deserialize", #[Object, InstanceIdentifier]) [
670                     bodyChecked = '''
671                         throw new «UnsupportedOperationException.name»("Direct invocation not supported.");
672                     '''
673                 ]
674             ]
675
676             val rawRet = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
677             val ret = rawRet as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
678             listener?.onChoiceCodecCreated(inputType, ret, node);
679             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
680             return ret;
681         } catch (Exception e) {
682             processException(inputType, e);
683             return null;
684         }
685     }
686
687     private def keyConstructorList(List<QName> qnames) {
688         val names = new TreeSet<String>()
689         for (name : qnames) {
690             val fieldName = name.getterName;
691             names.add(fieldName);
692         }
693         return Joiner.on(",").join(names);
694     }
695
696     private def serializeBodyFacade(GeneratedType type, SchemaNode node) {
697         val ret = serializeBody(type, node);
698         return ret;
699     }
700
701     private def String deserializeBody(GeneratedType type, SchemaNode node, InstanceIdentifier<?> bindingId) {
702         val ret = deserializeBodyImpl(type, node, bindingId);
703         return ret;
704     }
705
706     private def deserializeKey(GeneratedType type, ListSchemaNode node) {
707         if (node.keyDefinition != null && !node.keyDefinition.empty) {
708             return '''
709                 «type.resolvedName»Key getKey = («type.resolvedName»Key) «keyTransformer(type, node).canonicalName».fromDomStatic(_localQName,_compositeNode);
710                 _builder.setKey(getKey);
711             ''';
712         }
713     }
714
715     private def String deserializeBodyWithAugmentations(GeneratedType type, DataNodeContainer node, InstanceIdentifier<?> bindingId) '''
716         {
717             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
718             if($2 == null) {
719                 return null;
720             }
721             java.util.Map _compositeNode = (java.util.Map) $2;
722             //System.out.println(_localQName + " " + _compositeNode);
723             «type.builderName» _builder = new «type.builderName»();
724             «deserializeDataNodeContainerBody(type, node, bindingId)»
725             «type.deserializeAugmentations»
726             return _builder.build();
727         }
728     '''
729
730     private def dispatch String deserializeBodyImpl(GeneratedType type, SchemaNode node, InstanceIdentifier<?> bindingId) '''
731         {
732             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
733
734             if($2 == null) {
735             return null;
736             }
737             java.util.Map _compositeNode = (java.util.Map) $2;
738             «type.builderName» _builder = new «type.builderName»();
739             return _builder.build();
740         }
741     '''
742
743     private def dispatch String deserializeBodyImpl(GeneratedType type, ListSchemaNode node, InstanceIdentifier<?> bindingId) '''
744         {
745             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
746             if($2 == null) {
747                 return null;
748             }
749             java.util.Map _compositeNode = (java.util.Map) $2;
750             //System.out.println(_localQName + " " + _compositeNode);
751             «type.builderName» _builder = new «type.builderName»();
752             «deserializeKey(type, node)»
753             «deserializeDataNodeContainerBody(type, node, bindingId)»
754             «type.deserializeAugmentations»
755             return _builder.build();
756         }
757     '''
758
759     private def dispatch String deserializeBodyImpl(GeneratedType type, ContainerSchemaNode node, InstanceIdentifier<?> bindingId) {
760         return deserializeBodyWithAugmentations(type, node, bindingId);
761     }
762
763     private def dispatch String deserializeBodyImpl(GeneratedType type, NotificationDefinition node, InstanceIdentifier<?> bindingId) {
764         return deserializeBodyWithAugmentations(type, node, bindingId);
765     }
766
767     private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node, InstanceIdentifier<?> bindingId) {
768         return deserializeBodyWithAugmentations(type, node, bindingId);
769     }
770
771     private def deserializeDataNodeContainerBody(GeneratedType type, DataNodeContainer node, InstanceIdentifier<?> bindingId) {
772         deserializeNodeContainerBodyImpl(type, type.allProperties, node, bindingId);
773     }
774
775     private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, Type> properties,
776         DataNodeContainer node, InstanceIdentifier<?> bindingId) {
777         val ret = '''
778             boolean _is_empty = true;
779             «FOR child : node.childNodes»
780                 «val signature = properties.getFor(child)»
781                 «IF signature !== null»
782                     «deserializeProperty(child, signature.value, signature.key)»
783                     _builder.«signature.key.toSetter»(«signature.key»);
784                 «ENDIF»
785             «ENDFOR»
786         '''
787         return ret;
788     }
789
790     def deserializeAugmentations(GeneratedType type) '''
791         «InstanceIdentifier.resolvedName» iid = $3.builder().child(«type.resolvedName».class).build();
792         java.util.Map _augmentation = (java.util.Map) «AUGMENTATION_CODEC».deserialize(_compositeNode,$3);
793         if(_augmentation != null) {
794             «Iterator.name» _entries = _augmentation.entrySet().iterator();
795             while(_entries.hasNext()) {
796                 java.util.Map.Entry _entry = (java.util.Map.Entry) _entries.next();
797                 ////System.out.println("Aug. key:" + _entry.getKey());
798                 Class _type = (Class) _entry.getKey();
799                 «Augmentation.resolvedName» _value = («Augmentation.name») _entry.getValue();
800                 if(_value != null) {
801                     _builder.addAugmentation(_type,_value);
802                 }
803             }
804         }
805     '''
806
807     private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type,
808         String propertyName) '''
809         java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
810             localName»"));
811         ////System.out.println("«propertyName»#deCode"+_dom_«propertyName»);
812         java.util.List «propertyName» = new java.util.ArrayList();
813         if(_dom_«propertyName» != null) {
814             java.util.List _serialized = new java.util.ArrayList();
815             java.util.Iterator _iterator = _dom_«propertyName».iterator();
816             boolean _hasNext = _iterator.hasNext();
817             while(_hasNext) {
818                 Object _listItem = _iterator.next();
819                 _is_empty = false;
820                 ////System.out.println("  item" + _listItem);
821                 «val param = type.actualTypeArguments.get(0)»
822                 «InstanceIdentifier.resolvedName» iid = $3.builder().child(«param.resolvedName».class).build();
823                 Object _value = «type.actualTypeArguments.get(0).serializer(schema).resolvedName».fromDomStatic(_localQName,_listItem,iid);
824                 ////System.out.println("  value" + _value);
825                 «propertyName».add(_value);
826                 _hasNext = _iterator.hasNext();
827             }
828         }
829
830         ////System.out.println(" list" + «propertyName»);
831     '''
832
833     private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
834         String propertyName) '''
835         java.util.List _dom_«propertyName» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
836             localName»"));
837         java.util.List «propertyName» = new java.util.ArrayList();
838         if(_dom_«propertyName» != null) {
839             java.util.List _serialized = new java.util.ArrayList();
840             java.util.Iterator _iterator = _dom_«propertyName».iterator();
841             boolean _hasNext = _iterator.hasNext();
842             while(_hasNext) {
843                 _is_empty = false;
844                 Object _listItem = _iterator.next();
845                 if(_listItem instanceof java.util.Map.Entry) {
846                     Object _innerValue = ((java.util.Map.Entry) _listItem).getValue();
847                     Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue", schema.type)»;
848                     «propertyName».add(_value);
849                 }
850                 _hasNext = _iterator.hasNext();
851             }
852         }
853     '''
854
855     private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
856         java.util.List _dom_«propertyName»_list =
857             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
858         «type.resolvedName» «propertyName» = null;
859         if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
860             _is_empty = false;
861             java.util.Map.Entry _dom_«propertyName» = (java.util.Map.Entry) _dom_«propertyName»_list.get(0);
862             Object _inner_value = _dom_«propertyName».getValue();
863             «propertyName» = «deserializeValue(type, "_inner_value", schema.type)»;
864         }
865     '''
866
867     private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type,
868         String propertyName) '''
869         java.util.List _dom_«propertyName»_list =
870             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
871         «type.resolvedName» «propertyName» = null;
872         if(_dom_«propertyName»_list != null && _dom_«propertyName»_list.size() > 0) {
873             _is_empty = false;
874             java.util.Map _dom_«propertyName» = (java.util.Map) _dom_«propertyName»_list.get(0);
875             «InstanceIdentifier.resolvedName» iid = $3.builder().child(«type.resolvedName».class).build();
876             «propertyName» =  «type.serializer(schema).resolvedName».fromDomStatic(_localQName,_dom_«propertyName»,iid);
877         }
878     '''
879
880     private def dispatch CharSequence deserializeProperty(ChoiceNode schema, Type type, String propertyName) '''
881         «type.resolvedName» «propertyName» = «type.serializer(schema).resolvedName».fromDomStatic(_localQName,_compositeNode,$3);
882         if(«propertyName» != null) {
883             _is_empty = false;
884         }
885     '''
886
887     private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter,
888         TypeDefinition<?> typeDefinition) '''
889         («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter»)
890     '''
891
892     private def dispatch String deserializeValue(Enumeration type, String domParameter, TypeDefinition<?> typeDefinition) '''
893         («type.resolvedName») «type.valueSerializer(typeDefinition).resolvedName».fromDomValue(«domParameter»)
894     '''
895
896     private def dispatch String deserializeValue(Type type, String domParameter, TypeDefinition<?> typeDef) {
897         if (INSTANCE_IDENTIFIER.equals(type)) {
898             return '''(«InstanceIdentifier.name») «INSTANCE_IDENTIFIER_CODEC».deserialize(«domParameter»)'''
899         } else if (CLASS_TYPE.equals(type)) {
900             return '''(«Class.name») «IDENTITYREF_CODEC».deserialize(«domParameter»)'''
901         } else if (typeDef!=null && typeDef instanceof EmptyTypeDefinition) {
902             if(domParameter == null) {
903                 return ''' Boolean.FALSE '''
904             } else {
905                 return ''' Boolean.TRUE '''
906             }
907         }
908         return '''(«type.resolvedName») «domParameter»'''
909     }
910
911     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
912         Class<?> inputType, GeneratedTransferObject typeSpec, TypeDefinition<?> typeDef) {
913         try {
914
915             val returnType = typeSpec.valueReturnType;
916             if (returnType == null) {
917                 val ctCls = createDummyImplementation(inputType, typeSpec);
918                 val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
919                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
920             }
921
922             val ctCls = createClass(typeSpec.codecClassName) [
923                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
924                 if (inputType.isYangBindingAvailable) {
925                     implementsType(BINDING_CODEC)
926                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
927                     staticField(it, IDENTITYREF_CODEC, BindingCodec)
928                     implementsType(BindingDeserializer.asCtClass)
929                 }
930                 method(Object, "toDomValue", Object) [
931                     modifiers = PUBLIC + FINAL + STATIC
932                     val ctSpec = typeSpec.asCtClass;
933                     bodyChecked = '''
934                         {
935                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
936
937                             if($1 == null) {
938                             return null;
939                             }
940                             «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
941                             ////System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
942                             «returnType.resolvedName» _value =  _encapsulatedValue.getValue();
943                             ////System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
944                             Object _domValue = «serializeValue(returnType, "_value", null)»;
945                             return _domValue;
946                         }
947                     '''
948                 ]
949                 method(Object, "serialize", Object) [
950                     bodyChecked = '''
951                         {
952                             return toDomValue($1);
953                         }
954                     '''
955                 ]
956                 method(Object, "fromDomValue", Object) [
957                     modifiers = PUBLIC + FINAL + STATIC
958                     bodyChecked = '''
959                         {
960                             ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
961
962                             if($1 == null) {
963                             return null;
964                             }
965                             «returnType.resolvedName» _simpleValue = «deserializeValue(returnType, "$1", null)»;
966                             «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue);
967                             return _value;
968                         }
969                     '''
970                 ]
971                 method(Object, "deserialize", Object) [
972                     bodyChecked = '''{
973                             return fromDomValue($1);
974                     }
975                     '''
976                 ]
977             ]
978
979             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
980             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
981             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
982         } catch (Exception e) {
983             LOG.error("Cannot compile DOM Codec for {}", inputType, e);
984             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
985             exception.addSuppressed(e);
986             throw exception;
987         }
988     }
989
990     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
991         Class<?> inputType, GeneratedTransferObject typeSpec, UnionTypeDefinition typeDef) {
992         try {
993             val ctCls = createClass(typeSpec.codecClassName) [
994                 val properties = typeSpec.allProperties;
995                 val getterToTypeDefinition = XtendHelper.getTypes(typeDef).toMap[type|type.QName.getterName];
996                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
997                 if (inputType.isYangBindingAvailable) {
998                     implementsType(BINDING_CODEC)
999                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
1000                     staticField(it, IDENTITYREF_CODEC, BindingCodec)
1001                     implementsType(BindingDeserializer.asCtClass)
1002                 }
1003                 method(Object, "toDomValue", Object) [
1004                     modifiers = PUBLIC + FINAL + STATIC
1005                     val ctSpec = inputType.asCtClass;
1006                     bodyChecked = '''
1007                         {
1008                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
1009
1010                             if($1 == null) {
1011                             return null;
1012                             }
1013                             «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
1014                             «FOR property : properties.entrySet»
1015                             «IF property.key != "getValue"»
1016                                 «property.value.resolvedName» «property.key» = («property.value.resolvedName») _value.«property.
1017                             key»();
1018                                 if(«property.key» != null) {
1019                                     return «serializeValue(property.value, property.key,
1020                             getterToTypeDefinition.get(property.key))»;
1021                                 }
1022                             «ENDIF»
1023                             «ENDFOR»
1024
1025                             return null;
1026                         }
1027                     '''
1028                 ]
1029                 method(Object, "serialize", Object) [
1030                     bodyChecked = '''
1031                         {
1032                             return toDomValue($1);
1033                         }
1034                     '''
1035                 ]
1036                 method(Object, "fromDomValue", Object) [
1037                     modifiers = PUBLIC + FINAL + STATIC
1038                     bodyChecked = '''
1039                         {
1040                             ////System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
1041
1042                             if($1 == null) {
1043                             return null;
1044                             }
1045                             if($1 instanceof String) {
1046                             String _simpleValue = (String) $1;
1047                             return new «typeSpec.resolvedName»(_simpleValue.toCharArray());
1048                             }
1049                             return null;
1050                         }
1051                     '''
1052                 ]
1053                 method(Object, "deserialize", Object) [
1054                     bodyChecked = '''{
1055                             return fromDomValue($1);
1056                     }
1057                     '''
1058                 ]
1059             ]
1060
1061             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
1062             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
1063             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
1064         } catch (Exception e) {
1065             LOG.error("Cannot compile DOM Codec for {}", inputType, e);
1066             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
1067             exception.addSuppressed(e);
1068             throw exception;
1069         }
1070     }
1071
1072     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
1073         Class<?> inputType, GeneratedTransferObject typeSpec, BitsTypeDefinition typeDef) {
1074         try {
1075             val ctCls = createClass(typeSpec.codecClassName) [
1076                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
1077                 if (inputType.isYangBindingAvailable) {
1078                     implementsType(BINDING_CODEC)
1079                     staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
1080                     staticField(it, IDENTITYREF_CODEC, BindingCodec)
1081                     implementsType(BindingDeserializer.asCtClass)
1082                 }
1083                 method(Object, "toDomValue", Object) [
1084                     modifiers = PUBLIC + FINAL + STATIC
1085                     val ctSpec = typeSpec.asCtClass;
1086                     bodyChecked = '''
1087                         {
1088                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
1089
1090                             if($1 == null) {
1091                             return null;
1092                             }
1093                             «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
1094                             «HashSet.resolvedName» _value = new «HashSet.resolvedName»();
1095                             //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
1096
1097                             «FOR bit : typeDef.bits»
1098                             «val getter = bit.getterName()»
1099                             if(Boolean.TRUE.equals(_encapsulatedValue.«getter»())) {
1100                                 _value.add("«bit.name»");
1101                             }
1102                             «ENDFOR»
1103                             «Set.resolvedName» _domValue =  «Collections.resolvedName».unmodifiableSet(_value);
1104                             //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_domValue);
1105
1106                             return _domValue;
1107                         }
1108                     '''
1109                 ]
1110                 method(Object, "serialize", Object) [
1111                     bodyChecked = '''
1112                         {
1113                             return toDomValue($1);
1114                         }
1115                     '''
1116                 ]
1117                 method(Object, "fromDomValue", Object) [
1118                     modifiers = PUBLIC + FINAL + STATIC
1119                     val sortedBits = typeDef.bits.sort[o1, o2|o1.propertyName.compareTo(o2.propertyName)]
1120                     bodyChecked = '''
1121                         {
1122                             //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
1123
1124                             if($1 == null) {
1125                             return null;
1126                             }
1127                             «Set.resolvedName» _domValue = («Set.resolvedName») $1;
1128                             «FOR bit : sortedBits»
1129                             Boolean «bit.propertyName» = Boolean.valueOf(_domValue.contains("«bit.name»"));
1130                             «ENDFOR»
1131
1132                             return new «inputType.resolvedName»(«FOR bit : sortedBits SEPARATOR ","»«bit.propertyName»«ENDFOR»);
1133                         }
1134                     '''
1135                 ]
1136                 method(Object, "deserialize", Object) [
1137                     bodyChecked = '''{
1138                             return fromDomValue($1);
1139                     }
1140                     '''
1141                 ]
1142             ]
1143
1144             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
1145             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
1146             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
1147         } catch (Exception e) {
1148             LOG.error("Cannot compile DOM Codec for {}", inputType, e);
1149             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
1150             exception.addSuppressed(e);
1151             throw exception;
1152         }
1153     }
1154
1155     def String getPropertyName(Bit bit) {
1156         '''_«BindingGeneratorUtil.parseToValidParamName(bit.name)»'''
1157     }
1158
1159     def String getterName(Bit bit) {
1160
1161         val paramName = BindingGeneratorUtil.parseToValidParamName(bit.name);
1162         return '''is«paramName.toFirstUpper»''';
1163     }
1164
1165     def boolean isYangBindingAvailable(Class<?> class1) {
1166         try {
1167             val bindingCodecClass = class1.classLoader.loadClass(BINDING_CODEC.name);
1168             return bindingCodecClass !== null;
1169         } catch (ClassNotFoundException e) {
1170             return false;
1171         }
1172     }
1173
1174     private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
1175         LOG.trace("Generating Dummy DOM Codec for {} with {}", object, object.classLoader)
1176         return createClass(typeSpec.codecClassName) [
1177             if (object.isYangBindingAvailable) {
1178                 implementsType(BINDING_CODEC)
1179                 staticField(it, INSTANCE_IDENTIFIER_CODEC, BindingCodec)
1180                 staticField(it, IDENTITYREF_CODEC, BindingCodec)
1181                 implementsType(BindingDeserializer.asCtClass)
1182             }
1183             //implementsType(BindingDeserializer.asCtClass)
1184             method(Object, "toDomValue", Object) [
1185                 modifiers = PUBLIC + FINAL + STATIC
1186                 bodyChecked = '''{
1187                     if($1 == null) {
1188                         return null;
1189                     }
1190                     return $1.toString();
1191
1192                     }'''
1193             ]
1194             method(Object, "serialize", Object) [
1195                 bodyChecked = '''
1196                     {
1197                         return toDomValue($1);
1198                     }
1199                 '''
1200             ]
1201             method(Object, "fromDomValue", Object) [
1202                 modifiers = PUBLIC + FINAL + STATIC
1203                 bodyChecked = '''return null;'''
1204             ]
1205             method(Object, "deserialize", Object) [
1206                 bodyChecked = '''{
1207                         return fromDomValue($1);
1208                     }
1209                     '''
1210             ]
1211         ]
1212     }
1213
1214     private def Type getValueReturnType(GeneratedTransferObject object) {
1215         for (prop : object.properties) {
1216             if (prop.name == "value") {
1217                 return prop.returnType;
1218             }
1219         }
1220         if (object.superType != null) {
1221             return getValueReturnType(object.superType);
1222         }
1223         return null;
1224     }
1225
1226     private def dispatch Class<?> generateValueTransformer(Class<?> inputType, Enumeration typeSpec, TypeDefinition<?> type) {
1227         var EnumerationType enumSchemaType
1228         if (type instanceof EnumerationType) {
1229             enumSchemaType = type as EnumerationType
1230         } else {
1231             val typeRef = new ReferencedTypeImpl(typeSpec.packageName, typeSpec.name);
1232             val schema = getSchemaNode(typeRef) as ExtendedType;
1233             enumSchemaType = schema.baseType as EnumerationType;
1234         }
1235         val enumSchema = enumSchemaType;
1236         try {
1237             //log.info("Generating DOM Codec for {} with {}", inputType, inputType.classLoader)
1238             val ctCls = createClass(typeSpec.codecClassName) [
1239                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
1240                 //implementsType(BINDING_CODEC)
1241                 method(Object, "toDomValue", Object) [
1242                     modifiers = PUBLIC + FINAL + STATIC
1243                     bodyChecked = '''{
1244                             if($1 == null) {
1245                                 return null;
1246                             }
1247                             «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
1248                             «FOR en : enumSchema.values»
1249                             if(«typeSpec.resolvedName».«BindingMapping.getClassName(en.name)».equals(_value)) {
1250                                 return "«en.name»";
1251                             }
1252                             «ENDFOR»
1253                             return null;
1254                         }
1255                     '''
1256                 ]
1257                 method(Object, "serialize", Object) [
1258                     bodyChecked = '''
1259                         return toDomValue($1);
1260                     '''
1261                 ]
1262                 method(Object, "fromDomValue", Object) [
1263                     modifiers = PUBLIC + FINAL + STATIC
1264                     bodyChecked = '''
1265                         {
1266                             if($1 == null) {
1267                                 return null;
1268                             }
1269                             String _value = (String) $1;
1270                             «FOR en : enumSchema.values»
1271                                 if("«en.name»".equals(_value)) {
1272                                     return «typeSpec.resolvedName».«BindingMapping.getClassName(en.name)»;
1273                                 }
1274                             «ENDFOR»
1275                             return null;
1276                         }
1277                     '''
1278                 ]
1279                 method(Object, "deserialize", Object) [
1280                     bodyChecked = '''
1281                         return fromDomValue($1);
1282                     '''
1283                 ]
1284             ]
1285
1286             val ret = ctCls.toClassImpl(inputType.classLoader, inputType.protectionDomain)
1287             LOG.debug("DOM Codec for {} was generated {}", inputType, ret)
1288             return ret;
1289         } catch (CodeGenerationException e) {
1290             throw new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
1291         } catch (Exception e) {
1292             LOG.error("Cannot compile DOM Codec for {}", inputType, e);
1293             val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType);
1294             exception.addSuppressed(e);
1295             throw exception;
1296         }
1297
1298     }
1299
1300     def Class<?> toClassImpl(CtClass newClass, ClassLoader loader, ProtectionDomain domain) {
1301         val cls = newClass.toClass(loader, domain);
1302         if (classFileCapturePath !== null) {
1303             newClass.writeFile(classFileCapturePath.absolutePath);
1304         }
1305         listener?.onCodecCreated(cls);
1306         return cls;
1307     }
1308
1309     def debugWriteClass(CtClass class1) {
1310         val path = class1.name.replace(".", "/") + ".class"
1311
1312         val captureFile = new File(classFileCapturePath, path);
1313         captureFile.createNewFile
1314
1315     }
1316
1317     /**
1318      * Default catch all
1319      *
1320      **/
1321     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, String propertyName) '''
1322         «type.resolvedName» «propertyName» = null;
1323     '''
1324
1325     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
1326         String propertyName) {
1327         _deserializeProperty(container, type.toInstance, propertyName)
1328     }
1329
1330     static def toSetter(String it) {
1331
1332         if (startsWith("is")) {
1333             return "set" + substring(2);
1334         } else if (startsWith("get")) {
1335             return "set" + substring(3);
1336         }
1337         return "set" + it;
1338     }
1339
1340     /*
1341     private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, String propertyName) '''
1342         «type.resolvedName» «propertyName» = value.«propertyName»();
1343         if(«propertyName» != null) {
1344             Object domValue = «type.serializer».toDomStatic(QNAME,«propertyName»);
1345             _childNodes.add(domValue);
1346         }
1347     '''
1348     */
1349     private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder'''
1350
1351     private def staticQNameField(CtClass it, QName node) {
1352         val field = new CtField(ctQName, "QNAME", it);
1353         field.modifiers = PUBLIC + FINAL + STATIC;
1354         addField(field,
1355             '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
1356     }
1357
1358     private def String serializeBodyImpl(GeneratedType type, DataNodeContainer nodeContainer) '''
1359         {
1360             «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
1361             java.util.List _childNodes = new java.util.ArrayList();
1362             «type.resolvedName» value = («type.resolvedName») $2;
1363             «transformDataContainerBody(type, type.allProperties, nodeContainer)»
1364             «serializeAugmentations»
1365             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
1366         }
1367     '''
1368
1369     private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) {
1370         return serializeBodyImpl(type, node);
1371     }
1372
1373     private def dispatch String serializeBody(GeneratedType type, NotificationDefinition node) {
1374         return serializeBodyImpl(type, node);
1375     }
1376
1377     private def dispatch String serializeBody(GeneratedType type, ContainerSchemaNode node) {
1378         return serializeBodyImpl(type, node);
1379     }
1380
1381     private def dispatch String serializeBody(GeneratedType type, ChoiceCaseNode node) {
1382         return serializeBodyImpl(type, node);
1383     }
1384
1385     private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
1386         {
1387         «QName.name» _resultName = «QName.name».create($1,QNAME.getLocalName());
1388             java.util.List _childNodes = new java.util.ArrayList();
1389             «type.resolvedName» value = («type.resolvedName») $2;
1390             return ($r) java.util.Collections.singletonMap(_resultName,_childNodes);
1391         }
1392     '''
1393
1394     private def transformDataContainerBody(Type type, Map<String, Type> properties, DataNodeContainer node) {
1395         val ret = '''
1396             «FOR child : node.childNodes»
1397                 «val signature = properties.getFor(child)»
1398                 «IF signature !== null»
1399                     ////System.out.println("«type.name»#«signature.key»" + value.«signature.key»());
1400                     «serializeProperty(child, signature.value, signature.key)»
1401                 «ENDIF»
1402             «ENDFOR»
1403         '''
1404         return ret;
1405     }
1406
1407     private static def serializeAugmentations() '''
1408         java.util.List _augmentations = (java.util.List) «AUGMENTATION_CODEC».serialize(value);
1409         if(_augmentations != null) {
1410             _childNodes.addAll(_augmentations);
1411         }
1412     '''
1413
1414     private static def Entry<String, Type> getFor(Map<String, Type> map, DataSchemaNode node) {
1415         var sig = map.get(node.getterName);
1416         if (sig != null) {
1417             return new SimpleEntry(node.getterName, sig);
1418         }
1419         sig = map.get(node.booleanGetterName);
1420         if (sig != null) {
1421             return new SimpleEntry(node.booleanGetterName, map.get(node.booleanGetterName));
1422         }
1423         return null;
1424     }
1425
1426     private static def String getBooleanGetterName(DataSchemaNode node) {
1427         return "is" + BindingMapping.getPropertyName(node.QName.localName).toFirstUpper;
1428     }
1429
1430     private static def String getGetterName(DataSchemaNode node) {
1431         return "get" + BindingMapping.getPropertyName(node.QName.localName).toFirstUpper;
1432     }
1433
1434     private static def String getGetterName(QName node) {
1435         return "get" + BindingMapping.getPropertyName(node.localName).toFirstUpper;
1436     }
1437
1438     private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
1439         String propertyName) '''
1440         «type.resolvedName» «propertyName» = value.«propertyName»();
1441         ////System.out.println("«propertyName»:" + «propertyName»);
1442         if(«propertyName» != null) {
1443             java.util.Iterator _iterator = «propertyName».iterator();
1444             boolean _hasNext = _iterator.hasNext();
1445             while(_hasNext) {
1446                 Object _listItem = _iterator.next();
1447                 Object _domValue = «type.actualTypeArguments.get(0).serializer(schema).resolvedName».toDomStatic(_resultName,_listItem);
1448                 _childNodes.add(_domValue);
1449                 _hasNext = _iterator.hasNext();
1450             }
1451         }
1452     '''
1453
1454     private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, String propertyName) '''
1455         «type.resolvedName» «propertyName» = value.«propertyName»();
1456
1457         if(«propertyName» != null) {
1458             «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
1459             Object _propValue = «serializeValue(type, propertyName, schema.type)»;
1460             if(_propValue != null) {
1461                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
1462                 _childNodes.add(_domValue);
1463             }
1464         }
1465     '''
1466
1467     private def dispatch serializeValue(GeneratedTransferObject type, String parameter, TypeDefinition<?> typeDefinition) {
1468         '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)'''
1469     }
1470
1471     private def dispatch serializeValue(Enumeration type, String parameter, TypeDefinition<?> typeDefinition) {
1472         '''«type.valueSerializer(typeDefinition).resolvedName».toDomValue(«parameter»)'''
1473     }
1474
1475     private def dispatch serializeValue(Type type, String parameter, EmptyTypeDefinition typeDefinition) {
1476         '''(«parameter».booleanValue() ? "" : null)'''
1477     }
1478
1479     private def dispatch serializeValue(Type signature, String property, TypeDefinition<?> typeDefinition) {
1480         serializeValue(signature,property)
1481     }
1482
1483     private def dispatch serializeValue(Type signature, String property, Void typeDefinition) {
1484         serializeValue(signature,property)
1485     }
1486
1487     private def dispatch serializeValue(Type signature, String property) {
1488         if (INSTANCE_IDENTIFIER == signature) {
1489             return '''«INSTANCE_IDENTIFIER_CODEC».serialize(«property»)'''
1490         } else if (CLASS_TYPE.equals(signature)) {
1491             return '''(«QName.resolvedName») «IDENTITYREF_CODEC».serialize(«property»)'''
1492         }
1493         if ("char[]" == signature.name) {
1494             return '''new String(«property»)''';
1495         }
1496         return '''«property»''';
1497     }
1498
1499     private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, ParameterizedType type,
1500         String propertyName) '''
1501         «type.resolvedName» «propertyName» = value.«propertyName»();
1502         if(«propertyName» != null) {
1503             «QName.name» _qname = «QName.name».create(_resultName,"«schema.QName.localName»");
1504             java.util.Iterator _iterator = «propertyName».iterator();
1505             boolean _hasNext = _iterator.hasNext();
1506             while(_hasNext) {
1507                 Object _listItem = _iterator.next();
1508                 Object _propValue = «serializeValue(type.actualTypeArguments.get(0), "_listItem", schema.type)»;
1509                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
1510                 _childNodes.add(_domValue);
1511                 _hasNext = _iterator.hasNext();
1512             }
1513         }
1514     '''
1515
1516     private def dispatch CharSequence serializeProperty(ChoiceNode container, GeneratedType type,
1517         String propertyName) '''
1518         «type.resolvedName» «propertyName» = value.«propertyName»();
1519         if(«propertyName» != null) {
1520             java.util.List domValue = «type.serializer(container).resolvedName».toDomStatic(_resultName,«propertyName»);
1521             _childNodes.addAll(domValue);
1522         }
1523     '''
1524
1525     /**
1526      * Default catch all
1527      *
1528      **/
1529     private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, String propertyName) '''
1530         «type.resolvedName» «propertyName» = value.«propertyName»();
1531         if(«propertyName» != null) {
1532             Object domValue = «propertyName»;
1533             _childNodes.add(domValue);
1534         }
1535     '''
1536
1537     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
1538         String propertyName) {
1539         serializeProperty(container, type.toInstance, propertyName)
1540     }
1541
1542     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type,
1543         String propertyName) '''
1544         «type.resolvedName» «propertyName» = value.«propertyName»();
1545         if(«propertyName» != null) {
1546             Object domValue = «type.serializer(container).resolvedName».toDomStatic(_resultName,«propertyName»);
1547             _childNodes.add(domValue);
1548         }
1549     '''
1550
1551     private def codecClassName(GeneratedType typeSpec) {
1552         return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
1553     }
1554
1555     private def codecClassName(Class<?> typeSpec) {
1556         return '''«typeSpec.name»$Broker$Codec$DOM'''
1557     }
1558
1559     private def HashMap<String, Type> getAllProperties(GeneratedType type) {
1560         val ret = new HashMap<String, Type>();
1561         type.collectAllProperties(ret);
1562         return ret;
1563     }
1564
1565     private def dispatch void collectAllProperties(GeneratedType type, Map<String, Type> set) {
1566         for (definition : type.methodDefinitions) {
1567             set.put(definition.name, definition.returnType);
1568         }
1569         for (property : type.properties) {
1570             set.put(property.getterName, property.returnType);
1571         }
1572         for (parent : type.implements) {
1573             parent.collectAllProperties(set);
1574         }
1575     }
1576
1577     def String getGetterName(GeneratedProperty property) {
1578         return "get" + property.name.toFirstUpper
1579     }
1580
1581     private def dispatch void collectAllProperties(Type type, Map<String, Type> set) {
1582         // NOOP for generic type.
1583     }
1584
1585     def String getResolvedName(Type type) {
1586         return type.asCtClass.name;
1587     }
1588
1589     def String getResolvedName(Class<?> type) {
1590         return type.asCtClass.name;
1591     }
1592
1593     def CtClass asCtClass(Type type) {
1594         val cls = loadClass(type.fullyQualifiedName)
1595         return cls.asCtClass;
1596     }
1597
1598     private def dispatch processException(Class<?> inputType, CodeGenerationException e) {
1599         LOG.error("Cannot compile DOM Codec for {}. One of it's prerequisites was not generated.", inputType);
1600         throw e;
1601     }
1602
1603     private def dispatch processException(Class<?> inputType, Exception e) {
1604         LOG.error("Cannot compile DOM Codec for {}", inputType, e);
1605         val exception = new CodeGenerationException("Cannot compile Transformator for " + inputType, e);
1606         throw exception;
1607     }
1608
1609     private def setBodyChecked(CtMethod method, String body) {
1610         try {
1611             method.setBody(body);
1612         } catch (CannotCompileException e) {
1613             LOG.error("Cannot compile method: {}#{} {}, Reason: {} Body: {}", method.declaringClass, method.name,
1614                 method.signature, e.message, body)
1615             throw e;
1616         }
1617     }
1618 }
1619
1620 @Data
1621 class PropertyPair {
1622
1623     String getterName;
1624
1625     Type type;
1626
1627     @Property
1628     Type returnType;
1629     @Property
1630     SchemaNode schemaNode;
1631 }