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