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