Merge "Added export of augmentation schemas to Binding Context"
[yangtools.git] / code-generator / binding-type-provider / src / main / java / org / opendaylight / yangtools / 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.yangtools.sal.binding.yang.types;
9
10 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*;
11 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;
12
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.TreeMap;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import org.apache.commons.lang3.StringEscapeUtils;
24 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
25 import org.opendaylight.yangtools.binding.generator.util.TypeConstants;
26 import org.opendaylight.yangtools.binding.generator.util.Types;
27 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.EnumerationBuilderImpl;
28 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
29 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
30 import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
31 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
32 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration;
33 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject;
34 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions;
35 import org.opendaylight.yangtools.sal.binding.model.api.Type;
36 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder;
37 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
38 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
39 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
40 import org.opendaylight.yangtools.yang.common.QName;
41 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.Module;
45 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
46 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
47 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
49 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
50 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
51 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
52 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
53 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
54 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
55 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
56 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
57 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
58 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
59 import org.opendaylight.yangtools.yang.model.util.StringType;
60 import org.opendaylight.yangtools.yang.model.util.UnionType;
61 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
62
63 import com.google.common.base.Preconditions;
64
65 public final class TypeProviderImpl implements TypeProvider {
66     /**
67      * Contains the schema data red from YANG files.
68      */
69     private final SchemaContext schemaContext;
70
71     /**
72      * The outter map maps module names to the map of the types for the module.
73      * The inner map maps the name of the concrete type to the JAVA
74      * <code>Type</code> (usually it is generated TO).
75      */
76     private Map<String, Map<String, Type>> genTypeDefsContextMap;
77
78     /**
79      * The map which maps schema paths to JAVA <code>Type</code>.
80      */
81     private final Map<SchemaPath, Type> referencedTypes;
82
83     /**
84      * Creates new instance of class <code>TypeProviderImpl</code>.
85      *
86      * @param schemaContext
87      *            contains the schema data red from YANG files
88      * @throws IllegalArgumentException
89      *             if <code>schemaContext</code> equal null.
90      */
91     public TypeProviderImpl(final SchemaContext schemaContext) {
92         Preconditions.checkArgument(schemaContext != null, "Schema Context cannot be null!");
93
94         this.schemaContext = schemaContext;
95         this.genTypeDefsContextMap = new HashMap<>();
96         this.referencedTypes = new HashMap<>();
97         resolveTypeDefsFromContext();
98     }
99
100     /**
101      * Puts <code>refType</code> to map with key <code>refTypePath</code>
102      *
103      * @param refTypePath
104      *            schema path used as the map key
105      * @param refType
106      *            type which represents the map value
107      * @throws IllegalArgumentException
108      *             <ul>
109      *             <li>if <code>refTypePath</code> equal null</li>
110      *             <li>if <code>refType</code> equal null</li>
111      *             </ul>
112      *
113      */
114     public void putReferencedType(final SchemaPath refTypePath, final Type refType) {
115         Preconditions.checkArgument(refTypePath != null,
116                 "Path reference of Enumeration Type Definition cannot be NULL!");
117         Preconditions.checkArgument(refType != null, "Reference to Enumeration Type cannot be NULL!");
118         referencedTypes.put(refTypePath, refType);
119     }
120
121     /**
122      *
123      * Converts basic YANG type <code>type</code> to JAVA <code>Type</code>.
124      *
125      * @param type
126      *            string with YANG name of type
127      * @return JAVA <code>Type</code> for YANG type <code>type</code>
128      * @see TypeProvider#javaTypeForYangType(String)
129      */
130     @Override
131     public Type javaTypeForYangType(String type) {
132         return BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForYangType(type);
133     }
134
135     @Override
136     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
137         return javaTypeForSchemaDefinitionType(typeDefinition, parentNode, null);
138     }
139
140     /**
141      * Converts schema definition type <code>typeDefinition</code> to JAVA
142      * <code>Type</code>
143      *
144      * @param typeDefinition
145      *            type definition which is converted to JAVA type
146      * @throws IllegalArgumentException
147      *             <ul>
148      *             <li>if <code>typeDefinition</code> equal null</li>
149      *             <li>if Q name of <code>typeDefinition</code> equal null</li>
150      *             <li>if name of <code>typeDefinition</code> equal null</li>
151      *             </ul>
152      */
153     @Override
154     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode, Restrictions r) {
155         Type returnType = null;
156         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
157         if (typeDefinition.getQName() == null) {
158             throw new IllegalArgumentException(
159                     "Type Definition cannot have non specified QName (QName cannot be NULL!)");
160         }
161         Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
162                 "Type Definitions Local Name cannot be NULL!");
163
164         if (typeDefinition instanceof ExtendedType) {
165             returnType = javaTypeForExtendedType(typeDefinition);
166         } else {
167             returnType = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode);
168             if (returnType == null) {
169                 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition,
170                         parentNode, r);
171             }
172         }
173         // TODO: add throw exception when we will be able to resolve ALL yang
174         // types!
175         // if (returnType == null) {
176         // throw new IllegalArgumentException("Type Provider can't resolve " +
177         // "type for specified Type Definition " + typedefName);
178         // }
179         return returnType;
180     }
181
182     /**
183      * Returns JAVA <code>Type</code> for instances of the type
184      * <code>LeafrefTypeDefinition</code> or
185      * <code>IdentityrefTypeDefinition</code>.
186      *
187      * @param typeDefinition
188      *            type definition which is converted to JAVA <code>Type</code>
189      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
190      */
191     private Type javaTypeForLeafrefOrIdentityRef(TypeDefinition<?> typeDefinition, SchemaNode parentNode) {
192         if (typeDefinition instanceof LeafrefTypeDefinition) {
193             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
194             return provideTypeForLeafref(leafref, parentNode);
195         } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
196             final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
197             return provideTypeForIdentityref(idref);
198         } else {
199             return null;
200         }
201     }
202
203     /**
204      * Returns JAVA <code>Type</code> for instances of the type
205      * <code>ExtendedType</code>.
206      *
207      * @param typeDefinition
208      *            type definition which is converted to JAVA <code>Type</code>
209      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
210      */
211     private Type javaTypeForExtendedType(TypeDefinition<?> typeDefinition) {
212         final String typedefName = typeDefinition.getQName().getLocalName();
213         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
214         Type returnType = null;
215         returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition);
216         if (returnType == null) {
217             if (baseTypeDef instanceof EnumTypeDefinition) {
218                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
219                 returnType = provideTypeForEnum(enumTypeDef, typedefName, typeDefinition);
220             } else {
221                 final Module module = findParentModule(schemaContext, typeDefinition);
222                 Restrictions r = BindingGeneratorUtil.getRestrictions(typeDefinition);
223                 if (module != null) {
224                     final Map<String, Type> genTOs = genTypeDefsContextMap.get(module.getName());
225                     if (genTOs != null) {
226                         returnType = genTOs.get(typedefName);
227                     }
228                     if (returnType == null) {
229                         returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
230                                 baseTypeDef, typeDefinition, r);
231                     }
232                 }
233             }
234         }
235         return returnType;
236         // TODO: add throw exception when we will be able to resolve ALL yang
237         // types!
238         // if (returnType == null) {
239         // throw new IllegalArgumentException("Type Provider can't resolve " +
240         // "type for specified Type Definition " + typedefName);
241         // }
242     }
243
244     /**
245      * Seeks for identity reference <code>idref</code> the JAVA
246      * <code>type</code>.<br />
247      * <br />
248      *
249      * <i>Example:<br />
250      * If identy which is referenced via <code>idref</code> has name <b>Idn</b>
251      * then returning type is <b>{@code Class<? extends Idn>}</b></i>
252      *
253      * @param idref
254      *            identityref type definition for which JAVA <code>Type</code>
255      *            is sought
256      * @return JAVA <code>Type</code> of the identity which is refrenced through
257      *         <code>idref</code>
258      */
259     private Type provideTypeForIdentityref(IdentityrefTypeDefinition idref) {
260         QName baseIdQName = idref.getIdentity().getQName();
261         Module module = schemaContext.findModuleByNamespaceAndRevision(baseIdQName.getNamespace(),
262                 baseIdQName.getRevision());
263         IdentitySchemaNode identity = null;
264         for (IdentitySchemaNode id : module.getIdentities()) {
265             if (id.getQName().equals(baseIdQName)) {
266                 identity = id;
267             }
268         }
269         Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
270
271         final String basePackageName = moduleNamespaceToPackageName(module);
272         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
273         final String genTypeName = parseToClassName(identity.getQName().getLocalName());
274
275         Type baseType = Types.typeForClass(Class.class);
276         Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
277         return Types.parameterizedTypeFor(baseType, paramType);
278     }
279
280     /**
281      * Converts <code>typeDefinition</code> to concrete JAVA <code>Type</code>.
282      *
283      * @param typeDefinition
284      *            type definition which should be converted to JAVA
285      *            <code>Type</code>
286      * @return JAVA <code>Type</code> which represents
287      *         <code>typeDefinition</code>
288      * @throws IllegalArgumentException
289      *             <ul>
290      *             <li>if <code>typeDefinition</code> equal null</li>
291      *             <li>if Q name of <code>typeDefinition</code></li>
292      *             <li>if name of <code>typeDefinition</code></li>
293      *             </ul>
294      */
295     public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition,
296             final SchemaNode parentNode) {
297         Type returnType = null;
298         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
299         if (typeDefinition.getQName() == null) {
300             throw new IllegalArgumentException(
301                     "Type Definition cannot have non specified QName (QName cannot be NULL!)");
302         }
303         Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
304                 "Type Definitions Local Name cannot be NULL!");
305
306         final String typedefName = typeDefinition.getQName().getLocalName();
307         if (typeDefinition instanceof ExtendedType) {
308             final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
309
310             if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
311                 final Module module = findParentModule(schemaContext, parentNode);
312
313                 if (module != null) {
314                     final Map<String, Type> genTOs = genTypeDefsContextMap.get(module.getName());
315                     if (genTOs != null) {
316                         returnType = genTOs.get(typedefName);
317                     }
318                 }
319             }
320         }
321         return returnType;
322     }
323
324     /**
325      * Gets base type definition for <code>extendTypeDef</code>. The method is
326      * recursivelly called until non <code>ExtendedType</code> type is found.
327      *
328      * @param extendTypeDef
329      *            type definition for which is the base type definition sought
330      * @return type definition which is base type for <code>extendTypeDef</code>
331      * @throws IllegalArgumentException
332      *             if <code>extendTypeDef</code> equal null
333      */
334     private TypeDefinition<?> baseTypeDefForExtendedType(final TypeDefinition<?> extendTypeDef) {
335         Preconditions.checkArgument(extendTypeDef != null, "Type Definiition reference cannot be NULL!");
336         final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
337         if (baseTypeDef instanceof ExtendedType) {
338             return baseTypeDefForExtendedType(baseTypeDef);
339         } else {
340             return baseTypeDef;
341         }
342
343     }
344
345     /**
346      * Converts <code>leafrefType</code> to JAVA <code>Type</code>.
347      *
348      * The path of <code>leafrefType</code> is followed to find referenced node
349      * and its <code>Type</code> is returned.
350      *
351      * @param leafrefType
352      *            leafref type definition for which is the type sought
353      * @return JAVA <code>Type</code> of data schema node which is referenced in
354      *         <code>leafrefType</code>
355      * @throws IllegalArgumentException
356      *             <ul>
357      *             <li>if <code>leafrefType</code> equal null</li>
358      *             <li>if path statement of <code>leafrefType</code> equal null</li>
359      *             </ul>
360      *
361      */
362     public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode) {
363         Type returnType = null;
364         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
365
366         Preconditions.checkArgument(leafrefType.getPathStatement() != null,
367                 "The Path Statement for Leafref Type Definition cannot be NULL!");
368
369         final RevisionAwareXPath xpath = leafrefType.getPathStatement();
370         final String strXPath = xpath.toString();
371
372         if (strXPath != null) {
373             if (strXPath.contains("[")) {
374                 returnType = Types.typeForClass(Object.class);
375             } else {
376                 final Module module = findParentModule(schemaContext, parentNode);
377                 if (module != null) {
378                     final SchemaNode dataNode;
379                     if (xpath.isAbsolute()) {
380                         dataNode = findDataSchemaNode(schemaContext, module, xpath);
381                     } else {
382                         dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
383                     }
384
385                     if (leafContainsEnumDefinition(dataNode)) {
386                         returnType = referencedTypes.get(dataNode.getPath());
387                     } else if (leafListContainsEnumDefinition(dataNode)) {
388                         returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
389                     } else {
390                         returnType = resolveTypeFromDataSchemaNode(dataNode);
391                     }
392                 }
393             }
394         }
395         return returnType;
396     }
397
398     /**
399      * Checks if <code>dataNode</code> is <code>LeafSchemaNode</code> and if it
400      * so then checks if it is of type <code>EnumTypeDefinition</code>.
401      *
402      * @param dataNode
403      *            data schema node for which is checked if it is leaf and if it
404      *            is of enum type
405      * @return boolean value
406      *         <ul>
407      *         <li>true - if <code>dataNode</code> is leaf of type enumeration</li>
408      *         <li>false - other cases</li>
409      *         </ul>
410      */
411     private boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
412         if (dataNode instanceof LeafSchemaNode) {
413             final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
414             if (leaf.getType() instanceof EnumTypeDefinition) {
415                 return true;
416             }
417         }
418         return false;
419     }
420
421     /**
422      * Checks if <code>dataNode</code> is <code>LeafListSchemaNode</code> and if
423      * it so then checks if it is of type <code>EnumTypeDefinition</code>.
424      *
425      * @param dataNode
426      *            data schema node for which is checked if it is leaflist and if
427      *            it is of enum type
428      * @return boolean value
429      *         <ul>
430      *         <li>true - if <code>dataNode</code> is leaflist of type
431      *         enumeration</li>
432      *         <li>false - other cases</li>
433      *         </ul>
434      */
435     private boolean leafListContainsEnumDefinition(final SchemaNode dataNode) {
436         if (dataNode instanceof LeafListSchemaNode) {
437             final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
438             if (leafList.getType() instanceof EnumTypeDefinition) {
439                 return true;
440             }
441         }
442         return false;
443     }
444
445     /**
446      * Converts <code>enumTypeDef</code> to
447      * {@link org.opendaylight.yangtools.sal.binding.model.api.Enumeration
448      * enumeration}.
449      *
450      * @param enumTypeDef
451      *            enumeration type definition which is converted to enumeration
452      * @param enumName
453      *            string with name which is used as the enumeration name
454      * @return enumeration type which is built with data (name, enum values)
455      *         from <code>enumTypeDef</code>
456      * @throws IllegalArgumentException
457      *             <ul>
458      *             <li>if <code>enumTypeDef</code> equals null</li>
459      *             <li>if enum values of <code>enumTypeDef</code> equal null</li>
460      *             <li>if Q name of <code>enumTypeDef</code> equal null</li>
461      *             <li>if name of <code>enumTypeDef</code> equal null</li>
462      *             </ul>
463      */
464     private Enumeration provideTypeForEnum(final EnumTypeDefinition enumTypeDef, final String enumName,
465             final SchemaNode parentNode) {
466         Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
467         Preconditions.checkArgument(enumTypeDef.getValues() != null,
468                 "EnumTypeDefinition MUST contain at least ONE value definition!");
469         Preconditions.checkArgument(enumTypeDef.getQName() != null, "EnumTypeDefinition MUST contain NON-NULL QName!");
470         Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
471                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
472
473         final String enumerationName = parseToClassName(enumName);
474
475         Module module = findParentModule(schemaContext, parentNode);
476         final String basePackageName = moduleNamespaceToPackageName(module);
477
478         final EnumBuilder enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
479         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
480         return enumBuilder.toInstance(null);
481     }
482
483     /**
484      * Adds enumeration to <code>typeBuilder</code>. The enumeration data are
485      * taken from <code>enumTypeDef</code>.
486      *
487      * @param enumTypeDef
488      *            enumeration type definition is source of enumeration data for
489      *            <code>typeBuilder</code>
490      * @param enumName
491      *            string with the name of enumeration
492      * @param typeBuilder
493      *            generated type builder to which is enumeration added
494      * @return enumeration type which contains enumeration data form
495      *         <code>enumTypeDef</code>
496      * @throws IllegalArgumentException
497      *             <ul>
498      *             <li>if <code>enumTypeDef</code> equals null</li>
499      *             <li>if enum values of <code>enumTypeDef</code> equal null</li>
500      *             <li>if Q name of <code>enumTypeDef</code> equal null</li>
501      *             <li>if name of <code>enumTypeDef</code> equal null</li>
502      *             <li>if name of <code>typeBuilder</code> equal null</li>
503      *             </ul>
504      *
505      */
506     private Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef, final String enumName,
507             final GeneratedTypeBuilderBase<?> typeBuilder) {
508         Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
509         Preconditions.checkArgument(enumTypeDef.getValues() != null,
510                 "EnumTypeDefinition MUST contain at least ONE value definition!");
511         Preconditions.checkArgument(enumTypeDef.getQName() != null, "EnumTypeDefinition MUST contain NON-NULL QName!");
512         Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
513                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
514         Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
515
516         final String enumerationName = parseToClassName(enumName);
517
518         final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
519         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
520         return enumBuilder.toInstance(enumBuilder);
521     }
522
523     /**
524      * Converts <code>dataNode</code> to JAVA <code>Type</code>.
525      *
526      * @param dataNode
527      *            contains information about YANG type
528      * @return JAVA <code>Type</code> representation of <code>dataNode</code>
529      */
530     private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode) {
531         Type returnType = null;
532         if (dataNode != null) {
533             if (dataNode instanceof LeafSchemaNode) {
534                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
535                 returnType = javaTypeForSchemaDefinitionType(leaf.getType(), leaf);
536             } else if (dataNode instanceof LeafListSchemaNode) {
537                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
538                 returnType = javaTypeForSchemaDefinitionType(leafList.getType(), leafList);
539             }
540         }
541         return returnType;
542     }
543
544     /**
545      * Passes through all modules and through all its type definitions and
546      * convert it to generated types.
547      *
548      * The modules are firstly sorted by mutual dependencies. The modules are
549      * sequentially passed. All type definitions of a module are at the
550      * beginning sorted so that type definition with less amount of references
551      * to other type definition are processed first.<br />
552      * For each module is created mapping record in the map
553      * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap}
554      * which map current module name to the map which maps type names to
555      * returned types (generated types).
556      *
557      */
558     private void resolveTypeDefsFromContext() {
559         final Set<Module> modules = schemaContext.getModules();
560         Preconditions.checkArgument(modules != null, "Sef of Modules cannot be NULL!");
561         final Module[] modulesArray = new Module[modules.size()];
562         int i = 0;
563         for (Module modul : modules) {
564             modulesArray[i++] = modul;
565         }
566         final List<Module> modulesSortedByDependency = ModuleDependencySort.sort(modulesArray);
567
568         for (final Module module : modulesSortedByDependency) {
569             if (module == null) {
570                 continue;
571             }
572             final String moduleName = module.getName();
573             final String basePackageName = moduleNamespaceToPackageName(module);
574
575             final DataNodeIterator it = new DataNodeIterator(module);
576             final List<TypeDefinition<?>> typeDefinitions = it.allTypedefs();
577             final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
578
579             final Map<String, Type> typeMap = new HashMap<>();
580             genTypeDefsContextMap.put(moduleName, typeMap);
581
582             if ((listTypeDefinitions != null) && (basePackageName != null)) {
583                 for (final TypeDefinition<?> typedef : listTypeDefinitions) {
584                     typedefToGeneratedType(basePackageName, moduleName, typedef);
585                 }
586             }
587         }
588     }
589
590     /**
591      *
592      * @param basePackageName
593      *            string with name of package to which the module belongs
594      * @param moduleName
595      *            string with the name of the module for to which the
596      *            <code>typedef</code> belongs
597      * @param typedef
598      *            type definition of the node for which should be creted JAVA
599      *            <code>Type</code> (usually generated TO)
600      * @return JAVA <code>Type</code> representation of <code>typedef</code> or
601      *         <code>null</code> value if <code>basePackageName</code> or
602      *         <code>modulName</code> or <code>typedef</code> or Q name of
603      *         <code>typedef</code> equals <code>null</code>
604      */
605     private Type typedefToGeneratedType(final String basePackageName, final String moduleName,
606             final TypeDefinition<?> typedef) {
607         if ((basePackageName != null) && (moduleName != null) && (typedef != null) && (typedef.getQName() != null)) {
608
609             final String typedefName = typedef.getQName().getLocalName();
610             final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
611             if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
612                     && !(innerTypeDefinition instanceof IdentityrefTypeDefinition)) {
613                 Type returnType = null;
614                 if (innerTypeDefinition instanceof ExtendedType) {
615                     ExtendedType innerExtendedType = (ExtendedType) innerTypeDefinition;
616                     returnType = provideGeneratedTOFromExtendedType(typedef, innerExtendedType, basePackageName);
617                 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
618                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
619                             (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef);
620                     genTOBuilder.setIsUnion(true);
621                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
622                     returnType = genTOBuilder.toInstance();
623                 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
624                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
625                     // TODO units for typedef enum
626                     returnType = provideTypeForEnum(enumTypeDef, typedefName, typedef);
627                 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
628                     final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
629                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForBitsTypeDefinition(
630                             basePackageName, bitsTypeDefinition, typedefName);
631                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
632                     returnType = genTOBuilder.toInstance();
633                 } else {
634                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
635                             innerTypeDefinition, typedef);
636                     returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType);
637                 }
638                 if (returnType != null) {
639                     final Map<String, Type> typeMap = genTypeDefsContextMap.get(moduleName);
640                     if (typeMap != null) {
641                         typeMap.put(typedefName, returnType);
642                     }
643                     return returnType;
644                 }
645             }
646         }
647         return null;
648     }
649
650     /**
651      * Wraps base YANG type to generated TO.
652      *
653      * @param basePackageName
654      *            string with name of package to which the module belongs
655      * @param typedef
656      *            type definition which is converted to the TO
657      * @param javaType
658      *            JAVA <code>Type</code> to which is <code>typedef</code> mapped
659      * @return generated transfer object which represent<code>javaType</code>
660      */
661     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
662             final Type javaType) {
663         Preconditions.checkNotNull(javaType, "javaType cannot be null");
664         final String propertyName = "value";
665
666         final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef);
667         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
668         final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
669         genPropBuilder.setReturnType(javaType);
670         genTOBuilder.addEqualsIdentity(genPropBuilder);
671         genTOBuilder.addHashIdentity(genPropBuilder);
672         genTOBuilder.addToStringProperty(genPropBuilder);
673         if (javaType instanceof ConcreteType && "String".equals(javaType.getName()) && typedef instanceof ExtendedType) {
674             final List<String> regExps = resolveRegExpressionsFromTypedef((ExtendedType) typedef);
675             addStringRegExAsConstant(genTOBuilder, regExps);
676         }
677         addUnitsToGenTO(genTOBuilder, typedef.getUnits());
678         return genTOBuilder.toInstance();
679     }
680
681     /**
682      * Converts output list of generated TO builders to one TO builder (first
683      * from list) which contains the remaining builders as its enclosing TO.
684      *
685      * @param basePackageName
686      *            string with name of package to which the module belongs
687      * @param typedef
688      *            type definition which should be of type
689      *            <code>UnionTypeDefinition</code>
690      * @param typeDefName
691      *            string with name for generated TO
692      * @return generated TO builder with the list of enclosed generated TO
693      *         builders
694      */
695     public GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
696             final UnionTypeDefinition typedef, String typeDefName, SchemaNode parentNode) {
697         final List<GeneratedTOBuilder> genTOBuilders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
698                 typedef, typeDefName, parentNode);
699         GeneratedTOBuilder resultTOBuilder = null;
700         if (!genTOBuilders.isEmpty()) {
701             resultTOBuilder = genTOBuilders.get(0);
702             genTOBuilders.remove(0);
703             for (GeneratedTOBuilder genTOBuilder : genTOBuilders) {
704                 resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
705             }
706         }
707         return resultTOBuilder;
708     }
709
710     /**
711      * Converts <code>typedef</code> to generated TO with
712      * <code>typeDefName</code>. Every union type from <code>typedef</code> is
713      * added to generated TO builder as property.
714      *
715      * @param basePackageName
716      *            string with name of package to which the module belongs
717      * @param typedef
718      *            type definition which should be of type
719      *            <code>UnionTypeDefinition</code>
720      * @param typeDefName
721      *            string with name for generated TO
722      * @return generated TO builder which represents <code>typedef</code>
723      * @throws IllegalArgumentException
724      *             <ul>
725      *             <li>if <code>basePackageName</code> equals null</li>
726      *             <li>if <code>typedef</code> equals null</li>
727      *             <li>if Q name of <code>typedef</code> equals null</li>
728      *             </ul>
729      */
730     public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
731             final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode) {
732         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
733         Preconditions.checkArgument(typedef != null, "Type Definition cannot be NULL!");
734         Preconditions.checkArgument(typedef.getQName() != null,
735                 "Type Definition cannot have non specified QName (QName cannot be NULL!)");
736
737         final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
738
739         if (typedef != null) {
740             final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
741
742             final GeneratedTOBuilder unionGenTOBuilder;
743             if (typeDefName != null && !typeDefName.isEmpty()) {
744                 final String typeName = parseToClassName(typeDefName);
745                 unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
746             } else {
747                 unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef);
748             }
749             generatedTOBuilders.add(unionGenTOBuilder);
750             unionGenTOBuilder.setIsUnion(true);
751             final List<String> regularExpressions = new ArrayList<String>();
752             for (final TypeDefinition<?> unionType : unionTypes) {
753                 final String unionTypeName = unionType.getQName().getLocalName();
754                 if (unionType instanceof UnionType) {
755                     generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionType) unionType,
756                             basePackageName, parentNode));
757                 } else if (unionType instanceof ExtendedType) {
758                     resolveExtendedSubtypeAsUnion(unionGenTOBuilder, (ExtendedType) unionType, unionTypeName,
759                             regularExpressions, parentNode);
760                 } else if (unionType instanceof EnumTypeDefinition) {
761                     final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
762                             unionTypeName, unionGenTOBuilder);
763                     updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
764                 } else {
765                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
766                             unionType, parentNode);
767                     updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
768                 }
769             }
770             if (!regularExpressions.isEmpty()) {
771                 addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
772             }
773
774             storeGenTO(typedef, unionGenTOBuilder, parentNode);
775         }
776         return generatedTOBuilders;
777     }
778
779     /**
780      * Wraps code which handle case when union subtype is also of the type
781      * <code>UnionType</code>.
782      *
783      * In this case the new generated TO is created for union subtype (recursive
784      * call of method
785      * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, TypeDefinition, String)
786      * provideGeneratedTOBuilderForUnionTypeDef} and in parent TO builder
787      * <code>parentUnionGenTOBuilder</code> is created property which type is
788      * equal to new generated TO.
789      *
790      * @param parentUnionGenTOBuilder
791      *            generated TO builder to which is the property with the child
792      *            union subtype added
793      * @param basePackageName
794      *            string with the name of the module package
795      * @param unionSubtype
796      *            type definition which represents union subtype
797      * @return list of generated TO builders. The number of the builders can be
798      *         bigger one due to recursive call of
799      *         <code>provideGeneratedTOBuildersForUnionTypeDef</code> method.
800      */
801     private List<GeneratedTOBuilder> resolveUnionSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
802             final UnionTypeDefinition unionSubtype, final String basePackageName, final SchemaNode parentNode) {
803         final String newTOBuilderName = provideAvailableNameForGenTOBuilder(parentUnionGenTOBuilder.getName());
804         final List<GeneratedTOBuilder> subUnionGenTOBUilders = provideGeneratedTOBuildersForUnionTypeDef(
805                 basePackageName, unionSubtype, newTOBuilderName, parentNode);
806
807         final GeneratedPropertyBuilder propertyBuilder;
808         propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingGeneratorUtil
809                 .parseToValidParamName(newTOBuilderName));
810         propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
811         parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
812         parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
813
814         return subUnionGenTOBUilders;
815     }
816
817     /**
818      * Wraps code which handle case when union subtype is of the type
819      * <code>ExtendedType</code>.
820      *
821      * If TO for this type already exists it is used for the creation of the
822      * property in <code>parentUnionGenTOBuilder</code>. In other case the base
823      * type is used for the property creation.
824      *
825      * @param parentUnionGenTOBuilder
826      *            generated TO builder in which new property is created
827      * @param unionSubtype
828      *            type definition of the <code>ExtendedType</code> type which
829      *            represents union subtype
830      * @param unionTypeName
831      *            string with the name for <code>unionSubtype</code>
832      * @param regularExpressions
833      *            list of strings with the regular expressions
834      */
835     private void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
836             final ExtendedType unionSubtype, final String unionTypeName, final List<String> regularExpressions,
837             final SchemaNode parentNode) {
838         final Type genTO = findGenTO(unionTypeName, parentNode);
839         if (genTO != null) {
840             updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
841         } else {
842             final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
843             if (unionTypeName.equals(baseType.getQName().getLocalName())) {
844                 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
845                         parentNode);
846                 if (javaType != null) {
847                     updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
848                 }
849             }
850             if (baseType instanceof StringType) {
851                 regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
852             }
853         }
854     }
855
856     /**
857      * Searches for generated TO for <code>searchedTypeDef</code> type
858      * definition in {@link #genTypeDefsContextMap genTypeDefsContextMap}
859      *
860      * @param searchedTypeName
861      *            string with name of <code>searchedTypeDef</code>
862      * @return generated TO for <code>searchedTypeDef</code> or
863      *         <code>null</code> it it doesn't exist
864      */
865     private Type findGenTO(final String searchedTypeName, final SchemaNode parentNode) {
866         final Module typeModule = findParentModule(schemaContext, parentNode);
867         if (typeModule != null && typeModule.getName() != null) {
868             final Map<String, Type> genTOs = genTypeDefsContextMap.get(typeModule.getName());
869             if (genTOs != null) {
870                 return genTOs.get(searchedTypeName);
871             }
872         }
873         return null;
874     }
875
876     /**
877      * Stores generated TO created from <code>genTOBuilder</code> for
878      * <code>newTypeDef</code> to {@link #genTypeDefsContextMap
879      * genTypeDefsContextMap} if the module for <code>newTypeDef</code> exists
880      *
881      * @param newTypeDef
882      *            type definition for which is <code>genTOBuilder</code> created
883      * @param genTOBuilder
884      *            generated TO builder which is converted to generated TO and
885      *            stored
886      */
887     private void storeGenTO(TypeDefinition<?> newTypeDef, GeneratedTOBuilder genTOBuilder, SchemaNode parentNode) {
888         if (!(newTypeDef instanceof UnionType)) {
889             Map<String, Type> genTOsMap = null;
890             final Module parentModule = findParentModule(schemaContext, parentNode);
891             if (parentModule != null && parentModule.getName() != null) {
892                 genTOsMap = genTypeDefsContextMap.get(parentModule.getName());
893                 genTOsMap.put(newTypeDef.getQName().getLocalName(), genTOBuilder.toInstance());
894             }
895         }
896     }
897
898     /**
899      * Adds a new property with the name <code>propertyName</code> and with type
900      * <code>type</code> to <code>unonGenTransObject</code>.
901      *
902      * @param unionGenTransObject
903      *            generated TO to which should be property added
904      * @param type
905      *            JAVA <code>type</code> of the property which should be added
906      *            to <code>unionGentransObject</code>
907      * @param propertyName
908      *            string with name of property which should be added to
909      *            <code>unionGentransObject</code>
910      */
911     private void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type,
912             final String propertyName) {
913         if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
914             final GeneratedPropertyBuilder propBuilder = unionGenTransObject
915                     .addProperty(parseToValidParamName(propertyName));
916             propBuilder.setReturnType(type);
917
918             unionGenTransObject.addEqualsIdentity(propBuilder);
919             unionGenTransObject.addHashIdentity(propBuilder);
920             unionGenTransObject.addToStringProperty(propBuilder);
921         }
922     }
923
924     /**
925      * Converts <code>typedef</code> to the generated TO builder.
926      *
927      * @param basePackageName
928      *            string with name of package to which the module belongs
929      * @param typedef
930      *            type definition from which is the generated TO builder created
931      * @return generated TO builder which contains data from
932      *         <code>typedef</code> and <code>basePackageName</code>
933      */
934     private GeneratedTOBuilder typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef) {
935
936         final String packageName = packageNameForGeneratedType(basePackageName, typedef.getPath());
937         final String typeDefTOName = typedef.getQName().getLocalName();
938
939         if ((packageName != null) && (typedef != null) && (typeDefTOName != null)) {
940             final String genTOName = parseToClassName(typeDefTOName);
941             final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTOName);
942             newType.addComment(typedef.getDescription());
943             return newType;
944         }
945         return null;
946     }
947
948     /**
949      * Converts <code>typeDef</code> which should be of the type
950      * <code>BitsTypeDefinition</code> to <code>GeneratedTOBuilder</code>.
951      *
952      * All the bits of the typeDef are added to returning generated TO as
953      * properties.
954      *
955      * @param basePackageName
956      *            string with name of package to which the module belongs
957      * @param typeDef
958      *            type definition from which is the generated TO builder created
959      * @param typeDefName
960      *            string with the name for generated TO builder
961      * @return generated TO builder which represents <code>typeDef</code>
962      * @throws IllegalArgumentException
963      *             <ul>
964      *             <li>if <code>typeDef</code> equals null</li>
965      *             <li>if <code>basePackageName</code> equals null</li>
966      *             </ul>
967      */
968     public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName,
969             final TypeDefinition<?> typeDef, String typeDefName) {
970
971         Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
972         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
973
974         if (typeDef instanceof BitsTypeDefinition) {
975             BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
976
977             final String typeName = parseToClassName(typeDefName);
978             final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
979
980             final List<Bit> bitList = bitsTypeDefinition.getBits();
981             GeneratedPropertyBuilder genPropertyBuilder;
982             for (final Bit bit : bitList) {
983                 String name = bit.getName();
984                 genPropertyBuilder = genTOBuilder.addProperty(parseToValidParamName(name));
985                 genPropertyBuilder.setReadOnly(true);
986                 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
987
988                 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
989                 genTOBuilder.addHashIdentity(genPropertyBuilder);
990                 genTOBuilder.addToStringProperty(genPropertyBuilder);
991             }
992
993             return genTOBuilder;
994         }
995         return null;
996     }
997
998     /**
999      * Converts the pattern constraints from <code>typedef</code> to the list of
1000      * the strings which represents these constraints.
1001      *
1002      * @param typedef
1003      *            extended type in which are the pattern constraints sought
1004      * @return list of strings which represents the constraint patterns
1005      * @throws IllegalArgumentException
1006      *             if <code>typedef</code> equals null
1007      *
1008      */
1009     private List<String> resolveRegExpressionsFromTypedef(ExtendedType typedef) {
1010         final List<String> regExps = new ArrayList<String>();
1011         Preconditions.checkArgument(typedef != null, "typedef can't be null");
1012         final TypeDefinition<?> strTypeDef = baseTypeDefForExtendedType(typedef);
1013         if (strTypeDef instanceof StringType) {
1014             final List<PatternConstraint> patternConstraints = typedef.getPatternConstraints();
1015             if (!patternConstraints.isEmpty()) {
1016                 String regEx;
1017                 String modifiedRegEx;
1018                 for (PatternConstraint patternConstraint : patternConstraints) {
1019                     regEx = patternConstraint.getRegularExpression();
1020                     modifiedRegEx = StringEscapeUtils.escapeJava(regEx);
1021                     regExps.add(modifiedRegEx);
1022                 }
1023             }
1024         }
1025         return regExps;
1026     }
1027
1028     /**
1029      *
1030      * Adds to the <code>genTOBuilder</code> the constant which contains regular
1031      * expressions from the <code>regularExpressions</code>
1032      *
1033      * @param genTOBuilder
1034      *            generated TO builder to which are
1035      *            <code>regular expressions</code> added
1036      * @param regularExpressions
1037      *            list of string which represent regular expressions
1038      * @throws IllegalArgumentException
1039      *             <ul>
1040      *             <li>if <code>genTOBuilder</code> equals null</li>
1041      *             <li>if <code>regularExpressions</code> equals null</li>
1042      *             </ul>
1043      */
1044     private void addStringRegExAsConstant(GeneratedTOBuilder genTOBuilder, List<String> regularExpressions) {
1045         if (genTOBuilder == null) {
1046             throw new IllegalArgumentException("Generated transfer object builder can't be null");
1047         }
1048         if (regularExpressions == null) {
1049             throw new IllegalArgumentException("List of regular expressions can't be null");
1050         }
1051         if (!regularExpressions.isEmpty()) {
1052             genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), TypeConstants.PATTERN_CONSTANT_NAME,
1053                     regularExpressions);
1054         }
1055     }
1056
1057     /**
1058      * Creates generated TO with data about inner extended type
1059      * <code>innerExtendedType</code>, about the package name
1060      * <code>typedefName</code> and about the generated TO name
1061      * <code>typedefName</code>.
1062      *
1063      * It is supposed that <code>innerExtendedType</code> is already present in
1064      * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap} to
1065      * be possible set it as extended type for the returning generated TO.
1066      *
1067      * @param innerExtendedType
1068      *            extended type which is part of some other extended type
1069      * @param basePackageName
1070      *            string with the package name of the module
1071      * @param typedefName
1072      *            string with the name for the generated TO
1073      * @return generated TO which extends generated TO for
1074      *         <code>innerExtendedType</code>
1075      * @throws IllegalArgumentException
1076      *             <ul>
1077      *             <li>if <code>extendedType</code> equals null</li>
1078      *             <li>if <code>basePackageName</code> equals null</li>
1079      *             <li>if <code>typedefName</code> equals null</li>
1080      *             </ul>
1081      */
1082     private GeneratedTransferObject provideGeneratedTOFromExtendedType(final TypeDefinition<?> typedef, final ExtendedType innerExtendedType,
1083             final String basePackageName) {
1084         Preconditions.checkArgument(innerExtendedType != null, "Extended type cannot be NULL!");
1085         Preconditions.checkArgument(basePackageName != null, "String with base package name cannot be NULL!");
1086
1087         final String typedefName = typedef.getQName().getLocalName();
1088         final String classTypedefName = parseToClassName(typedefName);
1089         final String innerTypeDef = innerExtendedType.getQName().getLocalName();
1090         final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, classTypedefName);
1091         Restrictions r = BindingGeneratorUtil.getRestrictions(typedef);
1092         genTOBuilder.setRestrictions(r);
1093
1094         if (baseTypeDefForExtendedType(innerExtendedType) instanceof UnionTypeDefinition) {
1095             genTOBuilder.setIsUnion(true);
1096         }
1097
1098         Map<String, Type> typeMap = null;
1099         final Module parentModule = findParentModule(schemaContext, innerExtendedType);
1100         if (parentModule != null) {
1101             typeMap = genTypeDefsContextMap.get(parentModule.getName());
1102         }
1103
1104         if (typeMap != null) {
1105             Type type = typeMap.get(innerTypeDef);
1106             if (type instanceof GeneratedTransferObject) {
1107                 genTOBuilder.setExtendsType((GeneratedTransferObject) type);
1108             }
1109         }
1110         addUnitsToGenTO(genTOBuilder, typedef.getUnits());
1111
1112         return genTOBuilder.toInstance();
1113     }
1114
1115     /**
1116      * Finds out for each type definition how many immersion (depth) is
1117      * necessary to get to the base type. Every type definition is inserted to
1118      * the map which key is depth and value is list of type definitions with
1119      * equal depth. In next step are lists from this map concatenated to one
1120      * list in ascending order according to their depth. All type definitions
1121      * are in the list behind all type definitions on which depends.
1122      *
1123      * @param unsortedTypeDefinitions
1124      *            list of type definitions which should be sorted by depth
1125      * @return list of type definitions sorted according their each other
1126      *         dependencies (type definitions which are depend on other type
1127      *         definitions are in list behind them).
1128      */
1129     private List<TypeDefinition<?>> sortTypeDefinitionAccordingDepth(
1130             final Collection<TypeDefinition<?>> unsortedTypeDefinitions) {
1131         List<TypeDefinition<?>> sortedTypeDefinition = new ArrayList<>();
1132
1133         Map<Integer, List<TypeDefinition<?>>> typeDefinitionsDepths = new TreeMap<>();
1134         for (TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
1135             final int depth = getTypeDefinitionDepth(unsortedTypeDefinition);
1136             List<TypeDefinition<?>> typeDefinitionsConcreteDepth = typeDefinitionsDepths.get(depth);
1137             if (typeDefinitionsConcreteDepth == null) {
1138                 typeDefinitionsConcreteDepth = new ArrayList<TypeDefinition<?>>();
1139                 typeDefinitionsDepths.put(depth, typeDefinitionsConcreteDepth);
1140             }
1141             typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
1142         }
1143         // keys are in ascending order
1144         Set<Integer> depths = typeDefinitionsDepths.keySet();
1145         for (Integer depth : depths) {
1146             sortedTypeDefinition.addAll(typeDefinitionsDepths.get(depth));
1147         }
1148
1149         return sortedTypeDefinition;
1150     }
1151
1152     /**
1153      * Returns how many immersion is necessary to get from the type definition
1154      * to the base type.
1155      *
1156      * @param typeDefinition
1157      *            type definition for which is depth sought.
1158      * @return number of immersions which are necessary to get from the type
1159      *         definition to the base type
1160      */
1161     private int getTypeDefinitionDepth(final TypeDefinition<?> typeDefinition) {
1162         if (typeDefinition == null) {
1163             return 1;
1164         }
1165         int depth = 1;
1166         TypeDefinition<?> baseType = typeDefinition.getBaseType();
1167
1168         if (baseType instanceof ExtendedType) {
1169             depth = depth + getTypeDefinitionDepth(typeDefinition.getBaseType());
1170         } else if (baseType instanceof UnionType) {
1171             List<TypeDefinition<?>> childTypeDefinitions = ((UnionType) baseType).getTypes();
1172             int maxChildDepth = 0;
1173             int childDepth = 1;
1174             for (TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
1175                 childDepth = childDepth + getTypeDefinitionDepth(childTypeDefinition);
1176                 if (childDepth > maxChildDepth) {
1177                     maxChildDepth = childDepth;
1178                 }
1179             }
1180             return maxChildDepth;
1181         }
1182         return depth;
1183     }
1184
1185     /**
1186      * Returns string which contains the same value as <code>name</code> but
1187      * integer suffix is incremented by one. If <code>name</code> contains no
1188      * number suffix then number 1 is added.
1189      *
1190      * @param name
1191      *            string with name of augmented node
1192      * @return string with the number suffix incremented by one (or 1 is added)
1193      */
1194     private String provideAvailableNameForGenTOBuilder(String name) {
1195         Pattern searchedPattern = Pattern.compile("[0-9]+\\z");
1196         Matcher mtch = searchedPattern.matcher(name);
1197         if (mtch.find()) {
1198             final int newSuffix = Integer.valueOf(name.substring(mtch.start())) + 1;
1199             return name.substring(0, mtch.start()) + newSuffix;
1200         } else {
1201             return name + 1;
1202         }
1203     }
1204
1205     private void addUnitsToGenTO(GeneratedTOBuilder to, String units) {
1206         if (units != null && !units.isEmpty()) {
1207             to.addConstant(Types.STRING, "_UNITS", "\"" + units + "\"");
1208             GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("UNITS");
1209             prop.setReturnType(Types.STRING);
1210             to.addToStringProperty(prop);
1211         }
1212     }
1213
1214 }