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