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