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