YANG typedefs generation as class with extends key word
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-generator-impl / src / main / java / org / opendaylight / controller / sal / binding / yang / types / TypeProviderImpl.java
1 /*
2  * Copyright (c) 2013 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.controller.sal.binding.yang.types;
9
10 import org.apache.commons.lang.StringEscapeUtils;
11 import org.opendaylight.controller.binding.generator.util.ReferencedTypeImpl;
12 import org.opendaylight.controller.binding.generator.util.TypeConstants;
13 import org.opendaylight.controller.binding.generator.util.Types;
14 import org.opendaylight.controller.binding.generator.util.generated.type.builder.EnumerationBuilderImpl;
15 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
16 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
17 import org.opendaylight.controller.sal.binding.model.api.Enumeration;
18 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
19 import org.opendaylight.controller.sal.binding.model.api.Type;
20 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
21 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
22 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
23 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
24 import org.opendaylight.controller.yang.common.QName;
25 import org.opendaylight.controller.yang.model.api.*;
26 import org.opendaylight.controller.yang.model.api.type.*;
27 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
28 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
29 import org.opendaylight.controller.yang.model.util.ExtendedType;
30
31 import org.opendaylight.controller.yang.model.util.StringType;
32 import org.opendaylight.controller.yang.model.util.UnionType;
33
34 import java.util.ArrayList;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.TreeMap;
40
41 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.*;
42 import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.*;
43
44 public final class TypeProviderImpl implements TypeProvider {
45
46     private final SchemaContext schemaContext;
47     private Map<String, Map<String, Type>> genTypeDefsContextMap;
48     private final Map<SchemaPath, Type> referencedTypes;
49
50     public TypeProviderImpl(final SchemaContext schemaContext) {
51         if (schemaContext == null) {
52             throw new IllegalArgumentException("Schema Context cannot be null!");
53         }
54
55         this.schemaContext = schemaContext;
56         this.genTypeDefsContextMap = new HashMap<>();
57         this.referencedTypes = new HashMap<>();
58         resolveTypeDefsFromContext();
59     }
60
61     public void putReferencedType(final SchemaPath refTypePath, final Type refType) {
62         if (refTypePath == null) {
63             throw new IllegalArgumentException("Path reference of " + "Enumeration Type Definition cannot be NULL!");
64         }
65
66         if (refType == null) {
67             throw new IllegalArgumentException("Reference to Enumeration " + "Type cannot be NULL!");
68         }
69         referencedTypes.put(refTypePath, refType);
70     }
71
72     /*
73      * (non-Javadoc)
74      * 
75      * @see org.opendaylight.controller.yang.model.type.provider.TypeProvider#
76      * javaTypeForYangType(java.lang.String)
77      */
78     @Override
79     public Type javaTypeForYangType(String type) {
80         Type t = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForYangType(type);
81         return t;
82     }
83
84     @Override
85     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition) {
86         Type returnType = null;
87         if (typeDefinition == null) {
88             throw new IllegalArgumentException("Type Definition cannot be NULL!");
89         }
90         if (typeDefinition.getQName() == null) {
91             throw new IllegalArgumentException(
92                     "Type Definition cannot have non specified QName (QName cannot be NULL!)");
93         }
94         if (typeDefinition.getQName().getLocalName() == null) {
95             throw new IllegalArgumentException("Type Definitions Local Name cannot be NULL!");
96         }
97         final String typedefName = typeDefinition.getQName().getLocalName();
98         if (typeDefinition instanceof ExtendedType) {
99             final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
100
101             if (baseTypeDef instanceof LeafrefTypeDefinition) {
102                 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) baseTypeDef;
103                 returnType = provideTypeForLeafref(leafref);
104             } else if (baseTypeDef instanceof IdentityrefTypeDefinition) {
105                 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) baseTypeDef;
106                 returnType = returnTypeForIdentityref(idref);
107             } else if (baseTypeDef instanceof EnumTypeDefinition) {
108                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
109                 returnType = resolveEnumFromTypeDefinition(enumTypeDef, typedefName);
110             } else {
111                 final Module module = findParentModuleForTypeDefinition(schemaContext, typeDefinition);
112                 if (module != null) {
113                     final Map<String, Type> genTOs = genTypeDefsContextMap.get(module.getName());
114                     if (genTOs != null) {
115                         returnType = genTOs.get(typedefName);
116                     }
117                     if (returnType == null) {
118                         returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
119                                 .javaTypeForSchemaDefinitionType(baseTypeDef);
120                     }
121                 }
122             }
123         } else {
124             if (typeDefinition instanceof LeafrefTypeDefinition) {
125                 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
126                 returnType = provideTypeForLeafref(leafref);
127             } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
128                 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
129                 returnType = returnTypeForIdentityref(idref);
130             } else {
131                 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition);
132             }
133         }
134         // TODO: add throw exception when we will be able to resolve ALL yang
135         // types!
136         // if (returnType == null) {
137         // throw new IllegalArgumentException("Type Provider can't resolve " +
138         // "type for specified Type Definition " + typedefName);
139         // }
140         return returnType;
141     }
142
143     private Type returnTypeForIdentityref(IdentityrefTypeDefinition idref) {
144         QName baseIdQName = idref.getIdentity();
145         Module module = schemaContext.findModuleByNamespace(baseIdQName.getNamespace());
146         IdentitySchemaNode identity = null;
147         for (IdentitySchemaNode id : module.getIdentities()) {
148             if (id.getQName().equals(baseIdQName)) {
149                 identity = id;
150             }
151         }
152         if (identity == null) {
153             throw new IllegalArgumentException("Target identity '" + baseIdQName + "' do not exists");
154         }
155
156         final String basePackageName = moduleNamespaceToPackageName(module);
157         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
158         final String genTypeName = parseToClassName(identity.getQName().getLocalName());
159
160         Type baseType = Types.typeForClass(Class.class);
161         Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
162         Type returnType = Types.parameterizedTypeFor(baseType, paramType);
163         return returnType;
164     }
165
166     public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition) {
167         Type returnType = null;
168         if (typeDefinition == null) {
169             throw new IllegalArgumentException("Type Definition cannot be NULL!");
170         }
171         if (typeDefinition.getQName() == null) {
172             throw new IllegalArgumentException(
173                     "Type Definition cannot have non specified QName (QName cannot be NULL!)");
174         }
175         if (typeDefinition.getQName() == null) {
176             throw new IllegalArgumentException("Type Definitions Local Name cannot be NULL!");
177         }
178
179         final String typedefName = typeDefinition.getQName().getLocalName();
180         if (typeDefinition instanceof ExtendedType) {
181             final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
182
183             if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
184                 final Module module = findParentModuleForTypeDefinition(schemaContext, typeDefinition);
185
186                 if (module != null) {
187                     final Map<String, Type> genTOs = genTypeDefsContextMap.get(module.getName());
188                     if (genTOs != null) {
189                         returnType = genTOs.get(typedefName);
190                     }
191                 }
192             }
193         }
194         return returnType;
195     }
196
197     private TypeDefinition<?> baseTypeDefForExtendedType(final TypeDefinition<?> extendTypeDef) {
198         if (extendTypeDef == null) {
199             throw new IllegalArgumentException("Type Definiition reference cannot be NULL!");
200         }
201         final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
202         if (baseTypeDef instanceof ExtendedType) {
203             return baseTypeDefForExtendedType(baseTypeDef);
204         } else {
205             return baseTypeDef;
206         }
207
208     }
209
210     public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType) {
211         Type returnType = null;
212         if (leafrefType == null) {
213             throw new IllegalArgumentException("Leafref Type Definition reference cannot be NULL!");
214         }
215
216         if (leafrefType.getPathStatement() == null) {
217             throw new IllegalArgumentException("The Path Statement for Leafref Type Definition cannot be NULL!");
218         }
219
220         final RevisionAwareXPath xpath = leafrefType.getPathStatement();
221         final String strXPath = xpath.toString();
222
223         if (strXPath != null) {
224             if (strXPath.matches(".*//[.* | .*//].*")) {
225                 returnType = Types.typeForClass(Object.class);
226             } else {
227                 final Module module = findParentModuleForTypeDefinition(schemaContext, leafrefType);
228                 if (module != null) {
229                     final DataSchemaNode dataNode;
230                     if (xpath.isAbsolute()) {
231                         dataNode = findDataSchemaNode(schemaContext, module, xpath);
232                     } else {
233                         dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, leafrefType, xpath);
234                     }
235
236                     if (leafContainsEnumDefinition(dataNode)) {
237                         returnType = referencedTypes.get(dataNode.getPath());
238                     } else if (leafListContainsEnumDefinition(dataNode)) {
239                         returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
240                     } else {
241                         returnType = resolveTypeFromDataSchemaNode(dataNode);
242                     }
243                 }
244             }
245         }
246         return returnType;
247     }
248
249     private boolean leafContainsEnumDefinition(final DataSchemaNode dataNode) {
250         if (dataNode instanceof LeafSchemaNode) {
251             final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
252             if (leaf.getType() instanceof EnumTypeDefinition) {
253                 return true;
254             }
255         }
256         return false;
257     }
258
259     private boolean leafListContainsEnumDefinition(final DataSchemaNode dataNode) {
260         if (dataNode instanceof LeafListSchemaNode) {
261             final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
262             if (leafList.getType() instanceof EnumTypeDefinition) {
263                 return true;
264             }
265         }
266         return false;
267     }
268
269     private Enumeration resolveEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final String enumName) {
270         if (enumTypeDef == null) {
271             throw new IllegalArgumentException("EnumTypeDefinition reference cannot be NULL!");
272         }
273         if (enumTypeDef.getValues() == null) {
274             throw new IllegalArgumentException("EnumTypeDefinition MUST contain at least ONE value definition!");
275         }
276         if (enumTypeDef.getQName() == null) {
277             throw new IllegalArgumentException("EnumTypeDefinition MUST contain NON-NULL QName!");
278         }
279         if (enumTypeDef.getQName().getLocalName() == null) {
280             throw new IllegalArgumentException("Local Name in EnumTypeDefinition QName cannot be NULL!");
281         }
282
283         final String enumerationName = parseToClassName(enumName);
284
285         Module module = findParentModuleForTypeDefinition(schemaContext, enumTypeDef);
286         final String basePackageName = moduleNamespaceToPackageName(module);
287
288         final EnumBuilder enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
289         updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
290         return enumBuilder.toInstance(null);
291     }
292
293     private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final String enumName,
294             final GeneratedTypeBuilder typeBuilder) {
295         if (enumTypeDef == null) {
296             throw new IllegalArgumentException("EnumTypeDefinition reference cannot be NULL!");
297         }
298         if (enumTypeDef.getValues() == null) {
299             throw new IllegalArgumentException("EnumTypeDefinition MUST contain at least ONE value definition!");
300         }
301         if (enumTypeDef.getQName() == null) {
302             throw new IllegalArgumentException("EnumTypeDefinition MUST contain NON-NULL QName!");
303         }
304         if (enumTypeDef.getQName().getLocalName() == null) {
305             throw new IllegalArgumentException("Local Name in EnumTypeDefinition QName cannot be NULL!");
306         }
307         if (typeBuilder == null) {
308             throw new IllegalArgumentException("Generated Type Builder reference cannot be NULL!");
309         }
310
311         final String enumerationName = parseToClassName(enumName);
312         final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
313
314         updateEnumPairsFromEnumTypeDef(enumTypeDef, enumBuilder);
315
316         return enumBuilder;
317     }
318
319     private void updateEnumPairsFromEnumTypeDef(final EnumTypeDefinition enumTypeDef, final EnumBuilder enumBuilder) {
320         if (enumBuilder != null) {
321             final List<EnumPair> enums = enumTypeDef.getValues();
322             if (enums != null) {
323                 int listIndex = 0;
324                 for (final EnumPair enumPair : enums) {
325                     if (enumPair != null) {
326                         final String enumPairName = parseToClassName(enumPair.getName());
327                         Integer enumPairValue = enumPair.getValue();
328
329                         if (enumPairValue == null) {
330                             enumPairValue = listIndex;
331                         }
332                         enumBuilder.addValue(enumPairName, enumPairValue);
333                         listIndex++;
334                     }
335                 }
336             }
337         }
338     }
339
340     private Type resolveTypeFromDataSchemaNode(final DataSchemaNode dataNode) {
341         Type returnType = null;
342         if (dataNode != null) {
343             if (dataNode instanceof LeafSchemaNode) {
344                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
345                 returnType = javaTypeForSchemaDefinitionType(leaf.getType());
346             } else if (dataNode instanceof LeafListSchemaNode) {
347                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
348                 returnType = javaTypeForSchemaDefinitionType(leafList.getType());
349             }
350         }
351         return returnType;
352     }
353
354     private void resolveTypeDefsFromContext() {
355         final Set<Module> modules = schemaContext.getModules();
356         if (modules == null) {
357             throw new IllegalArgumentException("Sef of Modules cannot be NULL!");
358         }
359         for (final Module module : modules) {
360             if (module == null) {
361                 continue;
362             }
363             final String moduleName = module.getName();
364             final String basePackageName = moduleNamespaceToPackageName(module);
365
366             final Set<TypeDefinition<?>> typeDefinitions = module.getTypeDefinitions();
367             final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
368
369             final Map<String, Type> typeMap = new HashMap<>();
370             genTypeDefsContextMap.put(moduleName, typeMap);
371
372             if ((listTypeDefinitions != null) && (basePackageName != null)) {
373                 for (final TypeDefinition<?> typedef : listTypeDefinitions) {
374                     typedefToGeneratedType(basePackageName, moduleName, typedef);
375                 }
376             }
377         }
378     }
379
380     private Type typedefToGeneratedType(final String basePackageName, final String moduleName,
381             final TypeDefinition<?> typedef) {
382         if ((basePackageName != null) && (moduleName != null) && (typedef != null) && (typedef.getQName() != null)) {
383
384             final String typedefName = typedef.getQName().getLocalName();
385             final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
386             if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
387                     && !(innerTypeDefinition instanceof IdentityrefTypeDefinition)) {
388                 Type returnType = null;
389                 if (innerTypeDefinition instanceof ExtendedType) {
390                     ExtendedType extendedTypeDef = (ExtendedType) innerTypeDefinition;
391                     returnType = resolveExtendedTypeFromTypeDef(extendedTypeDef, basePackageName, typedefName,
392                             moduleName);
393                 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
394                     final GeneratedTOBuilder genTOBuilder = addUnionGeneratedTypeDefinition(basePackageName, typedef,
395                             typedefName);
396                     returnType = genTOBuilder.toInstance();
397                 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
398                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
399                     returnType = resolveEnumFromTypeDefinition(enumTypeDef, typedefName);
400
401                 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
402                     final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
403                     final GeneratedTOBuilder genTOBuilder = bitsTypedefToTransferObject(basePackageName,
404                             bitsTypeDefinition, typedefName);
405                     returnType = genTOBuilder.toInstance();
406
407                 } else {
408                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
409                             .javaTypeForSchemaDefinitionType(innerTypeDefinition);
410
411                     returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType);
412                 }
413                 if (returnType != null) {
414                     final Map<String, Type> typeMap = genTypeDefsContextMap.get(moduleName);
415                     if (typeMap != null) {
416                         typeMap.put(typedefName, returnType);
417                     }
418                     return returnType;
419                 }
420             }
421         }
422         return null;
423     }
424
425     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
426             final Type javaType) {
427         if (javaType != null) {
428             final String typedefName = typedef.getQName().getLocalName();
429             final String propertyName = parseToValidParamName(typedefName);
430
431             final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef);
432
433             final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
434
435             genPropBuilder.setReturnType(javaType);
436             genTOBuilder.addEqualsIdentity(genPropBuilder);
437             genTOBuilder.addHashIdentity(genPropBuilder);
438             genTOBuilder.addToStringProperty(genPropBuilder);
439             if (javaType == BaseYangTypes.STRING_TYPE) {
440                 if (typedef instanceof ExtendedType) {
441                     final List<String> regExps = resolveRegExpressionsFromTypedef((ExtendedType) typedef);
442                     addStringRegExAsConstant(genTOBuilder, regExps);
443                 }
444             }
445             return genTOBuilder.toInstance();
446         }
447         return null;
448     }
449
450     public GeneratedTOBuilder addUnionGeneratedTypeDefinition(final String basePackageName,
451             final TypeDefinition<?> typedef, String typeDefName) {
452         if (basePackageName == null) {
453             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
454         }
455         if (typedef == null) {
456             throw new IllegalArgumentException("Type Definition cannot be NULL!");
457         }
458         if (typedef.getQName() == null) {
459             throw new IllegalArgumentException(
460                     "Type Definition cannot have non specified QName (QName cannot be NULL!)");
461         }
462
463         final TypeDefinition<?> baseTypeDefinition = typedef.getBaseType();
464         if ((baseTypeDefinition != null) && (baseTypeDefinition instanceof UnionTypeDefinition)) {
465             final Module parentModule = findParentModuleForTypeDefinition(schemaContext, typedef);
466             final UnionTypeDefinition unionTypeDef = (UnionTypeDefinition) baseTypeDefinition;
467             final List<TypeDefinition<?>> unionTypes = unionTypeDef.getTypes();
468
469             Map<String, Type> genTOsMap = null;
470             if (parentModule != null && parentModule.getName() != null) {
471                 genTOsMap = genTypeDefsContextMap.get(parentModule.getName());
472             }
473
474             final GeneratedTOBuilder unionGenTransObject;
475             if (typeDefName != null && !typeDefName.isEmpty()) {
476                 final String typeName = parseToClassName(typeDefName);
477                 unionGenTransObject = new GeneratedTOBuilderImpl(basePackageName, typeName);
478             } else {
479                 unionGenTransObject = typedefToTransferObject(basePackageName, typedef);
480             }
481             unionGenTransObject.setIsUnion(true);
482
483             final List<String> regularExpressions = new ArrayList<String>();
484             for (final TypeDefinition<?> unionType : unionTypes) {
485                 final String typeName = unionType.getQName().getLocalName();
486                 if (unionType instanceof ExtendedType) {
487                     final Module unionTypeModule = findParentModuleForTypeDefinition(schemaContext, unionType);
488                     if (unionTypeModule != null && unionTypeModule.getName() != null) {
489                         final Map<String, Type> innerGenTOs = genTypeDefsContextMap.get(unionTypeModule.getName());
490                         Type genTransferObject = null;
491                         if (innerGenTOs != null) {
492                             genTransferObject = innerGenTOs.get(typeName);
493                         }
494                         if (genTransferObject != null) {
495                             updateUnionTypeAsProperty(unionGenTransObject, genTransferObject,
496                                     genTransferObject.getName());
497                         } else {
498                             final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionType);
499                             if (typeName.equals(baseType.getQName().getLocalName())) {
500                                 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
501                                         .javaTypeForSchemaDefinitionType(baseType);
502                                 if (javaType != null) {
503                                     updateUnionTypeAsProperty(unionGenTransObject, javaType, typeName);
504                                 }
505                             }
506                             if (baseType instanceof StringType) {
507                                 regularExpressions.addAll(resolveRegExpressionsFromTypedef((ExtendedType) unionType));
508                             }
509                         }
510                     }
511                 } else if (unionType instanceof EnumTypeDefinition) {
512                     final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition((EnumTypeDefinition) unionType,
513                             typeName, unionGenTransObject);
514                     final Type enumRefType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
515                     updateUnionTypeAsProperty(unionGenTransObject, enumRefType, typeName);
516                 } else {
517                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER
518                             .javaTypeForSchemaDefinitionType(unionType);
519                     if (javaType != null) {
520                         updateUnionTypeAsProperty(unionGenTransObject, javaType, typeName);
521                     }
522                 }
523             }
524             if (!regularExpressions.isEmpty()) {
525                 addStringRegExAsConstant(unionGenTransObject, regularExpressions);
526             }
527
528             genTOsMap.put(typedef.getQName().getLocalName(), unionGenTransObject.toInstance());
529             return unionGenTransObject;
530         }
531         return null;
532     }
533
534     private void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type,
535             final String propertyName) {
536         if (unionGenTransObject != null && type != null) {
537             if (!unionGenTransObject.containsProperty(propertyName)) {
538                 final GeneratedPropertyBuilder propBuilder = unionGenTransObject
539                         .addProperty(parseToValidParamName(propertyName));
540                 propBuilder.setReturnType(type);
541
542                 if (!(type instanceof Enumeration)) {
543                     unionGenTransObject.addEqualsIdentity(propBuilder);
544                     unionGenTransObject.addHashIdentity(propBuilder);
545                     unionGenTransObject.addToStringProperty(propBuilder);
546                 }
547             }
548         }
549     }
550
551     private GeneratedTOBuilder typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef) {
552
553         final String packageName = packageNameForGeneratedType(basePackageName, typedef.getPath());
554         final String typeDefTOName = typedef.getQName().getLocalName();
555
556         if ((packageName != null) && (typedef != null) && (typeDefTOName != null)) {
557             final String genTOName = parseToClassName(typeDefTOName);
558             final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTOName);
559
560             return newType;
561         }
562         return null;
563     }
564
565     public GeneratedTOBuilder bitsTypedefToTransferObject(final String basePackageName,
566             final TypeDefinition<?> typeDef, String typeDefName) {
567
568         if (typeDef == null) {
569             throw new IllegalArgumentException("typeDef cannot be NULL!");
570         }
571         if (basePackageName == null) {
572             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
573         }
574
575         if (typeDef instanceof BitsTypeDefinition) {
576             BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
577
578             final String typeName = parseToClassName(typeDefName);
579             final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
580
581             final List<Bit> bitList = bitsTypeDefinition.getBits();
582             GeneratedPropertyBuilder genPropertyBuilder;
583             for (final Bit bit : bitList) {
584                 String name = bit.getName();
585                 genPropertyBuilder = genTOBuilder.addProperty(parseToValidParamName(name));
586                 genPropertyBuilder.setReadOnly(false);
587                 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
588
589                 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
590                 genTOBuilder.addHashIdentity(genPropertyBuilder);
591                 genTOBuilder.addToStringProperty(genPropertyBuilder);
592             }
593
594             return genTOBuilder;
595         }
596         return null;
597     }
598
599     private List<String> resolveRegExpressionsFromTypedef(ExtendedType typedef) {
600         final List<String> regExps = new ArrayList<String>();
601         if (typedef == null) {
602             throw new IllegalArgumentException("typedef can't be null");
603         }
604         final TypeDefinition<?> strTypeDef = baseTypeDefForExtendedType(typedef);
605         if (strTypeDef instanceof StringType) {
606             final List<PatternConstraint> patternConstraints = typedef.getPatterns();
607             if (!patternConstraints.isEmpty()) {
608                 String regEx;
609                 String modifiedRegEx;
610                 for (PatternConstraint patternConstraint : patternConstraints) {
611                     regEx = patternConstraint.getRegularExpression();
612                     modifiedRegEx = StringEscapeUtils.escapeJava(regEx);
613                     regExps.add(modifiedRegEx);
614                 }
615             }
616         }
617         return regExps;
618     }
619
620     private void addStringRegExAsConstant(GeneratedTOBuilder genTOBuilder, List<String> regularExpressions) {
621         if (genTOBuilder == null)
622             throw new IllegalArgumentException("genTOBuilder can't be null");
623         if (regularExpressions == null)
624             throw new IllegalArgumentException("regularExpressions can't be null");
625
626         if (!regularExpressions.isEmpty()) {
627             genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), TypeConstants.PATTERN_CONSTANT_NAME,
628                     regularExpressions);
629         }
630     }
631
632     private GeneratedTransferObject resolveExtendedTypeFromTypeDef(final ExtendedType extendedType,
633             final String basePackageName, final String typedefName, final String moduleName) {
634
635         if (extendedType == null) {
636             throw new IllegalArgumentException("Extended type cannot be NULL!");
637         }
638         if (basePackageName == null) {
639             throw new IllegalArgumentException("String with base package name cannot be NULL!");
640         }
641         if (typedefName == null) {
642             throw new IllegalArgumentException("String with type definition name cannot be NULL!");
643         }
644
645         final String typeDefName = parseToClassName(typedefName);
646         final String lowTypeDef = extendedType.getQName().getLocalName();
647         final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeDefName);
648
649         final Map<String, Type> typeMap = genTypeDefsContextMap.get(moduleName);
650         if (typeMap != null) {
651             Type type = typeMap.get(lowTypeDef);
652             if (type instanceof GeneratedTransferObject) {
653                 genTOBuilder.setExtendsType((GeneratedTransferObject) type);
654             }
655         }
656
657         return genTOBuilder.toInstance();
658     }
659
660     /**
661      * The method find out for each type definition how many immersion (depth)
662      * is necessary to get to the base type. Every type definition is inserted
663      * to the map which key is depth and value is list of type definitions with
664      * equal depth. In next step are lists from this map concatenated to one
665      * list in ascending order according to their depth. All type definitions
666      * are in the list behind all type definitions on which depends.
667      * 
668      * @param unsortedTypeDefinitions
669      *            represents list of type definitions
670      * @return list of type definitions sorted according their each other
671      *         dependencies (type definitions which are depend on other type
672      *         definitions are in list behind them).
673      */
674     private List<TypeDefinition<?>> sortTypeDefinitionAccordingDepth(
675             final Set<TypeDefinition<?>> unsortedTypeDefinitions) {
676         List<TypeDefinition<?>> sortedTypeDefinition = new ArrayList<>();
677
678         Map<Integer, List<TypeDefinition<?>>> typeDefinitionsDepths = new TreeMap<>();
679         for (TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
680             final int depth = getTypeDefinitionDepth(unsortedTypeDefinition);
681             List<TypeDefinition<?>> typeDefinitionsConcreteDepth = typeDefinitionsDepths.get(depth);
682             if (typeDefinitionsConcreteDepth == null) {
683                 typeDefinitionsConcreteDepth = new ArrayList<TypeDefinition<?>>();
684                 typeDefinitionsDepths.put(depth, typeDefinitionsConcreteDepth);
685             }
686             typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
687         }
688
689         Set<Integer> depths = typeDefinitionsDepths.keySet(); // keys are in
690                                                               // ascending order
691         for (Integer depth : depths) {
692             sortedTypeDefinition.addAll(typeDefinitionsDepths.get(depth));
693         }
694
695         return sortedTypeDefinition;
696     }
697
698     /**
699      * The method return how many immersion is necessary to get from type
700      * definition to base type.
701      * 
702      * @param typeDefinition
703      *            is type definition for which is depth looked for.
704      * @return how many immersion is necessary to get from type definition to
705      *         base type
706      */
707     private int getTypeDefinitionDepth(final TypeDefinition<?> typeDefinition) {
708         if (typeDefinition == null) {
709             throw new IllegalArgumentException("Type definition can't be null");
710         }
711         int depth = 1;
712         TypeDefinition<?> baseType = typeDefinition.getBaseType();
713
714         if (baseType instanceof ExtendedType) {
715             depth = depth + getTypeDefinitionDepth(typeDefinition.getBaseType());
716         } else if (baseType instanceof UnionType) {
717             List<TypeDefinition<?>> childTypeDefinitions = ((UnionType) baseType).getTypes();
718             int maxChildDepth = 0;
719             int childDepth = 1;
720             for (TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
721                 childDepth = childDepth + getTypeDefinitionDepth(childTypeDefinition.getBaseType());
722                 if (childDepth > maxChildDepth) {
723                     maxChildDepth = childDepth;
724                 }
725             }
726             return maxChildDepth;
727         }
728         return depth;
729     }
730
731 }