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