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