Bug 1411 #3 BindingGeneratorImpl decomposition - Leafs
[mdsal.git] / binding2 / mdsal-binding2-generator-impl / src / main / java / org / opendaylight / mdsal / binding / javav2 / generator / yang / types / TypeProviderImpl.java
1 /*
2  * Copyright (c) 2017 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
9 package org.opendaylight.mdsal.binding.javav2.generator.yang.types;
10
11 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
12 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.addStringRegExAsConstant;
13 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.baseTypeDefForExtendedType;
14 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.getAllTypedefs;
15 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.getParentModule;
16 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.makeSerializable;
17 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.provideGeneratedTOFromExtendedType;
18 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.provideTypeForEnum;
19 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.resolveRegExpressionsFromTypedef;
20 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.sortTypeDefinitionAccordingDepth;
21 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.wrapJavaTypeIntoTO;
22 import static org.opendaylight.mdsal.binding.javav2.util.BindingMapping.getRootPackageName;
23 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
24 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
25 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
26
27 import com.google.common.annotations.Beta;
28 import com.google.common.base.Preconditions;
29 import com.google.common.base.Strings;
30 import com.google.common.collect.Sets;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Date;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
43 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
44 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
45 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
46 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
47 import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
48 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
49 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
50 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
51 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
52 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
53 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
54 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
55 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilderBase;
56 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
57 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
58 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
59 import org.opendaylight.yangtools.yang.common.QName;
60 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
61 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
62 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
63 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
65 import org.opendaylight.yangtools.yang.model.api.Module;
66 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
67 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
70 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
71 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
72 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
73 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
75 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
77 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
78 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
79 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
80 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
81 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84
85 @Beta
86 public final class TypeProviderImpl implements TypeProvider {
87
88     private static final Logger LOG = LoggerFactory.getLogger(TypeProviderImpl.class);
89     private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z");
90
91     /**
92      * Contains the schema data red from YANG files.
93      */
94     private final SchemaContext schemaContext;
95
96     /**
97      * Map<moduleName, Map<moduleDate, Map<typeName, type>>>
98      */
99     private final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap;
100
101     /**
102      * Map which maps schema paths to JAVA <code>Type</code>.
103      */
104     private final Map<SchemaPath, Type> referencedTypes;
105
106     /**
107      * Map for additional types e.g unions
108      */
109     private final Map<Module, Set<Type>> additionalTypes;
110
111     /**
112      * Creates new instance of class <code>TypeProviderImpl</code>.
113      *
114      * @param schemaContext
115      *            contains the schema data red from YANG files
116      * @throws IllegalArgumentException
117      *             if <code>schemaContext</code> equal null.
118      */
119     public TypeProviderImpl(final SchemaContext schemaContext) {
120         this.schemaContext = schemaContext;
121         this.genTypeDefsContextMap = new HashMap<>();
122         this.referencedTypes = new HashMap<>();
123         this.additionalTypes = new HashMap<>();
124         resolveTypeDefsFromContext(schemaContext, genTypeDefsContextMap, additionalTypes);
125     }
126
127     @Override
128     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> type, SchemaNode parentNode) {
129         return javaTypeForSchemaDefinitionType(type, parentNode, null);
130     }
131
132     /**
133      * Converts schema definition type <code>typeDefinition</code> to JAVA
134      * <code>Type</code>
135      *
136      * @param type
137      *            type definition which is converted to JAVA type
138      * @throws IllegalArgumentException
139      *             <ul>
140      *             <li>if <code>typeDefinition</code> equal null</li>
141      *             <li>if Qname of <code>typeDefinition</code> equal null</li>
142      *             <li>if name of <code>typeDefinition</code> equal null</li>
143      *             </ul>
144      */
145     @Override
146     public Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode, Restrictions restrictions) {
147         return javaTypeForSchemaDefType(type, parentNode, restrictions, this.schemaContext, this.genTypeDefsContextMap);
148     }
149
150     @Override
151     public String getTypeDefaultConstruction(LeafSchemaNode node) {
152         return null;
153     }
154
155     @Override
156     public String getConstructorPropertyName(SchemaNode node) {
157         return null;
158     }
159
160     @Override
161     public String getParamNameFromType(TypeDefinition<?> type) {
162         return null;
163     }
164
165     public Map<String, Map<Date, Map<String, Type>>> getGenTypeDefsContextMap() {
166         return genTypeDefsContextMap;
167     }
168
169     /**
170      * Passes through all modules and through all its type definitions and
171      * convert it to generated types.
172      *
173      * The modules are firstly sorted by mutual dependencies. The modules are
174      * sequentially passed. All type definitions of a module are at the
175      * beginning sorted so that type definition with less amount of references
176      * to other type definition are processed first.<br />
177      * For each module is created mapping record in the map
178      * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap}
179      * which map current module name to the map which maps type names to
180      * returned types (generated types).
181      *
182      */
183     private void resolveTypeDefsFromContext(final SchemaContext schemaContext, Map<String, Map<Date, Map<String,
184             Type>>> genTypeDefsContextMap,  Map<Module, Set<Type>> additionalTypes) {
185
186         final Set<Module> modules = schemaContext.getModules();
187         Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
188         final Module[] modulesArray = new Module[modules.size()];
189         int i = 0;
190         for (Module modul : modules) {
191             modulesArray[i++] = modul;
192         }
193         final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
194                 .sort(modulesArray);
195
196         for (final Module module : modulesSortedByDependency) {
197             Map<Date, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
198             if (dateTypeMap == null) {
199                 dateTypeMap = new HashMap<>();
200             }
201             dateTypeMap.put(module.getRevision(), Collections.emptyMap());
202             genTypeDefsContextMap.put(module.getName(), dateTypeMap);
203         }
204
205         modulesSortedByDependency.stream().filter(module -> module != null).forEach(module -> {
206             final String basePackageName = getRootPackageName(module);
207             final List<TypeDefinition<?>> typeDefinitions = getAllTypedefs(module);
208             final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
209             if (listTypeDefinitions != null) {
210                 for (final TypeDefinition<?> typedef : listTypeDefinitions) {
211                     typedefToGeneratedType(basePackageName, module, typedef, genTypeDefsContextMap,
212                             additionalTypes, schemaContext);
213                 }
214             }
215         });
216     }
217
218     /**
219      * Converts <code>typeDefinition</code> to concrete JAVA <code>Type</code>.
220      *
221      * @param typeDefinition
222      *            type definition which should be converted to JAVA
223      *            <code>Type</code>
224      * @return JAVA <code>Type</code> which represents
225      *         <code>typeDefinition</code>
226      * @throws IllegalArgumentException
227      *             <ul>
228      *             <li>if <code>typeDefinition</code> equal null</li>
229      *             <li>if Q name of <code>typeDefinition</code></li>
230      *             <li>if name of <code>typeDefinition</code></li>
231      *             </ul>
232      */
233     public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
234         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
235         Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
236                 "Type Definitions Local Name cannot be NULL!");
237
238         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
239         if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
240             final Module module = findParentModule(schemaContext, parentNode);
241
242             if (module != null) {
243                 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
244                 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
245                 if (genTOs != null) {
246                     return genTOs.get(typeDefinition.getQName().getLocalName());
247                 }
248             }
249         }
250         return null;
251     }
252
253     /**
254      * Puts <code>refType</code> to map with key <code>refTypePath</code>
255      *
256      * @param refTypePath
257      *            schema path used as the map key
258      * @param refType
259      *            type which represents the map value
260      * @throws IllegalArgumentException
261      *             <ul>
262      *             <li>if <code>refTypePath</code> equal null</li>
263      *             <li>if <code>refType</code> equal null</li>
264      *             </ul>
265      *
266      */
267     public void putReferencedType(final SchemaPath refTypePath, final Type refType) {
268         Preconditions.checkArgument(refTypePath != null,
269                 "Path reference of Enumeration Type Definition cannot be NULL!");
270         Preconditions.checkArgument(refType != null, "Reference to Enumeration Type cannot be NULL!");
271         referencedTypes.put(refTypePath, refType);
272     }
273
274     /**
275      * Converts <code>typeDef</code> which should be of the type
276      * <code>BitsTypeDefinition</code> to <code>GeneratedTOBuilder</code>.
277      *
278      * All the bits of the typeDef are added to returning generated TO as
279      * properties.
280      *
281      * @param basePackageName
282      *            string with name of package to which the module belongs
283      * @param typeDef
284      *            type definition from which is the generated TO builder created
285      * @param typeDefName
286      *            string with the name for generated TO builder
287      * @return generated TO builder which represents <code>typeDef</code>
288      * @throws IllegalArgumentException
289      *             <ul>
290      *             <li>if <code>typeDef</code> equals null</li>
291      *             <li>if <code>basePackageName</code> equals null</li>
292      *             </ul>
293      */
294     public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName, final
295     TypeDefinition<?> typeDef, final String typeDefName, final String moduleName) {
296
297         Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
298         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
299
300         if (typeDef instanceof BitsTypeDefinition) {
301             BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
302
303             final String typeName = BindingMapping.getClassName(typeDefName);
304             final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
305             final String typedefDescription = encodeAngleBrackets(typeDef.getDescription());
306
307             genTOBuilder.setDescription(typedefDescription);
308             genTOBuilder.setReference(typeDef.getReference());
309             genTOBuilder.setSchemaPath((List) typeDef.getPath().getPathFromRoot());
310             genTOBuilder.setModuleName(moduleName);
311             genTOBuilder.setBaseType(typeDef);
312
313             final List<Bit> bitList = bitsTypeDefinition.getBits();
314             GeneratedPropertyBuilder genPropertyBuilder;
315             for (final Bit bit : bitList) {
316                 String name = bit.getName();
317                 genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
318                 genPropertyBuilder.setReadOnly(true);
319                 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
320
321                 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
322                 genTOBuilder.addHashIdentity(genPropertyBuilder);
323                 genTOBuilder.addToStringProperty(genPropertyBuilder);
324             }
325
326             return genTOBuilder;
327         }
328         return null;
329     }
330
331     /**
332      * Converts <code>typedef</code> to generated TO with
333      * <code>typeDefName</code>. Every union type from <code>typedef</code> is
334      * added to generated TO builder as property.
335      *
336      * @param basePackageName
337      *            string with name of package to which the module belongs
338      * @param typedef
339      *            type definition which should be of type
340      *            <code>UnionTypeDefinition</code>
341      * @param typeDefName
342      *            string with name for generated TO
343      * @return generated TO builder which represents <code>typedef</code>
344      * @throws NullPointerException
345      *             <ul>
346      *             <li>if <code>basePackageName</code> is null</li>
347      *             <li>if <code>typedef</code> is null</li>
348      *             <li>if Qname of <code>typedef</code> is null</li>
349      *             </ul>
350      */
351     public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
352         final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode, final SchemaContext
353          schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
354         Preconditions.checkNotNull(basePackageName, "Base Package Name cannot be NULL!");
355         Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
356         Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
357
358         final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
359         final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
360         final Module module = findParentModule(schemaContext, parentNode);
361
362         final GeneratedTOBuilderImpl unionGenTOBuilder;
363         if (typeDefName != null && !typeDefName.isEmpty()) {
364             final String typeName = BindingMapping.getClassName(typeDefName);
365             unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
366             final String typedefDescription = encodeAngleBrackets(typedef.getDescription());
367             unionGenTOBuilder.setDescription(typedefDescription);
368             unionGenTOBuilder.setReference(typedef.getReference());
369             unionGenTOBuilder.setSchemaPath((List) typedef.getPath().getPathFromRoot());
370             unionGenTOBuilder.setModuleName(module.getName());
371         } else {
372             unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef, module.getName());
373         }
374
375         generatedTOBuilders.add(unionGenTOBuilder);
376         unionGenTOBuilder.setIsUnion(true);
377         final List<String> regularExpressions = new ArrayList<>();
378         for (final TypeDefinition<?> unionType : unionTypes) {
379             final String unionTypeName = unionType.getQName().getLocalName();
380             if (unionType.getBaseType() != null) {
381                 resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, regularExpressions,
382                         parentNode, schemaContext, genTypeDefsContextMap);
383             } else if (unionType instanceof UnionTypeDefinition) {
384                 generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionTypeDefinition) unionType,
385                         basePackageName, parentNode, schemaContext, genTypeDefsContextMap));
386             } else if (unionType instanceof EnumTypeDefinition) {
387                 final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
388                         unionTypeName, unionGenTOBuilder);
389                 updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
390             } else {
391                 final Type javaType = javaTypeForSchemaDefType(unionType, parentNode, null, schemaContext,
392                         genTypeDefsContextMap);
393                 updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
394             }
395         }
396         if (!regularExpressions.isEmpty()) {
397             addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
398         }
399
400         //storeGenTO(typedef, unionGenTOBuilder, parentNode);
401
402         return generatedTOBuilders;
403     }
404
405     public Map<Module, Set<Type>> getAdditionalTypes() {
406         return additionalTypes;
407     }
408
409     public static void addUnitsToGenTO(final GeneratedTOBuilder to, final String units) {
410         if (!Strings.isNullOrEmpty(units)) {
411             to.addConstant(Types.STRING, "Units", "\"" + units + "\"");
412             GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("UNITS");
413             prop.setReturnType(Types.STRING);
414             to.addToStringProperty(prop);
415         }
416     }
417
418     private Type javaTypeForSchemaDefType(final TypeDefinition<?> typeDefinition, final SchemaNode
419             parentNode, final Restrictions r, final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
420         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
421         String typedefName = typeDefinition.getQName().getLocalName();
422         Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
423
424         // Deal with base types
425         if (typeDefinition.getBaseType() == null) {
426             // We have to deal with differing handling of decimal64. The old parser used a fixed Decimal64 type
427             // and generated an enclosing ExtendedType to hold any range constraints. The new parser instantiates
428             // a base type which holds these constraints.
429             if (typeDefinition instanceof DecimalTypeDefinition) {
430                 final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode, r);
431                 if (ret != null) {
432                     return ret;
433                 }
434             }
435
436             // Deal with leafrefs/identityrefs
437             Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode, schemaContext, genTypeDefsContextMap);
438             if (ret != null) {
439                 return ret;
440             }
441
442             ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode);
443             if (ret == null) {
444                 LOG.debug("Failed to resolve Java type for {}", typeDefinition);
445             }
446
447             return ret;
448         }
449
450         Type returnType = javaTypeForExtendedType(typeDefinition, schemaContext, genTypeDefsContextMap);
451         if (r != null && returnType instanceof GeneratedTransferObject) {
452             GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
453             Module module = findParentModule(schemaContext, parentNode);
454             String basePackageName = BindingMapping.getRootPackageName(module);
455             String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typeDefinition
456                     .getPath(), BindingNamespaceType.Typedef);
457             String genTOName = BindingMapping.getClassName(typedefName);
458             String name = packageName + "." + genTOName;
459             if (!(returnType.getFullyQualifiedName().equals(name))) {
460                 returnType = shadedTOWithRestrictions(gto, r);
461             }
462         }
463         return returnType;
464     }
465
466     /**
467      *
468      * @param basePackageName
469      *            string with name of package to which the module belongs
470      * @param module
471      *            string with the name of the module for to which the
472      *            <code>typedef</code> belongs
473      * @param typedef
474      *            type definition of the node for which should be creted JAVA
475      *            <code>Type</code> (usually generated TO)
476      * @return JAVA <code>Type</code> representation of <code>typedef</code> or
477      *         <code>null</code> value if <code>basePackageName</code> or
478      *         <code>modulName</code> or <code>typedef</code> or Q name of
479      *         <code>typedef</code> equals <code>null</code>
480      */
481     private Type typedefToGeneratedType(final String basePackageName, final Module module, final
482     TypeDefinition<?> typedef, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap, Map<Module,
483             Set<Type>> additionalTypes, final SchemaContext schemaContext) {
484         final String moduleName = module.getName();
485         final Date moduleRevision = module.getRevision();
486         if ((basePackageName != null) && (moduleName != null) && (typedef != null)) {
487             final String typedefName = typedef.getQName().getLocalName();
488             final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
489             if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
490                     && !(innerTypeDefinition instanceof IdentityrefTypeDefinition)) {
491                 Type returnType;
492                 if (innerTypeDefinition.getBaseType() != null) {
493                     returnType = provideGeneratedTOFromExtendedType(typedef, innerTypeDefinition, basePackageName,
494                             module.getName(), schemaContext, genTypeDefsContextMap);
495                 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
496                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
497                             (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef, schemaContext, genTypeDefsContextMap);
498                     genTOBuilder.setTypedef(true);
499                     genTOBuilder.setIsUnion(true);
500                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
501                     makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
502                     returnType = genTOBuilder.toInstance();
503                     // union builder
504                     GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
505                             genTOBuilder.getName() + "Builder");
506                     unionBuilder.setIsUnionBuilder(true);
507                     MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
508                     method.setReturnType(returnType);
509                     method.addParameter(Types.STRING, "defaultValue");
510                     method.setAccessModifier(AccessModifier.PUBLIC);
511                     method.setStatic(true);
512                     Set<Type> types = additionalTypes.get(module);
513                     if (types == null) {
514                         types = Sets.newHashSet(unionBuilder.toInstance());
515                         additionalTypes.put(module, types);
516                     } else {
517                         types.add(unionBuilder.toInstance());
518                     }
519                 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
520                     // enums are automatically Serializable
521                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
522                     // TODO units for typedef enum
523                     returnType = provideTypeForEnum(enumTypeDef, typedefName, typedef, schemaContext);
524                 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
525                     final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
526                     final GeneratedTOBuilder genTOBuilder =
527                             provideGeneratedTOBuilderForBitsTypeDefinition(
528                                     basePackageName, bitsTypeDefinition, typedefName, module.getName());
529                     genTOBuilder.setTypedef(true);
530                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
531                     makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
532                     returnType = genTOBuilder.toInstance();
533                 } else {
534                     final Type javaType = javaTypeForSchemaDefType(innerTypeDefinition, typedef, null,
535                             schemaContext, genTypeDefsContextMap);
536                     returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType, module.getName());
537                 }
538                 if (returnType != null) {
539                     final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(moduleName);
540                     Map<String, Type> typeMap = modulesByDate.get(moduleRevision);
541                     if (typeMap != null) {
542                         if (typeMap.isEmpty()) {
543                             typeMap = new HashMap<>(4);
544                             modulesByDate.put(moduleRevision, typeMap);
545                         }
546                         typeMap.put(typedefName, returnType);
547                     }
548                     return returnType;
549                 }
550             }
551         }
552         return null;
553     }
554
555     /**
556      * Returns JAVA <code>Type</code> for instances of the type
557      * <code>ExtendedType</code>.
558      *
559      * @param typeDefinition
560      *            type definition which is converted to JAVA <code>Type</code>
561      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
562      */
563     private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition, final SchemaContext
564             schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
565
566         final String typedefName = typeDefinition.getQName().getLocalName();
567         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
568         Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition, schemaContext, genTypeDefsContextMap);
569         if (returnType == null) {
570             if (baseTypeDef instanceof EnumTypeDefinition) {
571                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
572                 returnType = provideTypeForEnum(enumTypeDef, typedefName, typeDefinition, schemaContext);
573             } else {
574                 final Module module = findParentModule(schemaContext, typeDefinition);
575                 Restrictions r = BindingGeneratorUtil.getRestrictions(typeDefinition);
576                 if (module != null) {
577                     final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
578                     final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
579                     if (genTOs != null) {
580                         returnType = genTOs.get(typedefName);
581                     }
582                     if (returnType == null) {
583                         returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
584                                 baseTypeDef, typeDefinition, r);
585                     }
586                 }
587             }
588         }
589         return returnType;
590     }
591
592     /**
593      * Returns JAVA <code>Type</code> for instances of the type
594      * <code>LeafrefTypeDefinition</code> or
595      * <code>IdentityrefTypeDefinition</code>.
596      *
597      * @param typeDefinition
598      *            type definition which is converted to JAVA <code>Type</code>
599      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
600      */
601     private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
602             final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
603         if (typeDefinition instanceof LeafrefTypeDefinition) {
604             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
605             if (isLeafRefSelfReference(leafref, parentNode, schemaContext)) {
606                 throw new YangValidationException("Leafref " + leafref.toString() + " is referencing itself, incoming" +
607                         " StackOverFlowError detected.");
608             }
609             return provideTypeForLeafref(leafref, parentNode, schemaContext, genTypeDefsContextMap);
610         } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
611             final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
612             return provideTypeForIdentityref(idref, schemaContext);
613         } else {
614             return null;
615         }
616     }
617
618     /**
619      * Converts <code>leafrefType</code> to JAVA <code>Type</code>.
620      *
621      * The path of <code>leafrefType</code> is followed to find referenced node
622      * and its <code>Type</code> is returned.
623      *
624      * @param leafrefType
625      *            leafref type definition for which is the type sought
626      * @return JAVA <code>Type</code> of data schema node which is referenced in
627      *         <code>leafrefType</code>
628      * @throws IllegalArgumentException
629      *             <ul>
630      *             <li>if <code>leafrefType</code> equal null</li>
631      *             <li>if path statement of <code>leafrefType</code> equal null</li>
632      *             </ul>
633      *
634      */
635     public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode,
636             final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
637
638         Type returnType = null;
639         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
640
641         Preconditions.checkArgument(leafrefType.getPathStatement() != null,
642                 "The Path Statement for Leafref Type Definition cannot be NULL!");
643
644         final RevisionAwareXPath xpath = leafrefType.getPathStatement();
645         final String strXPath = xpath.toString();
646
647         if (strXPath != null) {
648             if (strXPath.indexOf('[') == -1) {
649                 final Module module = findParentModule(schemaContext, parentNode);
650                 Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
651
652                 final SchemaNode dataNode;
653                 if (xpath.isAbsolute()) {
654                     dataNode = findDataSchemaNode(schemaContext, module, xpath);
655                 } else {
656                     dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
657                 }
658                 Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
659                         strXPath, getParentModule(parentNode, schemaContext).getName(), parentNode.getQName().getModule());
660
661                 if (leafContainsEnumDefinition(dataNode)) {
662                     returnType = referencedTypes.get(dataNode.getPath());
663                 } else if (leafListContainsEnumDefinition(dataNode)) {
664                     returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
665                 } else {
666                     returnType = resolveTypeFromDataSchemaNode(dataNode, schemaContext, genTypeDefsContextMap);
667                 }
668             } else {
669                 returnType = Types.typeForClass(Object.class);
670             }
671         }
672         Preconditions.checkArgument(returnType != null, "Failed to find leafref target: %s in module %s (%s)",
673                 strXPath, getParentModule(parentNode, schemaContext).getName(), parentNode.getQName().getModule());
674         return returnType;
675     }
676
677     /**
678      * Checks if <code>dataNode</code> is <code>LeafSchemaNode</code> and if it
679      * so then checks if it is of type <code>EnumTypeDefinition</code>.
680      *
681      * @param dataNode
682      *            data schema node for which is checked if it is leaf and if it
683      *            is of enum type
684      * @return boolean value
685      *         <ul>
686      *         <li>true - if <code>dataNode</code> is leaf of type enumeration</li>
687      *         <li>false - other cases</li>
688      *         </ul>
689      */
690     private static boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
691         if (dataNode instanceof LeafSchemaNode) {
692             final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
693             //CompatUtils is not used here anymore
694             if (leaf.getType() instanceof EnumTypeDefinition) {
695                 return true;
696             }
697         }
698         return false;
699     }
700
701     /**
702      * Checks if <code>dataNode</code> is <code>LeafListSchemaNode</code> and if
703      * it so then checks if it is of type <code>EnumTypeDefinition</code>.
704      *
705      * @param dataNode
706      *            data schema node for which is checked if it is leaflist and if
707      *            it is of enum type
708      * @return boolean value
709      *         <ul>
710      *         <li>true - if <code>dataNode</code> is leaflist of type
711      *         enumeration</li>
712      *         <li>false - other cases</li>
713      *         </ul>
714      */
715     private static boolean leafListContainsEnumDefinition(final SchemaNode dataNode) {
716         if (dataNode instanceof LeafListSchemaNode) {
717             final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
718             if (leafList.getType() instanceof EnumTypeDefinition) {
719                 return true;
720             }
721         }
722         return false;
723     }
724
725     /**
726      * Converts <code>dataNode</code> to JAVA <code>Type</code>.
727      *
728      * @param dataNode
729      *            contains information about YANG type
730      * @return JAVA <code>Type</code> representation of <code>dataNode</code>
731      */
732     private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode, final SchemaContext schemaContext,
733         Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
734         Type returnType = null;
735         if (dataNode != null) {
736             if (dataNode instanceof LeafSchemaNode) {
737                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
738                 //not using CompatUtils here anymore
739                 final TypeDefinition<?> type = leaf.getType();
740                 returnType = javaTypeForSchemaDefType(type, leaf, null, schemaContext, genTypeDefsContextMap);
741             } else if (dataNode instanceof LeafListSchemaNode) {
742                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
743                 returnType = javaTypeForSchemaDefType(leafList.getType(), leafList, null, schemaContext, genTypeDefsContextMap);
744             }
745         }
746         return returnType;
747     }
748
749     /**
750      * Seeks for identity reference <code>idref</code> the JAVA
751      * <code>type</code>.<br />
752      * <br />
753      *
754      * <i>Example:<br />
755      * If identy which is referenced via <code>idref</code> has name <b>Idn</b>
756      * then returning type is <b>{@code Class<? extends Idn>}</b></i>
757      *
758      * @param idref
759      *            identityref type definition for which JAVA <code>Type</code>
760      *            is sought
761      * @return JAVA <code>Type</code> of the identity which is refrenced through
762      *         <code>idref</code>
763      */
764     private static Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref, final SchemaContext schemaContext) {
765         //TODO: incompatibility with Binding spec v2, get first or only one
766         QName baseIdQName = idref.getIdentities().iterator().next().getQName();
767         Module module = schemaContext.findModuleByNamespaceAndRevision(baseIdQName.getNamespace(),
768                 baseIdQName.getRevision());
769         IdentitySchemaNode identity = null;
770         for (IdentitySchemaNode id : module.getIdentities()) {
771             if (id.getQName().equals(baseIdQName)) {
772                 identity = id;
773             }
774         }
775         Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
776
777         final String basePackageName = BindingMapping.getRootPackageName(module);
778         final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath
779                 (), BindingNamespaceType.Typedef);
780         final String genTypeName = BindingMapping.getClassName(identity.getQName());
781
782         Type baseType = Types.typeForClass(Class.class);
783         Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
784         return Types.parameterizedTypeFor(baseType, paramType);
785     }
786
787     /**
788      * Converts <code>typedef</code> to the generated TO builder.
789      *
790      * @param basePackageName
791      *            string with name of package to which the module belongs
792      * @param typedef
793      *            type definition from which is the generated TO builder created
794      * @return generated TO builder which contains data from
795      *         <code>typedef</code> and <code>basePackageName</code>
796      */
797     private static GeneratedTOBuilderImpl typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef, final String moduleName) {
798
799         final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typedef.getPath
800                 (), BindingNamespaceType.Typedef);
801         final String typeDefTOName = typedef.getQName().getLocalName();
802
803         if ((packageName != null) && (typeDefTOName != null)) {
804             final String genTOName = BindingMapping.getClassName(typeDefTOName);
805             final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName);
806             final String typedefDescription = encodeAngleBrackets(typedef.getDescription());
807
808             newType.setDescription(typedefDescription);
809             newType.setReference(typedef.getReference());
810             newType.setSchemaPath((List) typedef.getPath().getPathFromRoot());
811             newType.setModuleName(moduleName);
812
813             return newType;
814         }
815         return null;
816     }
817
818     private static GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto, final Restrictions r) {
819         GeneratedTOBuilder gtob = new GeneratedTOBuilderImpl(gto.getPackageName(), gto.getName());
820         GeneratedTransferObject parent = gto.getSuperType();
821         if (parent != null) {
822             gtob.setExtendsType(parent);
823         }
824         gtob.setRestrictions(r);
825         for (GeneratedProperty gp : gto.getProperties()) {
826             GeneratedPropertyBuilder gpb = gtob.addProperty(gp.getName());
827             gpb.setValue(gp.getValue());
828             gpb.setReadOnly(gp.isReadOnly());
829             gpb.setAccessModifier(gp.getAccessModifier());
830             gpb.setReturnType(gp.getReturnType());
831             gpb.setFinal(gp.isFinal());
832             gpb.setStatic(gp.isStatic());
833         }
834         return gtob.toInstance();
835     }
836
837     /**
838      * Adds a new property with the name <code>propertyName</code> and with type
839      * <code>type</code> to <code>unonGenTransObject</code>.
840      *
841      * @param unionGenTransObject
842      *            generated TO to which should be property added
843      * @param type
844      *            JAVA <code>type</code> of the property which should be added
845      *            to <code>unionGentransObject</code>
846      * @param propertyName
847      *            string with name of property which should be added to
848      *            <code>unionGentransObject</code>
849      */
850     private static void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type, final String propertyName) {
851         if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
852             final GeneratedPropertyBuilder propBuilder = unionGenTransObject
853                     .addProperty(BindingMapping.getPropertyName(propertyName));
854             propBuilder.setReturnType(type);
855
856             unionGenTransObject.addEqualsIdentity(propBuilder);
857             unionGenTransObject.addHashIdentity(propBuilder);
858             unionGenTransObject.addToStringProperty(propBuilder);
859         }
860     }
861
862     /**
863      * Wraps code which handle case when union subtype is also of the type
864      * <code>UnionType</code>.
865      *
866      * In this case the new generated TO is created for union subtype (recursive
867      * call of method
868      * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, UnionTypeDefinition,
869      * String, SchemaNode, SchemaContext, Map)}
870      * provideGeneratedTOBuilderForUnionTypeDef} and in parent TO builder
871      * <code>parentUnionGenTOBuilder</code> is created property which type is
872      * equal to new generated TO.
873      *
874      * @param parentUnionGenTOBuilder
875      *            generated TO builder to which is the property with the child
876      *            union subtype added
877      * @param basePackageName
878      *            string with the name of the module package
879      * @param unionSubtype
880      *            type definition which represents union subtype
881      * @return list of generated TO builders. The number of the builders can be
882      *         bigger one due to recursive call of
883      *         <code>provideGeneratedTOBuildersForUnionTypeDef</code> method.
884      */
885     private List<GeneratedTOBuilder> resolveUnionSubtypeAsUnion(final GeneratedTOBuilder
886         parentUnionGenTOBuilder, final UnionTypeDefinition unionSubtype, final String basePackageName,
887         final SchemaNode parentNode, final SchemaContext schemaContext, final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
888
889         final String newTOBuilderName = provideAvailableNameForGenTOBuilder(parentUnionGenTOBuilder.getName());
890         final List<GeneratedTOBuilder> subUnionGenTOBUilders = provideGeneratedTOBuildersForUnionTypeDef(
891                 basePackageName, unionSubtype, newTOBuilderName, parentNode, schemaContext, genTypeDefsContextMap);
892
893         final GeneratedPropertyBuilder propertyBuilder;
894         propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingMapping.getPropertyName(newTOBuilderName));
895         propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
896         parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
897         parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
898
899         return subUnionGenTOBUilders;
900     }
901
902     /**
903      * Converts output list of generated TO builders to one TO builder (first
904      * from list) which contains the remaining builders as its enclosing TO.
905      *
906      * @param basePackageName
907      *            string with name of package to which the module belongs
908      * @param typedef
909      *            type definition which should be of type
910      *            <code>UnionTypeDefinition</code>
911      * @param typeDefName
912      *            string with name for generated TO
913      * @return generated TO builder with the list of enclosed generated TO
914      *         builders
915      */
916     private GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
917         final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode, final SchemaContext
918               schemaContext, final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
919
920         final List<GeneratedTOBuilder> builders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
921                 typedef, typeDefName, parentNode, schemaContext, genTypeDefsContextMap);
922         Preconditions.checkState(!builders.isEmpty(), "No GeneratedTOBuilder objects generated from union %s", typedef);
923
924         final GeneratedTOBuilder resultTOBuilder = builders.remove(0);
925         for (GeneratedTOBuilder genTOBuilder : builders) {
926             resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
927         }
928
929         resultTOBuilder.addProperty("value").setReturnType(Types.CHAR_ARRAY);
930         return resultTOBuilder;
931     }
932
933     /**
934      * Wraps code which handle case when union subtype is of the type
935      * <code>ExtendedType</code>.
936      *
937      * If TO for this type already exists it is used for the creation of the
938      * property in <code>parentUnionGenTOBuilder</code>. In other case the base
939      * type is used for the property creation.
940      *
941      * @param parentUnionGenTOBuilder
942      *            generated TO builder in which new property is created
943      * @param unionSubtype
944      *            type definition of the <code>ExtendedType</code> type which
945      *            represents union subtype
946      * @param regularExpressions
947      *            list of strings with the regular expressions
948      * @param parentNode
949      *            parent Schema Node for Extended Subtype
950      *
951      */
952     private static void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder, final
953         TypeDefinition<?> unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode,
954         final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
955
956         final String unionTypeName = unionSubtype.getQName().getLocalName();
957         final Type genTO = findGenTO(unionTypeName, unionSubtype, schemaContext, genTypeDefsContextMap);
958         if (genTO != null) {
959             updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
960         } else {
961             final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
962             if (unionTypeName.equals(baseType.getQName().getLocalName())) {
963                 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
964                         parentNode);
965                 if (javaType != null) {
966                     updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
967                 }
968             }
969             if (baseType instanceof StringTypeDefinition) {
970                 regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
971             }
972         }
973     }
974
975     /**
976      * Returns string which contains the same value as <code>name</code> but
977      * integer suffix is incremented by one. If <code>name</code> contains no
978      * number suffix then number 1 is added.
979      *
980      * @param name
981      *            string with name of augmented node
982      * @return string with the number suffix incremented by one (or 1 is added)
983      */
984     private static String provideAvailableNameForGenTOBuilder(final String name) {
985         Matcher mtch = NUMBERS_PATTERN.matcher(name);
986         if (mtch.find()) {
987             final int newSuffix = Integer.valueOf(name.substring(mtch.start())) + 1;
988             return name.substring(0, mtch.start()) + newSuffix;
989         } else {
990             return name + 1;
991         }
992     }
993
994     /**
995      * Searches for generated TO for <code>searchedTypeDef</code> type
996      * definition in {@link #genTypeDefsContextMap genTypeDefsContextMap}
997      *
998      * @param searchedTypeName
999      *            string with name of <code>searchedTypeDef</code>
1000      * @return generated TO for <code>searchedTypeDef</code> or
1001      *         <code>null</code> it it doesn't exist
1002      */
1003     private static Type findGenTO(final String searchedTypeName, final SchemaNode parentNode,
1004         final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
1005
1006         final Module typeModule = findParentModule(schemaContext, parentNode);
1007         if (typeModule != null && typeModule.getName() != null) {
1008             final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(typeModule.getName());
1009             final Map<String, Type> genTOs = modulesByDate.get(typeModule.getRevision());
1010             if (genTOs != null) {
1011                 return genTOs.get(searchedTypeName);
1012             }
1013         }
1014         return null;
1015     }
1016
1017     /**
1018      * Adds enumeration to <code>typeBuilder</code>. The enumeration data are
1019      * taken from <code>enumTypeDef</code>.
1020      *
1021      * @param enumTypeDef
1022      *            enumeration type definition is source of enumeration data for
1023      *            <code>typeBuilder</code>
1024      * @param enumName
1025      *            string with the name of enumeration
1026      * @param typeBuilder
1027      *            generated type builder to which is enumeration added
1028      * @return enumeration type which contains enumeration data form
1029      *         <code>enumTypeDef</code>
1030      * @throws IllegalArgumentException
1031      *             <ul>
1032      *             <li>if <code>enumTypeDef</code> equals null</li>
1033      *             <li>if enum values of <code>enumTypeDef</code> equal null</li>
1034      *             <li>if Q name of <code>enumTypeDef</code> equal null</li>
1035      *             <li>if name of <code>enumTypeDef</code> equal null</li>
1036      *             <li>if name of <code>typeBuilder</code> equal null</li>
1037      *             </ul>
1038      *
1039      */
1040     private static Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef, final String enumName, final GeneratedTypeBuilderBase<?> typeBuilder) {
1041         Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
1042         Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
1043                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
1044         Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
1045
1046         final String enumerationName = BindingMapping.getClassName(enumName);
1047
1048         final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
1049         final String enumTypedefDescription = encodeAngleBrackets(enumTypeDef.getDescription());
1050         enumBuilder.setDescription(enumTypedefDescription);
1051         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
1052         return enumBuilder.toInstance(enumBuilder);
1053     }
1054
1055     private static boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode,
1056                                                   final SchemaContext schemaContext) {
1057         final SchemaNode leafRefValueNode;
1058         final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
1059         final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(leafRefXPath.toString()
1060                 .replaceAll("\\[(.*?)\\]", ""), leafRefXPath.isAbsolute());
1061
1062         ///// skip leafrefs in augments - they're checked once augments are resolved
1063         final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
1064         boolean isAugmenting = false;
1065         DataNodeContainer current = null;
1066         DataSchemaNode dataChildByName;
1067
1068         while (iterator.hasNext() && !isAugmenting) {
1069             final QName next = iterator.next();
1070             if (current == null) {
1071                 dataChildByName = schemaContext.getDataChildByName(next);
1072             } else {
1073                 dataChildByName = current.getDataChildByName(next);
1074             }
1075             if (dataChildByName != null) {
1076                 isAugmenting = dataChildByName.isAugmenting();
1077             } else {
1078                 return false;
1079             }
1080             if (dataChildByName instanceof DataNodeContainer) {
1081                 current = (DataNodeContainer) dataChildByName;
1082             }
1083         }
1084         if (isAugmenting) {
1085             return false;
1086         }
1087         /////
1088
1089         Module parentModule = getParentModule(parentNode, schemaContext);
1090         if (!leafRefStrippedXPath.isAbsolute()) {
1091             leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
1092                     parentNode, leafRefStrippedXPath);
1093         } else {
1094             leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath);
1095         }
1096         return (leafRefValueNode != null) && leafRefValueNode.equals(parentNode);
1097     }
1098
1099
1100 }