4163273d73b99a80efa8907f54d3cd3911c216c4
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / yang / types / TypeProviderImpl.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.sal.binding.yang.types;
9
10 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
11 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
12 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
13 import com.google.common.base.Preconditions;
14 import com.google.common.base.Strings;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.collect.Sets;
17 import com.google.common.io.BaseEncoding;
18 import java.io.Serializable;
19 import java.math.BigDecimal;
20 import java.math.BigInteger;
21 import java.net.URI;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Comparator;
26 import java.util.Date;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.TreeMap;
33 import java.util.regex.Matcher;
34 import java.util.regex.Pattern;
35 import org.apache.commons.lang3.StringEscapeUtils;
36 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
37 import org.opendaylight.yangtools.binding.generator.util.TypeConstants;
38 import org.opendaylight.yangtools.binding.generator.util.Types;
39 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.EnumerationBuilderImpl;
40 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
41 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
42 import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
43 import org.opendaylight.yangtools.sal.binding.model.api.AccessModifier;
44 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
45 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration;
46 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty;
47 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject;
48 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions;
49 import org.opendaylight.yangtools.sal.binding.model.api.Type;
50 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder;
51 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
52 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
53 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
54 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
55 import org.opendaylight.yangtools.yang.binding.BindingMapping;
56 import org.opendaylight.yangtools.yang.common.QName;
57 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
58 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
61 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
62 import org.opendaylight.yangtools.yang.model.api.Module;
63 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
64 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
65 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
66 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
67 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
68 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
69 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
70 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
71 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
72 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
73 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
75 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
77 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
78 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
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.EnumerationType;
82 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
83 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
84 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
85 import org.opendaylight.yangtools.yang.model.util.StringType;
86 import org.opendaylight.yangtools.yang.model.util.UnionType;
87 import org.opendaylight.yangtools.yang.model.util.type.BaseTypes;
88 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91
92 public final class TypeProviderImpl implements TypeProvider {
93     private static final Logger LOG = LoggerFactory.getLogger(TypeProviderImpl.class);
94     private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z");
95
96     /**
97      * Contains the schema data red from YANG files.
98      */
99     private final SchemaContext schemaContext;
100
101     /**
102      * Map<moduleName, Map<moduleDate, Map<typeName, type>>>
103      */
104     private final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap;
105
106     /**
107      * The map which maps schema paths to JAVA <code>Type</code>.
108      */
109     private final Map<SchemaPath, Type> referencedTypes;
110     private final Map<Module, Set<Type>> additionalTypes;
111
112     /**
113      * Creates new instance of class <code>TypeProviderImpl</code>.
114      *
115      * @param schemaContext
116      *            contains the schema data red from YANG files
117      * @throws IllegalArgumentException
118      *             if <code>schemaContext</code> equal null.
119      */
120     public TypeProviderImpl(final SchemaContext schemaContext) {
121         Preconditions.checkArgument(schemaContext != null, "Schema Context cannot be null!");
122
123         this.schemaContext = schemaContext;
124         this.genTypeDefsContextMap = new HashMap<>();
125         this.referencedTypes = new HashMap<>();
126         this.additionalTypes = new HashMap<>();
127         resolveTypeDefsFromContext();
128     }
129
130     /**
131      * Puts <code>refType</code> to map with key <code>refTypePath</code>
132      *
133      * @param refTypePath
134      *            schema path used as the map key
135      * @param refType
136      *            type which represents the map value
137      * @throws IllegalArgumentException
138      *             <ul>
139      *             <li>if <code>refTypePath</code> equal null</li>
140      *             <li>if <code>refType</code> equal null</li>
141      *             </ul>
142      *
143      */
144     public void putReferencedType(final SchemaPath refTypePath, final Type refType) {
145         Preconditions.checkArgument(refTypePath != null,
146                 "Path reference of Enumeration Type Definition cannot be NULL!");
147         Preconditions.checkArgument(refType != null, "Reference to Enumeration Type cannot be NULL!");
148         referencedTypes.put(refTypePath, refType);
149     }
150
151     public Map<Module, Set<Type>> getAdditionalTypes() {
152         return additionalTypes;
153     }
154
155     /**
156      *
157      * Converts basic YANG type <code>type</code> to JAVA <code>Type</code>.
158      *
159      * @param type
160      *            string with YANG name of type
161      * @return JAVA <code>Type</code> for YANG type <code>type</code>
162      * @see TypeProvider#javaTypeForYangType(String)
163      */
164     @Override
165     @Deprecated
166     public Type javaTypeForYangType(final String type) {
167         return BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForYangType(type);
168     }
169
170     @Override
171     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
172         return javaTypeForSchemaDefinitionType(typeDefinition, parentNode, null);
173     }
174
175     /**
176      * Converts schema definition type <code>typeDefinition</code> to JAVA
177      * <code>Type</code>
178      *
179      * @param typeDefinition
180      *            type definition which is converted to JAVA type
181      * @throws IllegalArgumentException
182      *             <ul>
183      *             <li>if <code>typeDefinition</code> equal null</li>
184      *             <li>if Qname of <code>typeDefinition</code> equal null</li>
185      *             <li>if name of <code>typeDefinition</code> equal null</li>
186      *             </ul>
187      */
188     @Override
189     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
190             final Restrictions r) {
191         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
192         Preconditions.checkArgument(typeDefinition.getQName() != null,
193                 "Type Definition cannot have non specified QName (QName cannot be NULL!)");
194         String typedefName = typeDefinition.getQName().getLocalName();
195         Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
196
197         // Deal with leafrefs/identityrefs first
198         Type returnType = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode);
199         if (returnType != null) {
200             return returnType;
201         }
202
203         if (typeDefinition.getBaseType() == null) {
204             // Now deal with base types
205             returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForYangType(typeDefinition.getQName()
206                 .getLocalName());
207             if (returnType == null) {
208                 LOG.debug("Failed to resolve Java type for {}", typeDefinition);
209             }
210
211             // FIXME: what about base types with restrictions?
212             return returnType;
213         }
214
215         returnType = javaTypeForExtendedType(typeDefinition);
216         if (r != null && returnType instanceof GeneratedTransferObject) {
217             GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
218             Module module = findParentModule(schemaContext, parentNode);
219             String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
220             String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName,
221                 typeDefinition.getPath());
222             String genTOName = BindingMapping.getClassName(typedefName);
223             String name = packageName + "." + genTOName;
224             if (!(returnType.getFullyQualifiedName().equals(name))) {
225                 returnType = shadedTOWithRestrictions(gto, r);
226             }
227         }
228         return returnType;
229     }
230
231     private static GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto, final Restrictions r) {
232         GeneratedTOBuilder gtob = new GeneratedTOBuilderImpl(gto.getPackageName(), gto.getName());
233         GeneratedTransferObject parent = gto.getSuperType();
234         if (parent != null) {
235             gtob.setExtendsType(parent);
236         }
237         gtob.setRestrictions(r);
238         for (GeneratedProperty gp : gto.getProperties()) {
239             GeneratedPropertyBuilder gpb = gtob.addProperty(gp.getName());
240             gpb.setValue(gp.getValue());
241             gpb.setReadOnly(gp.isReadOnly());
242             gpb.setAccessModifier(gp.getAccessModifier());
243             gpb.setReturnType(gp.getReturnType());
244             gpb.setFinal(gp.isFinal());
245             gpb.setStatic(gp.isStatic());
246         }
247         return gtob.toInstance();
248     }
249
250     private boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode) {
251         final SchemaNode leafRefValueNode;
252         final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
253         final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(leafRefXPath.toString()
254                 .replaceAll("\\[(.*?)\\]", ""), leafRefXPath.isAbsolute());
255
256         ///// skip leafrefs in augments - they're checked once augments are resolved
257         final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
258         boolean isAugmenting = false;
259         DataNodeContainer current = null;
260         DataSchemaNode dataChildByName;
261
262         while (iterator.hasNext() && !isAugmenting) {
263             final QName next = iterator.next();
264             if (current == null) {
265                 dataChildByName = schemaContext.getDataChildByName(next);
266             } else {
267                 dataChildByName = current.getDataChildByName(next);
268             }
269             if (dataChildByName != null) {
270                 isAugmenting = dataChildByName.isAugmenting();
271             } else {
272                 return false;
273             }
274             if (dataChildByName instanceof DataNodeContainer) {
275                 current = (DataNodeContainer) dataChildByName;
276             }
277         }
278         if (isAugmenting) {
279             return false;
280         }
281         /////
282
283         Module parentModule = getParentModule(parentNode);
284         if (!leafRefStrippedXPath.isAbsolute()) {
285             leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
286                     parentNode, leafRefStrippedXPath);
287         } else {
288             leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath);
289         }
290         return (leafRefValueNode != null) ? leafRefValueNode.equals(parentNode) : false;
291     }
292
293     /**
294      * Returns JAVA <code>Type</code> for instances of the type
295      * <code>LeafrefTypeDefinition</code> or
296      * <code>IdentityrefTypeDefinition</code>.
297      *
298      * @param typeDefinition
299      *            type definition which is converted to JAVA <code>Type</code>
300      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
301      */
302     private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
303         if (typeDefinition instanceof LeafrefTypeDefinition) {
304             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
305             if (isLeafRefSelfReference(leafref, parentNode)) {
306                 throw new YangValidationException("Leafref " + leafref.toString() + " is referencing itself, incoming" +
307                         " StackOverFlowError detected.");
308             }
309             return provideTypeForLeafref(leafref, parentNode);
310         } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
311             final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
312             return provideTypeForIdentityref(idref);
313         } else {
314             return null;
315         }
316     }
317
318     /**
319      * Returns JAVA <code>Type</code> for instances of the type
320      * <code>ExtendedType</code>.
321      *
322      * @param typeDefinition
323      *            type definition which is converted to JAVA <code>Type</code>
324      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
325      */
326     private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition) {
327         final String typedefName = typeDefinition.getQName().getLocalName();
328         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
329         Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition);
330         if (returnType == null) {
331             if (baseTypeDef instanceof EnumTypeDefinition) {
332                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
333                 returnType = provideTypeForEnum(enumTypeDef, typedefName, typeDefinition);
334             } else {
335                 final Module module = findParentModule(schemaContext, typeDefinition);
336                 Restrictions r = BindingGeneratorUtil.getRestrictions(typeDefinition);
337                 if (module != null) {
338                     final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
339                     final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
340                     if (genTOs != null) {
341                         returnType = genTOs.get(typedefName);
342                     }
343                     if (returnType == null) {
344                         returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
345                                 baseTypeDef, typeDefinition, r);
346                     }
347                 }
348             }
349         }
350         return returnType;
351     }
352
353     /**
354      * Seeks for identity reference <code>idref</code> the JAVA
355      * <code>type</code>.<br />
356      * <br />
357      *
358      * <i>Example:<br />
359      * If identy which is referenced via <code>idref</code> has name <b>Idn</b>
360      * then returning type is <b>{@code Class<? extends Idn>}</b></i>
361      *
362      * @param idref
363      *            identityref type definition for which JAVA <code>Type</code>
364      *            is sought
365      * @return JAVA <code>Type</code> of the identity which is refrenced through
366      *         <code>idref</code>
367      */
368     private Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref) {
369         QName baseIdQName = idref.getIdentity().getQName();
370         Module module = schemaContext.findModuleByNamespaceAndRevision(baseIdQName.getNamespace(),
371                 baseIdQName.getRevision());
372         IdentitySchemaNode identity = null;
373         for (IdentitySchemaNode id : module.getIdentities()) {
374             if (id.getQName().equals(baseIdQName)) {
375                 identity = id;
376             }
377         }
378         Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
379
380         final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
381         final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath());
382         final String genTypeName = BindingMapping.getClassName(identity.getQName());
383
384         Type baseType = Types.typeForClass(Class.class);
385         Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
386         return Types.parameterizedTypeFor(baseType, paramType);
387     }
388
389     /**
390      * Converts <code>typeDefinition</code> to concrete JAVA <code>Type</code>.
391      *
392      * @param typeDefinition
393      *            type definition which should be converted to JAVA
394      *            <code>Type</code>
395      * @return JAVA <code>Type</code> which represents
396      *         <code>typeDefinition</code>
397      * @throws IllegalArgumentException
398      *             <ul>
399      *             <li>if <code>typeDefinition</code> equal null</li>
400      *             <li>if Q name of <code>typeDefinition</code></li>
401      *             <li>if name of <code>typeDefinition</code></li>
402      *             </ul>
403      */
404     public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition,
405             final SchemaNode parentNode) {
406         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
407         if (typeDefinition.getQName() == null) {
408             throw new IllegalArgumentException(
409                     "Type Definition cannot have non specified QName (QName cannot be NULL!)");
410         }
411         Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
412                 "Type Definitions Local Name cannot be NULL!");
413
414         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
415         if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
416             final Module module = findParentModule(schemaContext, parentNode);
417
418             if (module != null) {
419                 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
420                 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
421                 if (genTOs != null) {
422                     return genTOs.get(typeDefinition.getQName().getLocalName());
423                 }
424             }
425         }
426         return null;
427     }
428
429     /**
430      * Gets base type definition for <code>extendTypeDef</code>. The method is
431      * recursively called until non <code>ExtendedType</code> type is found.
432      *
433      * @param extendTypeDef
434      *            type definition for which is the base type definition sought
435      * @return type definition which is base type for <code>extendTypeDef</code>
436      * @throws IllegalArgumentException
437      *             if <code>extendTypeDef</code> equal null
438      */
439     private static TypeDefinition<?> baseTypeDefForExtendedType(final TypeDefinition<?> extendTypeDef) {
440         Preconditions.checkArgument(extendTypeDef != null, "Type Definition reference cannot be NULL!");
441
442         TypeDefinition<?> ret = extendTypeDef;
443         while (ret.getBaseType() != null) {
444             ret = ret.getBaseType();
445         }
446
447         return ret;
448     }
449
450     /**
451      * Converts <code>leafrefType</code> to JAVA <code>Type</code>.
452      *
453      * The path of <code>leafrefType</code> is followed to find referenced node
454      * and its <code>Type</code> is returned.
455      *
456      * @param leafrefType
457      *            leafref type definition for which is the type sought
458      * @return JAVA <code>Type</code> of data schema node which is referenced in
459      *         <code>leafrefType</code>
460      * @throws IllegalArgumentException
461      *             <ul>
462      *             <li>if <code>leafrefType</code> equal null</li>
463      *             <li>if path statement of <code>leafrefType</code> equal null</li>
464      *             </ul>
465      *
466      */
467     public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode) {
468         Type returnType = null;
469         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
470
471         Preconditions.checkArgument(leafrefType.getPathStatement() != null,
472                 "The Path Statement for Leafref Type Definition cannot be NULL!");
473
474         final RevisionAwareXPath xpath = leafrefType.getPathStatement();
475         final String strXPath = xpath.toString();
476
477         if (strXPath != null) {
478             if (strXPath.indexOf('[') == -1) {
479                 final Module module = findParentModule(schemaContext, parentNode);
480                 if (module != null) {
481                     final SchemaNode dataNode;
482                     if (xpath.isAbsolute()) {
483                         dataNode = findDataSchemaNode(schemaContext, module, xpath);
484                     } else {
485                         dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
486                     }
487
488                     if (leafContainsEnumDefinition(dataNode)) {
489                         returnType = referencedTypes.get(dataNode.getPath());
490                     } else if (leafListContainsEnumDefinition(dataNode)) {
491                         returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
492                     } else {
493                         returnType = resolveTypeFromDataSchemaNode(dataNode);
494                     }
495                 }
496             } else {
497                 returnType = Types.typeForClass(Object.class);
498             }
499         }
500         if (returnType == null) {
501             throw new IllegalArgumentException("Failed to find leafref target: " + strXPath);
502         }
503         return returnType;
504     }
505
506     /**
507      * Checks if <code>dataNode</code> is <code>LeafSchemaNode</code> and if it
508      * so then checks if it is of type <code>EnumTypeDefinition</code>.
509      *
510      * @param dataNode
511      *            data schema node for which is checked if it is leaf and if it
512      *            is of enum type
513      * @return boolean value
514      *         <ul>
515      *         <li>true - if <code>dataNode</code> is leaf of type enumeration</li>
516      *         <li>false - other cases</li>
517      *         </ul>
518      */
519     private static boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
520         if (dataNode instanceof LeafSchemaNode) {
521             final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
522             if (leaf.getType() instanceof EnumTypeDefinition) {
523                 return true;
524             }
525         }
526         return false;
527     }
528
529     /**
530      * Checks if <code>dataNode</code> is <code>LeafListSchemaNode</code> and if
531      * it so then checks if it is of type <code>EnumTypeDefinition</code>.
532      *
533      * @param dataNode
534      *            data schema node for which is checked if it is leaflist and if
535      *            it is of enum type
536      * @return boolean value
537      *         <ul>
538      *         <li>true - if <code>dataNode</code> is leaflist of type
539      *         enumeration</li>
540      *         <li>false - other cases</li>
541      *         </ul>
542      */
543     private static boolean leafListContainsEnumDefinition(final SchemaNode dataNode) {
544         if (dataNode instanceof LeafListSchemaNode) {
545             final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
546             if (leafList.getType() instanceof EnumTypeDefinition) {
547                 return true;
548             }
549         }
550         return false;
551     }
552
553     /**
554      * Converts <code>enumTypeDef</code> to
555      * {@link org.opendaylight.yangtools.sal.binding.model.api.Enumeration
556      * enumeration}.
557      *
558      * @param enumTypeDef
559      *            enumeration type definition which is converted to enumeration
560      * @param enumName
561      *            string with name which is used as the enumeration name
562      * @return enumeration type which is built with data (name, enum values)
563      *         from <code>enumTypeDef</code>
564      * @throws IllegalArgumentException
565      *             <ul>
566      *             <li>if <code>enumTypeDef</code> equals null</li>
567      *             <li>if enum values of <code>enumTypeDef</code> equal null</li>
568      *             <li>if Q name of <code>enumTypeDef</code> equal null</li>
569      *             <li>if name of <code>enumTypeDef</code> equal null</li>
570      *             </ul>
571      */
572     private Enumeration provideTypeForEnum(final EnumTypeDefinition enumTypeDef, final String enumName,
573             final SchemaNode parentNode) {
574         Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
575         Preconditions.checkArgument(enumTypeDef.getValues() != null,
576                 "EnumTypeDefinition MUST contain at least ONE value definition!");
577         Preconditions.checkArgument(enumTypeDef.getQName() != null, "EnumTypeDefinition MUST contain NON-NULL QName!");
578         Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
579                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
580
581         final String enumerationName = BindingMapping.getClassName(enumName);
582
583         Module module = findParentModule(schemaContext, parentNode);
584         final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
585
586         final EnumerationBuilderImpl enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
587         enumBuilder.setDescription(enumTypeDef.getDescription());
588         enumBuilder.setReference(enumTypeDef.getReference());
589         enumBuilder.setModuleName(module.getName());
590         enumBuilder.setSchemaPath(enumTypeDef.getPath().getPathFromRoot());
591         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
592         return enumBuilder.toInstance(null);
593     }
594
595     /**
596      * Adds enumeration to <code>typeBuilder</code>. The enumeration data are
597      * taken from <code>enumTypeDef</code>.
598      *
599      * @param enumTypeDef
600      *            enumeration type definition is source of enumeration data for
601      *            <code>typeBuilder</code>
602      * @param enumName
603      *            string with the name of enumeration
604      * @param typeBuilder
605      *            generated type builder to which is enumeration added
606      * @return enumeration type which contains enumeration data form
607      *         <code>enumTypeDef</code>
608      * @throws IllegalArgumentException
609      *             <ul>
610      *             <li>if <code>enumTypeDef</code> equals null</li>
611      *             <li>if enum values of <code>enumTypeDef</code> equal null</li>
612      *             <li>if Q name of <code>enumTypeDef</code> equal null</li>
613      *             <li>if name of <code>enumTypeDef</code> equal null</li>
614      *             <li>if name of <code>typeBuilder</code> equal null</li>
615      *             </ul>
616      *
617      */
618     private static Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef, final String enumName,
619             final GeneratedTypeBuilderBase<?> typeBuilder) {
620         Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
621         Preconditions.checkArgument(enumTypeDef.getValues() != null,
622                 "EnumTypeDefinition MUST contain at least ONE value definition!");
623         Preconditions.checkArgument(enumTypeDef.getQName() != null, "EnumTypeDefinition MUST contain NON-NULL QName!");
624         Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
625                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
626         Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
627
628         final String enumerationName = BindingMapping.getClassName(enumName);
629
630         final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
631         enumBuilder.setDescription(enumTypeDef.getDescription());
632         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
633         return enumBuilder.toInstance(enumBuilder);
634     }
635
636     /**
637      * Converts <code>dataNode</code> to JAVA <code>Type</code>.
638      *
639      * @param dataNode
640      *            contains information about YANG type
641      * @return JAVA <code>Type</code> representation of <code>dataNode</code>
642      */
643     private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode) {
644         Type returnType = null;
645         if (dataNode != null) {
646             if (dataNode instanceof LeafSchemaNode) {
647                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
648                 returnType = javaTypeForSchemaDefinitionType(leaf.getType(), leaf);
649             } else if (dataNode instanceof LeafListSchemaNode) {
650                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
651                 returnType = javaTypeForSchemaDefinitionType(leafList.getType(), leafList);
652             }
653         }
654         return returnType;
655     }
656
657     /**
658      * Passes through all modules and through all its type definitions and
659      * convert it to generated types.
660      *
661      * The modules are firstly sorted by mutual dependencies. The modules are
662      * sequentially passed. All type definitions of a module are at the
663      * beginning sorted so that type definition with less amount of references
664      * to other type definition are processed first.<br />
665      * For each module is created mapping record in the map
666      * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap}
667      * which map current module name to the map which maps type names to
668      * returned types (generated types).
669      *
670      */
671     private void resolveTypeDefsFromContext() {
672         final Set<Module> modules = schemaContext.getModules();
673         Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
674         final Module[] modulesArray = new Module[modules.size()];
675         int i = 0;
676         for (Module modul : modules) {
677             modulesArray[i++] = modul;
678         }
679         final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
680                 .sort(modulesArray);
681
682         for (final Module module : modulesSortedByDependency) {
683             Map<Date, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
684             if (dateTypeMap == null) {
685                 dateTypeMap = new HashMap<>();
686             }
687             dateTypeMap.put(module.getRevision(), Collections.<String, Type>emptyMap());
688             genTypeDefsContextMap.put(module.getName(), dateTypeMap);
689         }
690
691         for (final Module module : modulesSortedByDependency) {
692             if (module != null) {
693                 final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
694                 if (basePackageName != null) {
695                     final List<TypeDefinition<?>> typeDefinitions = TypedefResolver.getAllTypedefs(module);
696                     final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
697                     if (listTypeDefinitions != null) {
698                         for (final TypeDefinition<?> typedef : listTypeDefinitions) {
699                             typedefToGeneratedType(basePackageName, module, typedef);
700                         }
701                     }
702                 }
703             }
704         }
705     }
706
707     /**
708      *
709      * @param basePackageName
710      *            string with name of package to which the module belongs
711      * @param module
712      *            string with the name of the module for to which the
713      *            <code>typedef</code> belongs
714      * @param typedef
715      *            type definition of the node for which should be creted JAVA
716      *            <code>Type</code> (usually generated TO)
717      * @return JAVA <code>Type</code> representation of <code>typedef</code> or
718      *         <code>null</code> value if <code>basePackageName</code> or
719      *         <code>modulName</code> or <code>typedef</code> or Q name of
720      *         <code>typedef</code> equals <code>null</code>
721      */
722     private Type typedefToGeneratedType(final String basePackageName, final Module module,
723             final TypeDefinition<?> typedef) {
724         final String moduleName = module.getName();
725         final Date moduleRevision = module.getRevision();
726         if ((basePackageName != null) && (moduleName != null) && (typedef != null) && (typedef.getQName() != null)) {
727             final String typedefName = typedef.getQName().getLocalName();
728             final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
729             if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
730                     && !(innerTypeDefinition instanceof IdentityrefTypeDefinition)) {
731                 Type returnType = null;
732                 if (innerTypeDefinition.getBaseType() != null) {
733                     returnType = provideGeneratedTOFromExtendedType(typedef, innerTypeDefinition, basePackageName,
734                         module.getName());
735                 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
736                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
737                             (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef);
738                     genTOBuilder.setTypedef(true);
739                     genTOBuilder.setIsUnion(true);
740                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
741                     makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
742                     returnType = genTOBuilder.toInstance();
743                     // union builder
744                     GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
745                             genTOBuilder.getName() + "Builder");
746                     unionBuilder.setIsUnionBuilder(true);
747                     MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
748                     method.setReturnType(returnType);
749                     method.addParameter(Types.STRING, "defaultValue");
750                     method.setAccessModifier(AccessModifier.PUBLIC);
751                     method.setStatic(true);
752                     Set<Type> types = additionalTypes.get(module);
753                     if (types == null) {
754                         types = Sets.<Type> newHashSet(unionBuilder.toInstance());
755                         additionalTypes.put(module, types);
756                     } else {
757                         types.add(unionBuilder.toInstance());
758                     }
759                 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
760                     // enums are automatically Serializable
761                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
762                     // TODO units for typedef enum
763                     returnType = provideTypeForEnum(enumTypeDef, typedefName, typedef);
764                 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
765                     final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
766                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForBitsTypeDefinition(
767                             basePackageName, bitsTypeDefinition, typedefName, module.getName());
768                     genTOBuilder.setTypedef(true);
769                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
770                     makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
771                     returnType = genTOBuilder.toInstance();
772                 } else {
773                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
774                             innerTypeDefinition, typedef);
775                     returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType, module.getName());
776                 }
777                 if (returnType != null) {
778                     final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(moduleName);
779                     Map<String, Type> typeMap = modulesByDate.get(moduleRevision);
780                     if (typeMap != null) {
781                         if (typeMap.isEmpty()) {
782                             typeMap = new HashMap<>(4);
783                             modulesByDate.put(moduleRevision, typeMap);
784                         }
785                         typeMap.put(typedefName, returnType);
786                     }
787                     return returnType;
788                 }
789             }
790         }
791         return null;
792     }
793
794     /**
795      * Wraps base YANG type to generated TO.
796      *
797      * @param basePackageName
798      *            string with name of package to which the module belongs
799      * @param typedef
800      *            type definition which is converted to the TO
801      * @param javaType
802      *            JAVA <code>Type</code> to which is <code>typedef</code> mapped
803      * @return generated transfer object which represent<code>javaType</code>
804      */
805     private static GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
806             final Type javaType, final String moduleName) {
807         Preconditions.checkNotNull(javaType, "javaType cannot be null");
808         final String propertyName = "value";
809
810         final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef, moduleName);
811         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
812         final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
813         genPropBuilder.setReturnType(javaType);
814         genTOBuilder.addEqualsIdentity(genPropBuilder);
815         genTOBuilder.addHashIdentity(genPropBuilder);
816         genTOBuilder.addToStringProperty(genPropBuilder);
817         if (javaType instanceof ConcreteType && "String".equals(javaType.getName()) && typedef.getBaseType() != null) {
818             final List<String> regExps = resolveRegExpressionsFromTypedef(typedef);
819             addStringRegExAsConstant(genTOBuilder, regExps);
820         }
821         addUnitsToGenTO(genTOBuilder, typedef.getUnits());
822         genTOBuilder.setTypedef(true);
823         makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
824         return genTOBuilder.toInstance();
825     }
826
827     /**
828      * Converts output list of generated TO builders to one TO builder (first
829      * from list) which contains the remaining builders as its enclosing TO.
830      *
831      * @param basePackageName
832      *            string with name of package to which the module belongs
833      * @param typedef
834      *            type definition which should be of type
835      *            <code>UnionTypeDefinition</code>
836      * @param typeDefName
837      *            string with name for generated TO
838      * @return generated TO builder with the list of enclosed generated TO
839      *         builders
840      */
841     public GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
842             final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode) {
843         final List<GeneratedTOBuilder> genTOBuilders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
844                 typedef, typeDefName, parentNode);
845         GeneratedTOBuilder resultTOBuilder = null;
846         if (genTOBuilders.isEmpty()) {
847             throw new IllegalStateException("No GeneratedTOBuilder objects generated from union " + typedef);
848         }
849
850         resultTOBuilder = genTOBuilders.remove(0);
851         for (GeneratedTOBuilder genTOBuilder : genTOBuilders) {
852             resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
853         }
854
855         final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value");
856         genPropBuilder.setReturnType(Types.CHAR_ARRAY);
857         resultTOBuilder.addEqualsIdentity(genPropBuilder);
858         resultTOBuilder.addHashIdentity(genPropBuilder);
859         resultTOBuilder.addToStringProperty(genPropBuilder);
860
861         return resultTOBuilder;
862     }
863
864     /**
865      * Converts <code>typedef</code> to generated TO with
866      * <code>typeDefName</code>. Every union type from <code>typedef</code> is
867      * added to generated TO builder as property.
868      *
869      * @param basePackageName
870      *            string with name of package to which the module belongs
871      * @param typedef
872      *            type definition which should be of type
873      *            <code>UnionTypeDefinition</code>
874      * @param typeDefName
875      *            string with name for generated TO
876      * @return generated TO builder which represents <code>typedef</code>
877      * @throws NullPointerException
878      *             <ul>
879      *             <li>if <code>basePackageName</code> is null</li>
880      *             <li>if <code>typedef</code> is null</li>
881      *             <li>if Qname of <code>typedef</code> is null</li>
882      *             </ul>
883      */
884     public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
885             final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode) {
886         Preconditions.checkNotNull(basePackageName, "Base Package Name cannot be NULL!");
887         Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
888         Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
889
890         final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
891         final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
892         final Module module = findParentModule(schemaContext, parentNode);
893
894         final GeneratedTOBuilderImpl unionGenTOBuilder;
895         if (typeDefName != null && !typeDefName.isEmpty()) {
896             final String typeName = BindingMapping.getClassName(typeDefName);
897             unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
898             unionGenTOBuilder.setDescription(typedef.getDescription());
899             unionGenTOBuilder.setReference(typedef.getReference());
900             unionGenTOBuilder.setSchemaPath(typedef.getPath().getPathFromRoot());
901             unionGenTOBuilder.setModuleName(module.getName());
902         } else {
903             unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef, module.getName());
904         }
905
906         generatedTOBuilders.add(unionGenTOBuilder);
907         unionGenTOBuilder.setIsUnion(true);
908         final List<String> regularExpressions = new ArrayList<String>();
909         for (final TypeDefinition<?> unionType : unionTypes) {
910             final String unionTypeName = unionType.getQName().getLocalName();
911             if (unionType.getBaseType() != null) {
912                 resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, regularExpressions,
913                         parentNode);
914             } else if (unionType instanceof UnionTypeDefinition) {
915                 generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionTypeDefinition) unionType,
916                     basePackageName, parentNode));
917             } else if (unionType instanceof EnumTypeDefinition) {
918                 final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
919                         unionTypeName, unionGenTOBuilder);
920                 updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
921             } else {
922                 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(unionType,
923                         parentNode);
924                 updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
925             }
926         }
927         if (!regularExpressions.isEmpty()) {
928             addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
929         }
930
931         storeGenTO(typedef, unionGenTOBuilder, parentNode);
932
933         return generatedTOBuilders;
934     }
935
936     /**
937      * Wraps code which handle case when union subtype is also of the type
938      * <code>UnionType</code>.
939      *
940      * In this case the new generated TO is created for union subtype (recursive
941      * call of method
942      * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, UnionTypeDefinition,
943      * String, SchemaNode)}
944      * provideGeneratedTOBuilderForUnionTypeDef} and in parent TO builder
945      * <code>parentUnionGenTOBuilder</code> is created property which type is
946      * equal to new generated TO.
947      *
948      * @param parentUnionGenTOBuilder
949      *            generated TO builder to which is the property with the child
950      *            union subtype added
951      * @param basePackageName
952      *            string with the name of the module package
953      * @param unionSubtype
954      *            type definition which represents union subtype
955      * @return list of generated TO builders. The number of the builders can be
956      *         bigger one due to recursive call of
957      *         <code>provideGeneratedTOBuildersForUnionTypeDef</code> method.
958      */
959     private List<GeneratedTOBuilder> resolveUnionSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
960             final UnionTypeDefinition unionSubtype, final String basePackageName, final SchemaNode parentNode) {
961         final String newTOBuilderName = provideAvailableNameForGenTOBuilder(parentUnionGenTOBuilder.getName());
962         final List<GeneratedTOBuilder> subUnionGenTOBUilders = provideGeneratedTOBuildersForUnionTypeDef(
963                 basePackageName, unionSubtype, newTOBuilderName, parentNode);
964
965         final GeneratedPropertyBuilder propertyBuilder;
966         propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingMapping.getPropertyName(newTOBuilderName));
967         propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
968         parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
969         parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
970
971         return subUnionGenTOBUilders;
972     }
973
974     /**
975      * Wraps code which handle case when union subtype is of the type
976      * <code>ExtendedType</code>.
977      *
978      * If TO for this type already exists it is used for the creation of the
979      * property in <code>parentUnionGenTOBuilder</code>. In other case the base
980      * type is used for the property creation.
981      *
982      * @param parentUnionGenTOBuilder
983      *            generated TO builder in which new property is created
984      * @param unionSubtype
985      *            type definition of the <code>ExtendedType</code> type which
986      *            represents union subtype
987      * @param regularExpressions
988      *            list of strings with the regular expressions
989      * @param parentNode
990      *            parent Schema Node for Extended Subtype
991      *
992      */
993     private void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
994             final TypeDefinition<?> unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode) {
995         final String unionTypeName = unionSubtype.getQName().getLocalName();
996         final Type genTO = findGenTO(unionTypeName, unionSubtype);
997         if (genTO != null) {
998             updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
999         } else {
1000             final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
1001             if (unionTypeName.equals(baseType.getQName().getLocalName())) {
1002                 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
1003                         parentNode);
1004                 if (javaType != null) {
1005                     updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
1006                 }
1007             }
1008             if (baseType instanceof StringType) {
1009                 regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
1010             }
1011         }
1012     }
1013
1014     /**
1015      * Searches for generated TO for <code>searchedTypeDef</code> type
1016      * definition in {@link #genTypeDefsContextMap genTypeDefsContextMap}
1017      *
1018      * @param searchedTypeName
1019      *            string with name of <code>searchedTypeDef</code>
1020      * @return generated TO for <code>searchedTypeDef</code> or
1021      *         <code>null</code> it it doesn't exist
1022      */
1023     private Type findGenTO(final String searchedTypeName, final SchemaNode parentNode) {
1024         final Module typeModule = findParentModule(schemaContext, parentNode);
1025         if (typeModule != null && typeModule.getName() != null) {
1026             final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(typeModule.getName());
1027             final Map<String, Type> genTOs = modulesByDate.get(typeModule.getRevision());
1028             if (genTOs != null) {
1029                 return genTOs.get(searchedTypeName);
1030             }
1031         }
1032         return null;
1033     }
1034
1035     /**
1036      * Stores generated TO created from <code>genTOBuilder</code> for
1037      * <code>newTypeDef</code> to {@link #genTypeDefsContextMap
1038      * genTypeDefsContextMap} if the module for <code>newTypeDef</code> exists
1039      *
1040      * @param newTypeDef
1041      *            type definition for which is <code>genTOBuilder</code> created
1042      * @param genTOBuilder
1043      *            generated TO builder which is converted to generated TO and
1044      *            stored
1045      */
1046     private void storeGenTO(final TypeDefinition<?> newTypeDef, final GeneratedTOBuilder genTOBuilder,
1047             final SchemaNode parentNode) {
1048         if (!(newTypeDef instanceof UnionTypeDefinition)) {
1049             final Module parentModule = findParentModule(schemaContext, parentNode);
1050             if (parentModule != null && parentModule.getName() != null) {
1051                 Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(parentModule.getName());
1052                 Map<String, Type> genTOsMap = modulesByDate.get(parentModule.getRevision());
1053                 genTOsMap.put(newTypeDef.getQName().getLocalName(), genTOBuilder.toInstance());
1054             }
1055         }
1056     }
1057
1058     /**
1059      * Adds a new property with the name <code>propertyName</code> and with type
1060      * <code>type</code> to <code>unonGenTransObject</code>.
1061      *
1062      * @param unionGenTransObject
1063      *            generated TO to which should be property added
1064      * @param type
1065      *            JAVA <code>type</code> of the property which should be added
1066      *            to <code>unionGentransObject</code>
1067      * @param propertyName
1068      *            string with name of property which should be added to
1069      *            <code>unionGentransObject</code>
1070      */
1071     private static void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type,
1072             final String propertyName) {
1073         if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
1074             final GeneratedPropertyBuilder propBuilder = unionGenTransObject
1075                     .addProperty(BindingMapping.getPropertyName(propertyName));
1076             propBuilder.setReturnType(type);
1077
1078             unionGenTransObject.addEqualsIdentity(propBuilder);
1079             unionGenTransObject.addHashIdentity(propBuilder);
1080             unionGenTransObject.addToStringProperty(propBuilder);
1081         }
1082     }
1083
1084     /**
1085      * Converts <code>typedef</code> to the generated TO builder.
1086      *
1087      * @param basePackageName
1088      *            string with name of package to which the module belongs
1089      * @param typedef
1090      *            type definition from which is the generated TO builder created
1091      * @return generated TO builder which contains data from
1092      *         <code>typedef</code> and <code>basePackageName</code>
1093      */
1094     private static GeneratedTOBuilderImpl typedefToTransferObject(final String basePackageName,
1095             final TypeDefinition<?> typedef, final String moduleName) {
1096
1097         final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typedef.getPath());
1098         final String typeDefTOName = typedef.getQName().getLocalName();
1099
1100         if ((packageName != null) && (typeDefTOName != null)) {
1101             final String genTOName = BindingMapping.getClassName(typeDefTOName);
1102             final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName);
1103
1104             newType.setDescription(typedef.getDescription());
1105             newType.setReference(typedef.getReference());
1106             newType.setSchemaPath(typedef.getPath().getPathFromRoot());
1107             newType.setModuleName(moduleName);
1108
1109             return newType;
1110         }
1111         return null;
1112     }
1113
1114     /**
1115      * Converts <code>typeDef</code> which should be of the type
1116      * <code>BitsTypeDefinition</code> to <code>GeneratedTOBuilder</code>.
1117      *
1118      * All the bits of the typeDef are added to returning generated TO as
1119      * properties.
1120      *
1121      * @param basePackageName
1122      *            string with name of package to which the module belongs
1123      * @param typeDef
1124      *            type definition from which is the generated TO builder created
1125      * @param typeDefName
1126      *            string with the name for generated TO builder
1127      * @return generated TO builder which represents <code>typeDef</code>
1128      * @throws IllegalArgumentException
1129      *             <ul>
1130      *             <li>if <code>typeDef</code> equals null</li>
1131      *             <li>if <code>basePackageName</code> equals null</li>
1132      *             </ul>
1133      */
1134     public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName,
1135             final TypeDefinition<?> typeDef, final String typeDefName, final String moduleName) {
1136
1137         Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
1138         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
1139
1140         if (typeDef instanceof BitsTypeDefinition) {
1141             BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
1142
1143             final String typeName = BindingMapping.getClassName(typeDefName);
1144             final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
1145
1146             genTOBuilder.setDescription(typeDef.getDescription());
1147             genTOBuilder.setReference(typeDef.getReference());
1148             genTOBuilder.setSchemaPath(typeDef.getPath().getPathFromRoot());
1149             genTOBuilder.setModuleName(moduleName);
1150             genTOBuilder.setBaseType(typeDef);
1151
1152             final List<Bit> bitList = bitsTypeDefinition.getBits();
1153             GeneratedPropertyBuilder genPropertyBuilder;
1154             for (final Bit bit : bitList) {
1155                 String name = bit.getName();
1156                 genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
1157                 genPropertyBuilder.setReadOnly(true);
1158                 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
1159
1160                 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
1161                 genTOBuilder.addHashIdentity(genPropertyBuilder);
1162                 genTOBuilder.addToStringProperty(genPropertyBuilder);
1163             }
1164
1165             return genTOBuilder;
1166         }
1167         return null;
1168     }
1169
1170     /**
1171      * Converts the pattern constraints from <code>typedef</code> to the list of
1172      * the strings which represents these constraints.
1173      *
1174      * @param typedef
1175      *            extended type in which are the pattern constraints sought
1176      * @return list of strings which represents the constraint patterns
1177      * @throws IllegalArgumentException
1178      *             if <code>typedef</code> equals null
1179      *
1180      */
1181     private static List<String> resolveRegExpressionsFromTypedef(final TypeDefinition<?> typedef) {
1182         Preconditions.checkArgument(typedef != null, "typedef can't be null");
1183
1184         final List<PatternConstraint> patternConstraints;
1185         if (typedef instanceof ExtendedType) {
1186             final TypeDefinition<?> strTypeDef = baseTypeDefForExtendedType(typedef);
1187             if (strTypeDef instanceof StringType) {
1188                 patternConstraints = ((ExtendedType)typedef).getPatternConstraints();
1189             } else {
1190                 patternConstraints = ImmutableList.of();
1191             }
1192         } else if (typedef instanceof StringTypeDefinition) {
1193             // FIXME: run diff against base
1194             patternConstraints = ((StringTypeDefinition) typedef).getPatternConstraints();
1195         } else {
1196             patternConstraints = ImmutableList.of();
1197         }
1198
1199         final List<String> regExps = new ArrayList<>(patternConstraints.size());
1200         for (PatternConstraint patternConstraint : patternConstraints) {
1201             final String regEx = patternConstraint.getRegularExpression();
1202             final String modifiedRegEx = StringEscapeUtils.escapeJava(regEx);
1203             regExps.add(modifiedRegEx);
1204         }
1205
1206         return regExps;
1207     }
1208
1209     /**
1210      *
1211      * Adds to the <code>genTOBuilder</code> the constant which contains regular
1212      * expressions from the <code>regularExpressions</code>
1213      *
1214      * @param genTOBuilder
1215      *            generated TO builder to which are
1216      *            <code>regular expressions</code> added
1217      * @param regularExpressions
1218      *            list of string which represent regular expressions
1219      * @throws IllegalArgumentException
1220      *             <ul>
1221      *             <li>if <code>genTOBuilder</code> equals null</li>
1222      *             <li>if <code>regularExpressions</code> equals null</li>
1223      *             </ul>
1224      */
1225     private static void addStringRegExAsConstant(final GeneratedTOBuilder genTOBuilder, final List<String> regularExpressions) {
1226         if (genTOBuilder == null) {
1227             throw new IllegalArgumentException("Generated transfer object builder can't be null");
1228         }
1229         if (regularExpressions == null) {
1230             throw new IllegalArgumentException("List of regular expressions can't be null");
1231         }
1232         if (!regularExpressions.isEmpty()) {
1233             genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), TypeConstants.PATTERN_CONSTANT_NAME,
1234                     regularExpressions);
1235         }
1236     }
1237
1238     /**
1239      * Creates generated TO with data about inner extended type
1240      * <code>innerExtendedType</code>, about the package name
1241      * <code>typedefName</code> and about the generated TO name
1242      * <code>typedefName</code>.
1243      *
1244      * It is supposed that <code>innerExtendedType</code> is already present in
1245      * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap} to
1246      * be possible set it as extended type for the returning generated TO.
1247      *
1248      * @param typedef
1249      *            Type Definition
1250      * @param innerExtendedType
1251      *            extended type which is part of some other extended type
1252      * @param basePackageName
1253      *            string with the package name of the module
1254      * @param moduleName
1255      *            Module Name
1256      * @return generated TO which extends generated TO for
1257      *         <code>innerExtendedType</code>
1258      * @throws IllegalArgumentException
1259      *             <ul>
1260      *             <li>if <code>extendedType</code> equals null</li>
1261      *             <li>if <code>basePackageName</code> equals null</li>
1262      *             <li>if <code>typedefName</code> equals null</li>
1263      *             </ul>
1264      */
1265     private GeneratedTransferObject provideGeneratedTOFromExtendedType(final TypeDefinition<?> typedef,
1266             final TypeDefinition<?> innerExtendedType, final String basePackageName, final String moduleName) {
1267         Preconditions.checkArgument(innerExtendedType != null, "Extended type cannot be NULL!");
1268         Preconditions.checkArgument(basePackageName != null, "String with base package name cannot be NULL!");
1269
1270         final String typedefName = typedef.getQName().getLocalName();
1271         final String classTypedefName = BindingMapping.getClassName(typedefName);
1272         final String innerTypeDef = innerExtendedType.getQName().getLocalName();
1273         final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, classTypedefName);
1274
1275         genTOBuilder.setDescription(typedef.getDescription());
1276         genTOBuilder.setReference(typedef.getReference());
1277         genTOBuilder.setSchemaPath(typedef.getPath().getPathFromRoot());
1278         genTOBuilder.setModuleName(moduleName);
1279         genTOBuilder.setTypedef(true);
1280         Restrictions r = BindingGeneratorUtil.getRestrictions(typedef);
1281         genTOBuilder.setRestrictions(r);
1282
1283         if (baseTypeDefForExtendedType(innerExtendedType) instanceof UnionTypeDefinition) {
1284             genTOBuilder.setIsUnion(true);
1285         }
1286
1287         Map<Date, Map<String, Type>> modulesByDate = null;
1288         Map<String, Type> typeMap = null;
1289         final Module parentModule = findParentModule(schemaContext, innerExtendedType);
1290         if (parentModule != null) {
1291             modulesByDate = genTypeDefsContextMap.get(parentModule.getName());
1292             typeMap = modulesByDate.get(parentModule.getRevision());
1293         }
1294
1295         if (typeMap != null) {
1296             Type type = typeMap.get(innerTypeDef);
1297             if (type instanceof GeneratedTransferObject) {
1298                 genTOBuilder.setExtendsType((GeneratedTransferObject) type);
1299             }
1300         }
1301         addUnitsToGenTO(genTOBuilder, typedef.getUnits());
1302         makeSerializable(genTOBuilder);
1303
1304         return genTOBuilder.toInstance();
1305     }
1306
1307     /**
1308      * Add {@link Serializable} to implemented interfaces of this TO. Also
1309      * compute and add serialVersionUID property.
1310      *
1311      * @param gto
1312      *            transfer object which needs to be serializable
1313      */
1314     private static void makeSerializable(final GeneratedTOBuilderImpl gto) {
1315         gto.addImplementsType(Types.typeForClass(Serializable.class));
1316         GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
1317         prop.setValue(Long.toString(BindingGeneratorUtil.computeDefaultSUID(gto)));
1318         gto.setSUID(prop);
1319     }
1320
1321     /**
1322      * Finds out for each type definition how many immersion (depth) is
1323      * necessary to get to the base type. Every type definition is inserted to
1324      * the map which key is depth and value is list of type definitions with
1325      * equal depth. In next step are lists from this map concatenated to one
1326      * list in ascending order according to their depth. All type definitions
1327      * are in the list behind all type definitions on which depends.
1328      *
1329      * @param unsortedTypeDefinitions
1330      *            list of type definitions which should be sorted by depth
1331      * @return list of type definitions sorted according their each other
1332      *         dependencies (type definitions which are depend on other type
1333      *         definitions are in list behind them).
1334      */
1335     private static List<TypeDefinition<?>> sortTypeDefinitionAccordingDepth(
1336             final Collection<TypeDefinition<?>> unsortedTypeDefinitions) {
1337         List<TypeDefinition<?>> sortedTypeDefinition = new ArrayList<>();
1338
1339         Map<Integer, List<TypeDefinition<?>>> typeDefinitionsDepths = new TreeMap<>();
1340         for (TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
1341             final int depth = getTypeDefinitionDepth(unsortedTypeDefinition);
1342             List<TypeDefinition<?>> typeDefinitionsConcreteDepth = typeDefinitionsDepths.get(depth);
1343             if (typeDefinitionsConcreteDepth == null) {
1344                 typeDefinitionsConcreteDepth = new ArrayList<TypeDefinition<?>>();
1345                 typeDefinitionsDepths.put(depth, typeDefinitionsConcreteDepth);
1346             }
1347             typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
1348         }
1349
1350         // SortedMap guarantees order corresponding to keys in ascending order
1351         for (List<TypeDefinition<?>> v : typeDefinitionsDepths.values()) {
1352             sortedTypeDefinition.addAll(v);
1353         }
1354
1355         return sortedTypeDefinition;
1356     }
1357
1358     /**
1359      * Returns how many immersion is necessary to get from the type definition
1360      * to the base type.
1361      *
1362      * @param typeDefinition
1363      *            type definition for which is depth sought.
1364      * @return number of immersions which are necessary to get from the type
1365      *         definition to the base type
1366      */
1367     private static int getTypeDefinitionDepth(final TypeDefinition<?> typeDefinition) {
1368         // FIXME: rewrite this in a non-recursive manner, without ExtendedType and UnionType
1369         if (typeDefinition == null) {
1370             return 1;
1371         }
1372         int depth = 1;
1373         TypeDefinition<?> baseType = typeDefinition.getBaseType();
1374
1375         if (baseType instanceof ExtendedType) {
1376             depth = depth + getTypeDefinitionDepth(typeDefinition.getBaseType());
1377         } else if (baseType instanceof UnionType) {
1378             List<TypeDefinition<?>> childTypeDefinitions = ((UnionType) baseType).getTypes();
1379             int maxChildDepth = 0;
1380             int childDepth = 1;
1381             for (TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
1382                 childDepth = childDepth + getTypeDefinitionDepth(childTypeDefinition);
1383                 if (childDepth > maxChildDepth) {
1384                     maxChildDepth = childDepth;
1385                 }
1386             }
1387             return maxChildDepth;
1388         }
1389         return depth;
1390     }
1391
1392     /**
1393      * Returns string which contains the same value as <code>name</code> but
1394      * integer suffix is incremented by one. If <code>name</code> contains no
1395      * number suffix then number 1 is added.
1396      *
1397      * @param name
1398      *            string with name of augmented node
1399      * @return string with the number suffix incremented by one (or 1 is added)
1400      */
1401     private static String provideAvailableNameForGenTOBuilder(final String name) {
1402         Matcher mtch = NUMBERS_PATTERN.matcher(name);
1403         if (mtch.find()) {
1404             final int newSuffix = Integer.valueOf(name.substring(mtch.start())) + 1;
1405             return name.substring(0, mtch.start()) + newSuffix;
1406         } else {
1407             return name + 1;
1408         }
1409     }
1410
1411     public static void addUnitsToGenTO(final GeneratedTOBuilder to, final String units) {
1412         if (!Strings.isNullOrEmpty(units)) {
1413             to.addConstant(Types.STRING, "_UNITS", "\"" + units + "\"");
1414             GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("UNITS");
1415             prop.setReturnType(Types.STRING);
1416             to.addToStringProperty(prop);
1417         }
1418     }
1419
1420     @Override
1421     public String getTypeDefaultConstruction(final LeafSchemaNode node) {
1422         return getTypeDefaultConstruction(node, node.getDefault());
1423     }
1424
1425     public String getTypeDefaultConstruction(final LeafSchemaNode node, final String defaultValue) {
1426         TypeDefinition<?> type = node.getType();
1427         QName typeQName = type.getQName();
1428         TypeDefinition<?> base = baseTypeDefForExtendedType(type);
1429         Preconditions.checkNotNull(type, "Cannot provide default construction for null type of %s", node);
1430         Preconditions.checkNotNull(defaultValue, "Cannot provide default construction for null default statement of %s",
1431                 node);
1432
1433         StringBuilder sb = new StringBuilder();
1434         String result = null;
1435         if (base instanceof BinaryTypeDefinition) {
1436             result = binaryToDef(defaultValue);
1437         } else if (base instanceof BitsTypeDefinition) {
1438             String parentName;
1439             String className;
1440             Module parent = getParentModule(node);
1441             Iterator<QName> path = node.getPath().getPathFromRoot().iterator();
1442             path.next();
1443             if (!(path.hasNext())) {
1444                 parentName = BindingMapping.getClassName(parent.getName()) + "Data";
1445                 String basePackageName = BindingMapping.getRootPackageName(parent.getQNameModule());
1446                 className = basePackageName + "." + parentName + "." + BindingMapping.getClassName(node.getQName());
1447             } else {
1448                 String basePackageName = BindingMapping.getRootPackageName(parent.getQNameModule());
1449                 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, type.getPath());
1450                 parentName = BindingMapping.getClassName(parent.getName());
1451                 className = packageName + "." + parentName + "." + BindingMapping.getClassName(node.getQName());
1452             }
1453             result = bitsToDef((BitsTypeDefinition) base, className, defaultValue, type instanceof ExtendedType);
1454         } else if (base instanceof BooleanTypeDefinition) {
1455             result = typeToDef(Boolean.class, defaultValue);
1456         } else if (base instanceof DecimalTypeDefinition) {
1457             result = typeToDef(BigDecimal.class, defaultValue);
1458         } else if (base instanceof EmptyTypeDefinition) {
1459             result = typeToDef(Boolean.class, defaultValue);
1460         } else if (base instanceof EnumTypeDefinition) {
1461             char[] defValArray = defaultValue.toCharArray();
1462             char first = Character.toUpperCase(defaultValue.charAt(0));
1463             defValArray[0] = first;
1464             String newDefVal = new String(defValArray);
1465             String className;
1466             if (type instanceof ExtendedType) {
1467                 Module m = getParentModule(type);
1468                 String basePackageName = BindingMapping.getRootPackageName(m.getQNameModule());
1469                 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, type.getPath());
1470                 className = packageName + "." + BindingMapping.getClassName(typeQName);
1471             } else {
1472                 Module parentModule = getParentModule(node);
1473                 String basePackageName = BindingMapping.getRootPackageName(parentModule.getQNameModule());
1474                 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, node.getPath());
1475                 className = packageName + "." + BindingMapping.getClassName(node.getQName());
1476             }
1477             result = className + "." + newDefVal;
1478         } else if (base instanceof IdentityrefTypeDefinition) {
1479             throw new UnsupportedOperationException("Cannot get default construction for identityref type");
1480         } else if (base instanceof InstanceIdentifierTypeDefinition) {
1481             throw new UnsupportedOperationException("Cannot get default construction for instance-identifier type");
1482         } else if (BaseTypes.isInt8(base)) {
1483             result = typeToDef(Byte.class, defaultValue);
1484         } else if (BaseTypes.isInt16(base)) {
1485             result = typeToDef(Short.class, defaultValue);
1486         } else if (BaseTypes.isInt32(base)) {
1487             result = typeToDef(Integer.class, defaultValue);
1488         } else if (BaseTypes.isInt64(base)) {
1489             result = typeToDef(Long.class, defaultValue);
1490         } else if (base instanceof LeafrefTypeDefinition) {
1491             result = leafrefToDef(node, (LeafrefTypeDefinition) base, defaultValue);
1492         } else if (base instanceof StringTypeDefinition) {
1493             result = "\"" + defaultValue + "\"";
1494         } else if (BaseTypes.isUint8(base)) {
1495             result = typeToDef(Short.class, defaultValue);
1496         } else if (BaseTypes.isUint16(base)) {
1497             result = typeToDef(Integer.class, defaultValue);
1498         } else if (BaseTypes.isUint32(base)) {
1499             result = typeToDef(Long.class, defaultValue);
1500         } else if (BaseTypes.isUint64(base)) {
1501             result = typeToDef(BigInteger.class, defaultValue);
1502         } else if (base instanceof UnionTypeDefinition) {
1503             result = unionToDef(node);
1504         } else {
1505             result = "";
1506         }
1507         sb.append(result);
1508
1509         if (type instanceof ExtendedType && !(base instanceof LeafrefTypeDefinition)
1510                 && !(base instanceof EnumerationType) && !(base instanceof UnionTypeDefinition)) {
1511             Module m = getParentModule(type);
1512             String basePackageName = BindingMapping.getRootPackageName(m.getQNameModule());
1513             String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, type.getPath());
1514             String className = packageName + "." + BindingMapping.getClassName(typeQName);
1515             sb.insert(0, "new " + className + "(");
1516             sb.insert(sb.length(), ')');
1517         }
1518
1519         return sb.toString();
1520     }
1521
1522     private static String typeToDef(final Class<?> clazz, final String defaultValue) {
1523         return "new " + clazz.getName() + "(\"" + defaultValue + "\")";
1524     }
1525
1526     private static String binaryToDef(final String defaultValue) {
1527         StringBuilder sb = new StringBuilder();
1528         BaseEncoding en = BaseEncoding.base64();
1529         byte[] encoded = en.decode(defaultValue);
1530         sb.append("new byte[] {");
1531         for (int i = 0; i < encoded.length; i++) {
1532             sb.append(encoded[i]);
1533             if (i != encoded.length - 1) {
1534                 sb.append(", ");
1535             }
1536         }
1537         sb.append('}');
1538         return sb.toString();
1539     }
1540
1541     private static final Comparator<Bit> BIT_NAME_COMPARATOR = new Comparator<Bit>() {
1542         @Override
1543         public int compare(final Bit o1, final Bit o2) {
1544             return o1.getName().compareTo(o2.getName());
1545         }
1546     };
1547
1548     private static String bitsToDef(final BitsTypeDefinition type, final String className, final String defaultValue,
1549             final boolean isExt) {
1550         List<Bit> bits = new ArrayList<>(type.getBits());
1551         Collections.sort(bits, BIT_NAME_COMPARATOR);
1552         StringBuilder sb = new StringBuilder();
1553         if (!isExt) {
1554             sb.append("new ");
1555             sb.append(className);
1556             sb.append('(');
1557         }
1558         for (int i = 0; i < bits.size(); i++) {
1559             if (bits.get(i).getName().equals(defaultValue)) {
1560                 sb.append(true);
1561             } else {
1562                 sb.append(false);
1563             }
1564             if (i != bits.size() - 1) {
1565                 sb.append(", ");
1566             }
1567         }
1568         if (!isExt) {
1569             sb.append(')');
1570         }
1571         return sb.toString();
1572     }
1573
1574     private Module getParentModule(final SchemaNode node) {
1575         QName qname = node.getPath().getPathFromRoot().iterator().next();
1576         URI namespace = qname.getNamespace();
1577         Date revision = qname.getRevision();
1578         return schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
1579     }
1580
1581     private String leafrefToDef(final LeafSchemaNode parentNode, final LeafrefTypeDefinition leafrefType, final String defaultValue) {
1582         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
1583         Preconditions.checkArgument(leafrefType.getPathStatement() != null,
1584                 "The Path Statement for Leafref Type Definition cannot be NULL!");
1585
1586         final RevisionAwareXPath xpath = leafrefType.getPathStatement();
1587         final String strXPath = xpath.toString();
1588
1589         if (strXPath != null) {
1590             if (strXPath.indexOf('[') == -1) {
1591                 final Module module = findParentModule(schemaContext, parentNode);
1592                 if (module != null) {
1593                     final SchemaNode dataNode;
1594                     if (xpath.isAbsolute()) {
1595                         dataNode = findDataSchemaNode(schemaContext, module, xpath);
1596                     } else {
1597                         dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
1598                     }
1599                     String result = getTypeDefaultConstruction((LeafSchemaNode) dataNode, defaultValue);
1600                     return result;
1601                 }
1602             } else {
1603                 return "new java.lang.Object()";
1604             }
1605         }
1606
1607         return null;
1608     }
1609
1610     private String unionToDef(final LeafSchemaNode node) {
1611         String parentName;
1612         String className;
1613
1614         if (node.getType() instanceof ExtendedType) {
1615             ExtendedType type = (ExtendedType) node.getType();
1616             QName typeQName = type.getQName();
1617             Module module = null;
1618             Set<Module> modules = schemaContext.findModuleByNamespace(typeQName.getNamespace());
1619             if (modules.size() > 1) {
1620                 for (Module m : modules) {
1621                     if (m.getRevision().equals(typeQName.getRevision())) {
1622                         module = m;
1623                         break;
1624                     }
1625                 }
1626                 if (module == null) {
1627                     List<Module> modulesList = new ArrayList<>(modules);
1628                     Collections.sort(modulesList, new Comparator<Module>() {
1629                         @Override
1630                         public int compare(final Module o1, final Module o2) {
1631                             return o1.getRevision().compareTo(o2.getRevision());
1632                         }
1633                     });
1634                     module = modulesList.get(0);
1635                 }
1636             } else {
1637                 module = modules.iterator().next();
1638             }
1639
1640             String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
1641             className = basePackageName + "." + BindingMapping.getClassName(typeQName);
1642         } else {
1643             Iterator<QName> path = node.getPath().getPathFromRoot().iterator();
1644             QName first = path.next();
1645             if (!(path.hasNext())) {
1646                 URI namespace = first.getNamespace();
1647                 Date revision = first.getRevision();
1648                 Module parent = schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
1649                 parentName = BindingMapping.getClassName((parent).getName()) + "Data";
1650                 String basePackageName = BindingMapping.getRootPackageName(parent.getQNameModule());
1651                 className = basePackageName + "." + parentName + "." + BindingMapping.getClassName(node.getQName());
1652             } else {
1653                 URI namespace = first.getNamespace();
1654                 Date revision = first.getRevision();
1655                 Module parentModule = schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
1656                 String basePackageName = BindingMapping.getRootPackageName(parentModule.getQNameModule());
1657                 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName,
1658                     node.getType().getPath());
1659                 className = packageName + "." + BindingMapping.getClassName(node.getQName());
1660             }
1661         }
1662         return union(className, node.getDefault(), node);
1663     }
1664
1665     private static String union(final String className, final String defaultValue, final LeafSchemaNode node) {
1666         StringBuilder sb = new StringBuilder();
1667         sb.append("new ");
1668         sb.append(className);
1669         sb.append("(\"");
1670         sb.append(defaultValue);
1671         sb.append("\".toCharArray())");
1672         return sb.toString();
1673     }
1674
1675     @Override
1676     public String getConstructorPropertyName(final SchemaNode node) {
1677         if (node instanceof TypeDefinition<?>) {
1678             return "value";
1679         } else {
1680             return "";
1681         }
1682     }
1683
1684     @Override
1685     public String getParamNameFromType(final TypeDefinition<?> type) {
1686         return BindingMapping.getPropertyName(type.getQName().getLocalName());
1687     }
1688
1689 }