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