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