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