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