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