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