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