Merge "Replay the installedSwView data structure to populate node flows and group...
[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 org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
13 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
14 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
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.WeakHashMap
26 import java.util.List
27 import java.util.TreeSet
28 import com.google.common.base.Joiner
29 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
30 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
31 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
32 import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.*;
33 import org.opendaylight.yangtools.yang.binding.BindingDeserializer
34 import org.opendaylight.yangtools.yang.binding.BindingSerializer
35 import org.opendaylight.yangtools.yang.binding.BindingCodec
36 import org.slf4j.LoggerFactory
37
38 class TransformerGenerator {
39
40     private static val log = LoggerFactory.getLogger(TransformerGenerator)
41
42     public static val STRING = Types.typeForClass(String);
43     public static val BOOLEAN = Types.typeForClass(Boolean);
44     public static val INTEGER = Types.typeForClass(Integer);
45
46     //public static val DECIMAL = Types.typeForClass(Decimal);
47     public static val LONG = Types.typeForClass(Long);
48
49     val ClassPool classPool
50     val extension JavassistUtils utils;
51
52     CtClass ctTransformator
53
54     CtClass ctQName
55
56     @Property
57     var Map<Type, Type> typeDefinitions;
58
59     @Property
60     var Map<Type, GeneratedTypeBuilder> typeToDefinition
61
62     @Property
63     var Map<Type, SchemaNode> typeToSchemaNode
64
65     val Map<Class<?>, Class<?>> generatedClasses = new WeakHashMap();
66
67     public new(ClassPool pool) {
68         classPool = pool;
69         utils = new JavassistUtils(pool)
70
71         ctTransformator = BindingCodec.asCtClass;
72         ctQName = QName.asCtClass
73     }
74
75     def Class<? extends BindingCodec<Map<QName, Object>, Object>> transformerFor(Class<?> inputType) {
76         return withClassLoader(inputType.classLoader) [ |
77             val ret = generatedClasses.get(inputType);
78             if (ret !== null) {
79                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
80             }
81             val ref = Types.typeForClass(inputType)
82             val node = typeToSchemaNode.get(ref)
83             val typeSpecBuilder = typeToDefinition.get(ref)
84             val typeSpec = typeSpecBuilder.toInstance();
85             val newret = generateTransformerFor(inputType, typeSpec, node)
86             generatedClasses.put(inputType, newret);
87             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
88         ]
89     }
90
91     def Class<?> keyTransformerFor(Class<?> inputType, GeneratedType type, ListSchemaNode schema) {
92         return withClassLoader(inputType.classLoader) [ |
93             val transformer = generatedClasses.get(inputType);
94             if (transformer != null) {
95                 return transformer;
96             }
97             val newret = generateKeyTransformerFor(inputType, type, schema);
98             generatedClasses.put(inputType, newret);
99             return newret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
100         ]
101     }
102
103     def Class<?> keyTransformer(GeneratedType type, ListSchemaNode node) {
104         val cls = loadClassWithTCCL(type.resolvedName + "Key");
105         keyTransformerFor(cls, type, node);
106     }
107
108     private def serializer(Type type) {
109         val cls = loadClassWithTCCL(type.resolvedName);
110         transformerFor(cls);
111
112     }
113
114     def Class<?> getValueSerializer(GeneratedTransferObject type) {
115         val cls = loadClassWithTCCL(type.resolvedName);
116         val transformer = generatedClasses.get(cls);
117         if (transformer !== null) {
118             return transformer;
119         }
120         val valueTransformer = generateValueTransformer(cls, type);
121         generatedClasses.put(cls, valueTransformer);
122         return valueTransformer;
123     }
124
125     private def generateKeyTransformerFor(Class<? extends Object> inputType, GeneratedType typeSpec, ListSchemaNode node) {
126         try {
127             log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
128             val properties = typeSpec.allProperties;
129             val ctCls = createClass(inputType.transformatorFqn) [
130                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
131                 staticQNameField(node.QName);
132                 implementsType(ctTransformator)
133                 method(Object, "toDomStatic", QName, Object) [
134                     modifiers = PUBLIC + FINAL + STATIC
135                     body = '''
136                         {
137                         
138                             return null;
139                         }
140                     '''
141                 ]
142                 method(Object, "fromDomStatic", QName, Object) [
143                     modifiers = PUBLIC + FINAL + STATIC
144                     body = '''
145                         {
146                             if($2 == null){
147                                 return  null;
148                             }
149                             «QName.name» _localQName = $1;
150                             java.util.Map _compositeNode = (java.util.Map) $2;
151                             «FOR key : node.keyDefinition»
152                                 «val propertyName = key.getterName»
153                                 «val keyDef = node.getDataChildByName(key)»
154                                 «val property = properties.get(propertyName)»
155                                 «deserializeProperty(keyDef, property.returnType, property)»;
156                             «ENDFOR»
157                             «inputType.name» _value = new «inputType.name»(«node.keyDefinition.keyConstructorList»);
158                             return _value;
159                         }
160                     '''
161                 ]
162                 method(Object, "serialize", Object) [
163                     body = '''
164                         return toDomStatic(QNAME,$1);
165                     '''
166                 ]
167                 method(Object, "deserialize", Object) [
168                     body = '''
169                         return fromDomStatic(QNAME,$1);
170                     '''
171                 ]
172             ]
173             val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
174             log.info("DOM Codec for {} was generated {}",inputType,ret)
175             return ret as Class<? extends BindingCodec<Map<QName,Object>, ?>>;
176         } catch (Exception e) {
177             log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
178             val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
179             exception.addSuppressed(e);
180             throw exception;
181         }
182     }
183
184     private def <D> Class<? extends BindingCodec<Map<QName, Object>, D>> generateTransformerFor(Class<D> inputType,
185         GeneratedType typeSpec, SchemaNode node) {
186         try {
187             log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
188             val ctCls = createClass(typeSpec.transformatorFqn) [
189                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
190                 staticQNameField(inputType);
191                 implementsType(ctTransformator)
192                 method(Object, "toDomStatic", QName, Object) [
193                     modifiers = PUBLIC + FINAL + STATIC
194                     body = serializeBodyFacade(typeSpec, node)
195                 ]
196                 method(Object, "serialize", Object) [
197                     body = '''
198                         return toDomStatic(QNAME,$1);
199                     '''
200                 ]
201                 method(Object, "fromDomStatic", QName, Object) [
202                     modifiers = PUBLIC + FINAL + STATIC
203                     body = deserializeBody(typeSpec, node)
204                 ]
205                 method(Object, "deserialize", Object) [
206                     body = '''
207                         return fromDomStatic(QNAME,$1);
208                     '''
209                 ]
210             ]
211
212             val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
213             return ret as Class<? extends BindingCodec<Map<QName,Object>, D>>;
214         } catch (Exception e) {
215             log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
216             val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
217             exception.addSuppressed(e);
218             throw exception;
219         }
220     }
221
222     private def keyConstructorList(List<QName> qnames) {
223         val names = new TreeSet<String>()
224         for (name : qnames) {
225             val fieldName = name.getterName;
226             names.add(fieldName);
227         }
228         return Joiner.on(",").join(names);
229     }
230
231     private def serializeBodyFacade(GeneratedType type, SchemaNode node) {
232         val ret = serializeBody(type, node);
233         return ret;
234     }
235
236     private def String deserializeBody(GeneratedType type, SchemaNode node) {
237         val ret = deserializeBodyImpl(type, node);
238         return ret;
239     }
240
241     private def deserializeKey(GeneratedType type, ListSchemaNode node) {
242         if (node.keyDefinition != null && !node.keyDefinition.empty) {
243             return '''
244                 «type.resolvedName»Key getKey = («type.resolvedName»Key) «keyTransformer(type, node).canonicalName».fromDomStatic(_localQName,_compositeNode);
245                 _builder.setKey(getKey);
246             ''';
247         }
248     }
249
250     private def dispatch String deserializeBodyImpl(GeneratedType type, SchemaNode node) '''
251         {
252             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
253             
254             if($2 == null) {
255                 return null;
256             }
257             java.util.Map _compositeNode = (java.util.Map) $2;
258             «type.builderName» _builder = new «type.builderName»();
259             
260             return _builder.build();
261         }
262     '''
263
264     private def dispatch String deserializeBodyImpl(GeneratedType type, ListSchemaNode node) '''
265         {
266             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
267             if($2 == null) {
268                 return null;
269             }
270             java.util.Map _compositeNode = (java.util.Map) $2;
271             «type.builderName» _builder = new «type.builderName»();
272             «deserializeKey(type, node)»
273             «deserializeDataNodeContainerBody(type, node)»
274             return _builder.build();
275         }
276     '''
277
278     private def dispatch String deserializeBodyImpl(GeneratedType type, ContainerSchemaNode node) '''
279         {
280             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
281             if($2 == null) {
282                 return null;
283             }
284             java.util.Map _compositeNode = (java.util.Map) $2;
285             «type.builderName» _builder = new «type.builderName»();
286             «deserializeDataNodeContainerBody(type, node)»
287             return _builder.build();
288         }
289     '''
290
291     private def dispatch String deserializeBodyImpl(GeneratedType type, ChoiceCaseNode node) '''
292         {
293             «QName.name» _localQName = «QName.name».create($1,QNAME.getLocalName());
294             if($2 == null) {
295                 return null;
296             }
297             java.util.Map _compositeNode = (java.util.Map) $2;
298             «type.builderName» _builder = new «type.builderName»();
299             «deserializeDataNodeContainerBody(type, node)»
300             return _builder.build();
301         }
302     '''
303
304     private def deserializeDataNodeContainerBody(GeneratedType type, DataNodeContainer node) {
305         deserializeNodeContainerBodyImpl(type, type.allProperties, node);
306     }
307
308     private def deserializeNodeContainerBodyImpl(GeneratedType type, HashMap<String, MethodSignature> properties,
309         DataNodeContainer node) {
310         val ret = '''
311             «FOR child : node.childNodes.filter[!augmenting]»
312                 «val signature = properties.get(child.getterName)»
313                 «deserializeProperty(child, signature.returnType, signature)»
314                 _builder.«signature.name.toSetter»(«signature.name»);
315             «ENDFOR»
316         '''
317         return ret;
318     }
319
320     private def dispatch CharSequence deserializeProperty(ListSchemaNode schema, ParameterizedType type,
321         MethodSignature property) '''
322         java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
323             localName»"));
324         //System.out.println("«property.name»#deCode"+_dom_«property.name»);
325         java.util.List «property.name» = new java.util.ArrayList();
326         if(_dom_«property.name» != null) {
327             java.util.List _serialized = new java.util.ArrayList();
328             java.util.Iterator _iterator = _dom_«property.name».iterator();
329             boolean _hasNext = _iterator.hasNext();
330             while(_hasNext) {
331                 Object _listItem = _iterator.next();
332                 //System.out.println("  item" + _listItem);
333                 Object _value = «type.actualTypeArguments.get(0).serializer.name».fromDomStatic(_localQName,_listItem);
334                 //System.out.println("  value" + _value);
335                 «property.name».add(_value);
336                 _hasNext = _iterator.hasNext();
337             }
338         }
339         
340         //System.out.println(" list" + «property.name»);
341     '''
342
343     private def dispatch CharSequence deserializeProperty(LeafListSchemaNode schema, ParameterizedType type,
344         MethodSignature property) '''
345         java.util.List _dom_«property.name» = _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.
346             localName»"));
347         java.util.List «property.name» = new java.util.ArrayList();
348         if(_dom_«property.name» != null) {
349             java.util.List _serialized = new java.util.ArrayList();
350             java.util.Iterator _iterator = _dom_«property.name».iterator();
351             boolean _hasNext = _iterator.hasNext();
352             while(_hasNext) {
353                 Object _listItem = _iterator.next();
354                 if(_listItem instanceof java.util.Map.Entry) {
355                     Object _innerValue = ((java.util.Map.Entry) _listItem).getValue();
356                     Object _value = «deserializeValue(type.actualTypeArguments.get(0), "_innerValue")»;
357                     «property.name».add(_value);
358                 }
359                 _hasNext = _iterator.hasNext();
360             }
361         }
362     '''
363
364     private def dispatch CharSequence deserializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) '''
365         java.util.List _dom_«property.name»_list = 
366             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
367         «type.resolvedName» «property.name» = null;
368         if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) {
369             java.util.Map.Entry _dom_«property.name» = (java.util.Map.Entry) _dom_«property.name»_list.get(0);
370             Object _inner_value = _dom_«property.name».getValue();
371             «property.name» = «deserializeValue(type, "_inner_value")»;
372         }
373     '''
374
375     private def dispatch CharSequence deserializeProperty(ContainerSchemaNode schema, Type type,
376         MethodSignature property) '''
377         java.util.List _dom_«property.name»_list = 
378             _compositeNode.get(«QName.name».create(_localQName,"«schema.QName.localName»"));
379         «type.resolvedName» «property.name» = null;
380         if(_dom_«property.name»_list != null && _dom_«property.name»_list.size() > 0) {
381             
382             java.util.Map _dom_«property.name» = (java.util.Map) _dom_«property.name»_list.get(0);
383             «type.resolvedName» «property.name» =  «type.serializer.name».fromDomStatic(_localQName,_dom_«property.name»);
384         }
385     '''
386
387     private def dispatch String deserializeValue(GeneratedTransferObject type, String domParameter) '''
388         («type.resolvedName») «type.valueSerializer.name».fromDomValue(«domParameter»);
389     '''
390
391     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
392         Class<?> inputType, GeneratedTransferObject typeSpec) {
393         try {
394
395             val returnType = typeSpec.valueReturnType;
396             if (returnType == null) {
397
398                 val ctCls = createDummyImplementation(inputType, typeSpec);
399                 val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
400                 return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
401             }
402             val ctCls = createClass(typeSpec.transformatorFqn) [
403                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
404                 implementsType(ctTransformator)
405                 implementsType(BindingDeserializer.asCtClass)
406                 method(Object, "toDomValue", Object) [
407                     modifiers = PUBLIC + FINAL + STATIC
408                     body = '''
409                         {
410                             ////System.out.println("«inputType.simpleName»#toDomValue: "+$1);
411                             
412                             if($1 == null) {
413                                 return null;
414                             }
415                             «typeSpec.resolvedName» _encapsulatedValue = («typeSpec.resolvedName») $1;
416                             //System.out.println("«inputType.simpleName»#toDomValue:Enc: "+_encapsulatedValue);
417                             «returnType.resolvedName» _value =  _encapsulatedValue.getValue();
418                             //System.out.println("«inputType.simpleName»#toDomValue:DeEnc: "+_value);
419                             return _value;
420                         }
421                     '''
422                 ]
423                 method(Object, "serialize", Object) [
424                     body = '''
425                         {
426                             return toDomValue($1);
427                         }
428                     '''
429                 ]
430                 method(Object, "fromDomValue", Object) [
431                     modifiers = PUBLIC + FINAL + STATIC
432                     body = '''
433                         {
434                             //System.out.println("«inputType.simpleName»#fromDomValue: "+$1);
435                             
436                             if($1 == null) {
437                                 return null;
438                             }
439                             «returnType.name» _simpleValue = «deserializeValue(returnType, "$1")»;
440                             «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(_simpleValue);
441                             return _value;
442                         }
443                     '''
444                 ]
445                 method(Object, "deserialize", Object) [
446                     body = '''{
447                             return fromDomValue($1);
448                     }
449                     '''
450                 ]
451             ]
452
453             val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
454             log.info("DOM Codec for {} was generated {}",inputType,ret)
455             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
456         } catch (Exception e) {
457             log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
458             val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
459             exception.addSuppressed(e);
460             throw exception;
461         }
462
463     }
464
465     private def createDummyImplementation(Class<?> object, GeneratedTransferObject typeSpec) {
466         log.info("Generating Dummy DOM Codec for {} with {}",object,object.classLoader)
467         return createClass(typeSpec.transformatorFqn) [
468             //staticField(Map,"AUGMENTATION_SERIALIZERS");
469             implementsType(ctTransformator)
470             implementsType(BindingDeserializer.asCtClass)
471             method(Object, "toDomValue", Object) [
472                 modifiers = PUBLIC + FINAL + STATIC
473                 body = '''return null;'''
474             ]
475             method(Object, "serialize", Object) [
476                 body = '''
477                     {
478                         return toDomValue($1);
479                     }
480                 '''
481             ]
482             method(Object, "fromDomValue", Object) [
483                 modifiers = PUBLIC + FINAL + STATIC
484                 body = '''return null;'''
485             ]
486             method(Object, "deserialize", Object) [
487                 body = '''{
488                         return fromDomValue($1);
489                     }
490                     '''
491             ]
492         ]
493     }
494
495     def Type getValueReturnType(GeneratedTransferObject object) {
496         for (prop : object.properties) {
497             if (prop.name == "value") {
498                 return prop.returnType;
499             }
500         }
501         if (object.superType != null) {
502             return getValueReturnType(object.superType);
503         }
504         return null;
505     }
506
507     private def dispatch Class<? extends BindingCodec<Map<QName, Object>, Object>> generateValueTransformer(
508         Class<?> inputType, Enumeration typeSpec) {
509         try {
510             log.info("Generating DOM Codec for {} with {}",inputType,inputType.classLoader)
511             val ctCls = createClass(typeSpec.transformatorFqn) [
512                 //staticField(Map,"AUGMENTATION_SERIALIZERS");
513                 implementsType(ctTransformator)
514                 method(Object, "toDomValue", Object) [
515                     modifiers = PUBLIC + FINAL + STATIC
516                     body = '''
517                         if($1 == null) {
518                             return null;
519                         }
520                         «typeSpec.resolvedName» _value = («typeSpec.resolvedName») $1;
521                         return _value.getValue();
522                     '''
523                 ]
524                 method(Object, "serialize", Object) [
525                     body = '''
526                         return toDomValue($1);
527                     '''
528                 ]
529                 method(Object, "fromDomValue", Object) [
530                     modifiers = PUBLIC + FINAL + STATIC
531                     body = '''
532                         if($1 == null) {
533                             return null;
534                         }
535                         _simpleValue = null;
536                         «typeSpec.resolvedName» _value = new «typeSpec.resolvedName»(null);
537                         return _value;
538                     '''
539                 ]
540                 method(Object, "deserialize", Object) [
541                     body = '''
542                         return fromDomValue($1);
543                     '''
544                 ]
545             ]
546
547             val ret = ctCls.toClass(inputType.classLoader, inputType.protectionDomain)
548             log.info("DOM Codec for {} was generated {}",inputType,ret)
549             return ret as Class<? extends BindingCodec<Map<QName,Object>, Object>>;
550         } catch (Exception e) {
551             log.error("Cannot compile DOM Codec for {}. Exception {}",inputType,e);
552             val exception = new IllegalStateException("Cannot compile Transformator for " + inputType);
553             exception.addSuppressed(e);
554             throw exception;
555         }
556
557     }
558
559     private def dispatch String deserializeValue(Type type, String domParameter) '''(«type.resolvedName») «domParameter»'''
560
561     /** 
562      * Default catch all
563      * 
564      **/
565     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, Type type, MethodSignature property) '''
566         «type.resolvedName» «property.name» = null;
567     '''
568
569     private def dispatch CharSequence deserializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
570         MethodSignature property) {
571         _deserializeProperty(container, type.toInstance, property)
572     }
573
574     public static def toSetter(String it) {
575
576         if (startsWith("is")) {
577             return "set" + substring(2);
578         } else if (startsWith("get")) {
579             return "set" + substring(3);
580         }
581         return "set" + it;
582     }
583
584     /* 
585     private def dispatch CharSequence deserializeProperty(DataSchemaNode container,GeneratedType type, MethodSignature property) '''
586         «property.returnType.resolvedName» «property.name» = value.«property.name»();
587         if(«property.name» != null) {
588             Object domValue = «type.serializer».toDomStatic(QNAME,«property.name»);
589             childNodes.add(domValue);
590         }
591     '''
592     */
593     private def getBuilderName(GeneratedType type) '''«type.resolvedName»Builder'''
594
595     private def staticQNameField(CtClass it, Class node) {
596         val field = new CtField(ctQName, "QNAME", it);
597         field.modifiers = PUBLIC + FINAL + STATIC;
598         addField(field, '''«node.name».QNAME''')
599     }
600     
601     private def staticQNameField(CtClass it, QName node) {
602         val field = new CtField(ctQName, "QNAME", it);
603         field.modifiers = PUBLIC + FINAL + STATIC;
604         addField(field, '''«QName.asCtClass.name».create("«node.namespace»","«node.formattedRevision»","«node.localName»")''')
605     }
606
607     private def dispatch String serializeBody(GeneratedType type, ListSchemaNode node) '''
608         {
609             «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
610             java.util.List childNodes = new java.util.ArrayList();
611             «type.resolvedName» value = («type.resolvedName») $2;
612             «transformDataContainerBody(type.allProperties, node)»
613             return ($r) java.util.Collections.singletonMap(resultName,childNodes);
614         }
615     '''
616
617     private def dispatch String serializeBody(GeneratedType type, ContainerSchemaNode node) '''
618         {
619             «QName.name» resultName = «QName.name».create($1,QNAME.getLocalName());
620             java.util.List childNodes = new java.util.ArrayList();
621             «type.resolvedName» value = («type.resolvedName») $2;
622             «transformDataContainerBody(type.allProperties, node)»
623             return ($r) java.util.Collections.singletonMap(resultName,childNodes);
624         }
625     '''
626
627     private def transformDataContainerBody(Map<String, MethodSignature> properties, DataNodeContainer node) {
628         val ret = '''
629             «FOR child : node.childNodes.filter[!augmenting]»
630                 «val signature = properties.get(child.getterName)»
631                 «serializeProperty(child, signature.returnType, signature)»
632             «ENDFOR»
633         '''
634         return ret;
635     }
636
637     private static def String getGetterName(DataSchemaNode node) {
638         return "get" + BindingGeneratorUtil.parseToClassName(node.QName.localName);
639     }
640
641     private static def String getGetterName(QName node) {
642         return "get" + BindingGeneratorUtil.parseToClassName(node.localName);
643     }
644
645     private def dispatch CharSequence serializeProperty(ListSchemaNode schema, ParameterizedType type,
646         MethodSignature property) '''
647         «property.returnType.resolvedName» «property.name» = value.«property.name»();
648         if(«property.name» != null) {
649             java.util.Iterator _iterator = «property.name».iterator();
650             boolean _hasNext = _iterator.hasNext();
651             while(_hasNext) {
652                 Object _listItem = _iterator.next();
653                 Object _domValue = «type.actualTypeArguments.get(0).serializer.name».toDomStatic(QNAME,_listItem);
654                 childNodes.add(_domValue);
655                 _hasNext = _iterator.hasNext();
656             }
657         }
658     '''
659
660     private def dispatch CharSequence serializeProperty(LeafSchemaNode schema, Type type, MethodSignature property) '''
661         «property.returnType.resolvedName» «property.name» = value.«property.name»();
662         
663         if(«property.name» != null) {
664             «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»");
665             Object _propValue = «serializeValue(type, property.name)»;
666             if(_propValue != null) {
667                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
668                 childNodes.add(_domValue);
669             }
670         }
671     '''
672
673     private def dispatch serializeValue(GeneratedTransferObject type, String parameter) '''«type.valueSerializer.name».toDomValue(«parameter»)'''
674
675     private def dispatch serializeValue(Type signature, String property) '''«property»'''
676
677     private def dispatch CharSequence serializeProperty(LeafListSchemaNode schema, Type type, MethodSignature property) '''
678         «property.returnType.resolvedName» «property.name» = value.«property.name»();
679         if(«property.name» != null) {
680             «QName.name» _qname = «QName.name».create(resultName,"«schema.QName.localName»");
681             java.util.Iterator _iterator = «property.name».iterator();
682             boolean _hasNext = _iterator.hasNext();
683             while(_hasNext) {
684                 Object _listItem = _iterator.next();
685                 Object _propValue = «property.name»;
686                 Object _domValue = java.util.Collections.singletonMap(_qname,_propValue);
687                 childNodes.add(_domValue);
688                 _hasNext = _iterator.hasNext();
689             }
690         }
691     '''
692
693     /** 
694      * Default catch all
695      * 
696      **/
697     private def dispatch CharSequence serializeProperty(DataSchemaNode container, Type type, MethodSignature property) '''
698         «property.returnType.resolvedName» «property.name» = value.«property.name»();
699         if(«property.name» != null) {
700             Object domValue = «property.name»;
701             childNodes.add(domValue);
702         }
703     '''
704
705     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedTypeBuilder type,
706         MethodSignature property) {
707         serializeProperty(container, type.toInstance, property)
708     }
709
710     private def dispatch CharSequence serializeProperty(DataSchemaNode container, GeneratedType type,
711         MethodSignature property) '''
712         «property.returnType.resolvedName» «property.name» = value.«property.name»();
713         if(«property.name» != null) {
714             Object domValue = «type.serializer».toDomStatic(QNAME,«property.name»);
715             childNodes.add(domValue);
716         }
717     '''
718
719     private def dispatch String serializeBody(GeneratedType type, SchemaNode node) '''
720         {
721             return ($r) java.util.Collections.singletonMap(this.QNAME,null);
722         }
723     '''
724
725     private def transformatorFqn(GeneratedType typeSpec) {
726         return '''«typeSpec.resolvedName»$Broker$Codec$DOM'''
727     }
728
729     private def transformatorFqn(Class typeSpec) {
730         return '''«typeSpec.name»$Broker$Codec$DOM'''
731     }
732
733     private def HashMap<String, MethodSignature> getAllProperties(GeneratedType type) {
734         val ret = new HashMap<String, MethodSignature>();
735         type.collectAllProperties(ret);
736         return ret;
737     }
738
739     private def dispatch void collectAllProperties(GeneratedType type, Map<String, MethodSignature> set) {
740         for (definition : type.methodDefinitions) {
741             set.put(definition.name, definition);
742         }
743
744         for (parent : type.implements) {
745             parent.collectAllProperties(set);
746         }
747     }
748
749     private def dispatch void collectAllProperties(Type type, Map<String, MethodSignature> set) {
750         // NOOP for generic type.
751     }
752
753     def String getResolvedName(Type type) {
754         return type.asCtClass.name;
755     }
756
757     def CtClass asCtClass(Type type) {
758         val name = type.fullyQualifiedName
759         val cls = loadClassWithTCCL(type.fullyQualifiedName)
760         return cls.asCtClass;
761     }
762
763 }
764
765 @Data
766 class PropertyPair {
767
768     String getterName;
769
770     Type type;
771
772     @Property
773     MethodSignature signature;
774     @Property
775     SchemaNode schemaNode;
776 }