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