2 * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.mdsal.binding.javav2.generator.yang.types;
11 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
12 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.addStringRegExAsConstant;
13 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.baseTypeDefForExtendedType;
14 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.getAllTypedefs;
15 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.getParentModule;
16 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.makeSerializable;
17 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.provideGeneratedTOFromExtendedType;
18 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.provideTypeForEnum;
19 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.resolveRegExpressionsFromTypedef;
20 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.sortTypeDefinitionAccordingDepth;
21 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.wrapJavaTypeIntoTO;
22 import static org.opendaylight.mdsal.binding.javav2.util.BindingMapping.getRootPackageName;
23 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
24 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
25 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
27 import com.google.common.annotations.Beta;
28 import com.google.common.base.Preconditions;
29 import com.google.common.base.Strings;
30 import com.google.common.collect.Sets;
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Date;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
41 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
43 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
44 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
45 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
46 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
47 import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
48 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
49 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
50 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
51 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
52 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
53 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
54 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
55 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilderBase;
56 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
57 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
58 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
59 import org.opendaylight.yangtools.yang.common.QName;
60 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
61 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
62 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
63 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
65 import org.opendaylight.yangtools.yang.model.api.Module;
66 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
67 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
70 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
71 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
72 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
73 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
75 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
77 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
78 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
79 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
80 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
81 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
86 public final class TypeProviderImpl implements TypeProvider {
88 private static final Logger LOG = LoggerFactory.getLogger(TypeProviderImpl.class);
89 private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z");
92 * Contains the schema data red from YANG files.
94 private final SchemaContext schemaContext;
97 * Map<moduleName, Map<moduleDate, Map<typeName, type>>>
99 private final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap;
102 * Map which maps schema paths to JAVA <code>Type</code>.
104 private final Map<SchemaPath, Type> referencedTypes;
107 * Map for additional types e.g unions
109 private final Map<Module, Set<Type>> additionalTypes;
112 * Creates new instance of class <code>TypeProviderImpl</code>.
114 * @param schemaContext
115 * contains the schema data red from YANG files
116 * @throws IllegalArgumentException
117 * if <code>schemaContext</code> equal null.
119 public TypeProviderImpl(final SchemaContext schemaContext) {
120 this.schemaContext = schemaContext;
121 this.genTypeDefsContextMap = new HashMap<>();
122 this.referencedTypes = new HashMap<>();
123 this.additionalTypes = new HashMap<>();
124 resolveTypeDefsFromContext(schemaContext, genTypeDefsContextMap, additionalTypes);
128 public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> type, SchemaNode parentNode) {
129 return javaTypeForSchemaDefinitionType(type, parentNode, null);
133 * Converts schema definition type <code>typeDefinition</code> to JAVA
137 * type definition which is converted to JAVA type
138 * @throws IllegalArgumentException
140 * <li>if <code>typeDefinition</code> equal null</li>
141 * <li>if Qname of <code>typeDefinition</code> equal null</li>
142 * <li>if name of <code>typeDefinition</code> equal null</li>
146 public Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode, Restrictions restrictions) {
147 return javaTypeForSchemaDefType(type, parentNode, restrictions, this.schemaContext, this.genTypeDefsContextMap);
151 public String getTypeDefaultConstruction(LeafSchemaNode node) {
156 public String getConstructorPropertyName(SchemaNode node) {
161 public String getParamNameFromType(TypeDefinition<?> type) {
166 * Passes through all modules and through all its type definitions and
167 * convert it to generated types.
169 * The modules are firstly sorted by mutual dependencies. The modules are
170 * sequentially passed. All type definitions of a module are at the
171 * beginning sorted so that type definition with less amount of references
172 * to other type definition are processed first.<br />
173 * For each module is created mapping record in the map
174 * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap}
175 * which map current module name to the map which maps type names to
176 * returned types (generated types).
179 private void resolveTypeDefsFromContext(final SchemaContext schemaContext, Map<String, Map<Date, Map<String,
180 Type>>> genTypeDefsContextMap, Map<Module, Set<Type>> additionalTypes) {
182 final Set<Module> modules = schemaContext.getModules();
183 Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
184 final Module[] modulesArray = new Module[modules.size()];
186 for (Module modul : modules) {
187 modulesArray[i++] = modul;
189 final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
192 for (final Module module : modulesSortedByDependency) {
193 Map<Date, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
194 if (dateTypeMap == null) {
195 dateTypeMap = new HashMap<>();
197 dateTypeMap.put(module.getRevision(), Collections.emptyMap());
198 genTypeDefsContextMap.put(module.getName(), dateTypeMap);
201 modulesSortedByDependency.stream().filter(module -> module != null).forEach(module -> {
202 final String basePackageName = getRootPackageName(module);
203 final List<TypeDefinition<?>> typeDefinitions = getAllTypedefs(module);
204 final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
205 if (listTypeDefinitions != null) {
206 for (final TypeDefinition<?> typedef : listTypeDefinitions) {
207 typedefToGeneratedType(basePackageName, module, typedef, genTypeDefsContextMap,
208 additionalTypes, schemaContext);
215 * Converts <code>typeDefinition</code> to concrete JAVA <code>Type</code>.
217 * @param typeDefinition
218 * type definition which should be converted to JAVA
220 * @return JAVA <code>Type</code> which represents
221 * <code>typeDefinition</code>
222 * @throws IllegalArgumentException
224 * <li>if <code>typeDefinition</code> equal null</li>
225 * <li>if Q name of <code>typeDefinition</code></li>
226 * <li>if name of <code>typeDefinition</code></li>
229 public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
230 Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
231 Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
232 "Type Definitions Local Name cannot be NULL!");
234 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
235 if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
236 final Module module = findParentModule(schemaContext, parentNode);
238 if (module != null) {
239 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
240 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
241 if (genTOs != null) {
242 return genTOs.get(typeDefinition.getQName().getLocalName());
250 * Puts <code>refType</code> to map with key <code>refTypePath</code>
253 * schema path used as the map key
255 * type which represents the map value
256 * @throws IllegalArgumentException
258 * <li>if <code>refTypePath</code> equal null</li>
259 * <li>if <code>refType</code> equal null</li>
263 public void putReferencedType(final SchemaPath refTypePath, final Type refType) {
264 Preconditions.checkArgument(refTypePath != null,
265 "Path reference of Enumeration Type Definition cannot be NULL!");
266 Preconditions.checkArgument(refType != null, "Reference to Enumeration Type cannot be NULL!");
267 referencedTypes.put(refTypePath, refType);
271 * Converts <code>typeDef</code> which should be of the type
272 * <code>BitsTypeDefinition</code> to <code>GeneratedTOBuilder</code>.
274 * All the bits of the typeDef are added to returning generated TO as
277 * @param basePackageName
278 * string with name of package to which the module belongs
280 * type definition from which is the generated TO builder created
282 * string with the name for generated TO builder
283 * @return generated TO builder which represents <code>typeDef</code>
284 * @throws IllegalArgumentException
286 * <li>if <code>typeDef</code> equals null</li>
287 * <li>if <code>basePackageName</code> equals null</li>
290 public static GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName, final
291 TypeDefinition<?> typeDef, final String typeDefName, final String moduleName) {
293 Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
294 Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
296 if (typeDef instanceof BitsTypeDefinition) {
297 BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
299 final String typeName = BindingMapping.getClassName(typeDefName);
300 final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
301 final String typedefDescription = encodeAngleBrackets(typeDef.getDescription());
303 genTOBuilder.setDescription(typedefDescription);
304 genTOBuilder.setReference(typeDef.getReference());
305 genTOBuilder.setSchemaPath((List) typeDef.getPath().getPathFromRoot());
306 genTOBuilder.setModuleName(moduleName);
307 genTOBuilder.setBaseType(typeDef);
309 final List<Bit> bitList = bitsTypeDefinition.getBits();
310 GeneratedPropertyBuilder genPropertyBuilder;
311 for (final Bit bit : bitList) {
312 String name = bit.getName();
313 genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
314 genPropertyBuilder.setReadOnly(true);
315 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
317 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
318 genTOBuilder.addHashIdentity(genPropertyBuilder);
319 genTOBuilder.addToStringProperty(genPropertyBuilder);
328 * Converts <code>typedef</code> to generated TO with
329 * <code>typeDefName</code>. Every union type from <code>typedef</code> is
330 * added to generated TO builder as property.
332 * @param basePackageName
333 * string with name of package to which the module belongs
335 * type definition which should be of type
336 * <code>UnionTypeDefinition</code>
338 * string with name for generated TO
339 * @return generated TO builder which represents <code>typedef</code>
340 * @throws NullPointerException
342 * <li>if <code>basePackageName</code> is null</li>
343 * <li>if <code>typedef</code> is null</li>
344 * <li>if Qname of <code>typedef</code> is null</li>
347 public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
348 final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode, final SchemaContext
349 schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
350 Preconditions.checkNotNull(basePackageName, "Base Package Name cannot be NULL!");
351 Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
352 Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
354 final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
355 final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
356 final Module module = findParentModule(schemaContext, parentNode);
358 final GeneratedTOBuilderImpl unionGenTOBuilder;
359 if (typeDefName != null && !typeDefName.isEmpty()) {
360 final String typeName = BindingMapping.getClassName(typeDefName);
361 unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
362 final String typedefDescription = encodeAngleBrackets(typedef.getDescription());
363 unionGenTOBuilder.setDescription(typedefDescription);
364 unionGenTOBuilder.setReference(typedef.getReference());
365 unionGenTOBuilder.setSchemaPath((List) typedef.getPath().getPathFromRoot());
366 unionGenTOBuilder.setModuleName(module.getName());
368 unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef, module.getName());
371 generatedTOBuilders.add(unionGenTOBuilder);
372 unionGenTOBuilder.setIsUnion(true);
373 final List<String> regularExpressions = new ArrayList<>();
374 for (final TypeDefinition<?> unionType : unionTypes) {
375 final String unionTypeName = unionType.getQName().getLocalName();
376 if (unionType.getBaseType() != null) {
377 resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, regularExpressions,
378 parentNode, schemaContext, genTypeDefsContextMap);
379 } else if (unionType instanceof UnionTypeDefinition) {
380 generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionTypeDefinition) unionType,
381 basePackageName, parentNode, schemaContext, genTypeDefsContextMap));
382 } else if (unionType instanceof EnumTypeDefinition) {
383 final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
384 unionTypeName, unionGenTOBuilder);
385 updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
387 final Type javaType = javaTypeForSchemaDefType(unionType, parentNode, null, schemaContext,
388 genTypeDefsContextMap);
389 updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
392 if (!regularExpressions.isEmpty()) {
393 addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
396 //storeGenTO(typedef, unionGenTOBuilder, parentNode);
398 return generatedTOBuilders;
401 public Map<Module, Set<Type>> getAdditionalTypes() {
402 return additionalTypes;
405 public static void addUnitsToGenTO(final GeneratedTOBuilder to, final String units) {
406 if (!Strings.isNullOrEmpty(units)) {
407 to.addConstant(Types.STRING, "Units", "\"" + units + "\"");
408 GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("UNITS");
409 prop.setReturnType(Types.STRING);
410 to.addToStringProperty(prop);
414 private Type javaTypeForSchemaDefType(final TypeDefinition<?> typeDefinition, final SchemaNode
415 parentNode, final Restrictions r, final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
416 Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
417 String typedefName = typeDefinition.getQName().getLocalName();
418 Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
420 // Deal with base types
421 if (typeDefinition.getBaseType() == null) {
422 // We have to deal with differing handling of decimal64. The old parser used a fixed Decimal64 type
423 // and generated an enclosing ExtendedType to hold any range constraints. The new parser instantiates
424 // a base type which holds these constraints.
425 if (typeDefinition instanceof DecimalTypeDefinition) {
426 final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode, r);
432 // Deal with leafrefs/identityrefs
433 Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode, schemaContext, genTypeDefsContextMap);
438 ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode);
440 LOG.debug("Failed to resolve Java type for {}", typeDefinition);
446 Type returnType = javaTypeForExtendedType(typeDefinition, schemaContext, genTypeDefsContextMap);
447 if (r != null && returnType instanceof GeneratedTransferObject) {
448 GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
449 Module module = findParentModule(schemaContext, parentNode);
450 String basePackageName = BindingMapping.getRootPackageName(module);
451 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typeDefinition
452 .getPath(), BindingNamespaceType.Typedef);
453 String genTOName = BindingMapping.getClassName(typedefName);
454 String name = packageName + "." + genTOName;
455 if (!(returnType.getFullyQualifiedName().equals(name))) {
456 returnType = shadedTOWithRestrictions(gto, r);
464 * @param basePackageName
465 * string with name of package to which the module belongs
467 * string with the name of the module for to which the
468 * <code>typedef</code> belongs
470 * type definition of the node for which should be creted JAVA
471 * <code>Type</code> (usually generated TO)
472 * @return JAVA <code>Type</code> representation of <code>typedef</code> or
473 * <code>null</code> value if <code>basePackageName</code> or
474 * <code>modulName</code> or <code>typedef</code> or Q name of
475 * <code>typedef</code> equals <code>null</code>
477 private Type typedefToGeneratedType(final String basePackageName, final Module module, final
478 TypeDefinition<?> typedef, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap, Map<Module,
479 Set<Type>> additionalTypes, final SchemaContext schemaContext) {
480 final String moduleName = module.getName();
481 final Date moduleRevision = module.getRevision();
482 if ((basePackageName != null) && (moduleName != null) && (typedef != null)) {
483 final String typedefName = typedef.getQName().getLocalName();
484 final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
485 if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
486 && !(innerTypeDefinition instanceof IdentityrefTypeDefinition)) {
488 if (innerTypeDefinition.getBaseType() != null) {
489 returnType = provideGeneratedTOFromExtendedType(typedef, innerTypeDefinition, basePackageName,
490 module.getName(), schemaContext, genTypeDefsContextMap);
491 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
492 final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
493 (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef, schemaContext, genTypeDefsContextMap);
494 genTOBuilder.setTypedef(true);
495 genTOBuilder.setIsUnion(true);
496 addUnitsToGenTO(genTOBuilder, typedef.getUnits());
497 makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
498 returnType = genTOBuilder.toInstance();
500 GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
501 genTOBuilder.getName() + "Builder");
502 unionBuilder.setIsUnionBuilder(true);
503 MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
504 method.setReturnType(returnType);
505 method.addParameter(Types.STRING, "defaultValue");
506 method.setAccessModifier(AccessModifier.PUBLIC);
507 method.setStatic(true);
508 Set<Type> types = additionalTypes.get(module);
510 types = Sets.newHashSet(unionBuilder.toInstance());
511 additionalTypes.put(module, types);
513 types.add(unionBuilder.toInstance());
515 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
516 // enums are automatically Serializable
517 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
518 // TODO units for typedef enum
519 returnType = provideTypeForEnum(enumTypeDef, typedefName, typedef, schemaContext);
520 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
521 final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
522 final GeneratedTOBuilder genTOBuilder =
523 provideGeneratedTOBuilderForBitsTypeDefinition(
524 basePackageName, bitsTypeDefinition, typedefName, module.getName());
525 genTOBuilder.setTypedef(true);
526 addUnitsToGenTO(genTOBuilder, typedef.getUnits());
527 makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
528 returnType = genTOBuilder.toInstance();
530 final Type javaType = javaTypeForSchemaDefType(innerTypeDefinition, typedef, null,
531 schemaContext, genTypeDefsContextMap);
532 returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType, module.getName());
534 if (returnType != null) {
535 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(moduleName);
536 Map<String, Type> typeMap = modulesByDate.get(moduleRevision);
537 if (typeMap != null) {
538 if (typeMap.isEmpty()) {
539 typeMap = new HashMap<>(4);
540 modulesByDate.put(moduleRevision, typeMap);
542 typeMap.put(typedefName, returnType);
552 * Returns JAVA <code>Type</code> for instances of the type
553 * <code>ExtendedType</code>.
555 * @param typeDefinition
556 * type definition which is converted to JAVA <code>Type</code>
557 * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
559 private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition, final SchemaContext
560 schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
562 final String typedefName = typeDefinition.getQName().getLocalName();
563 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
564 Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition, schemaContext, genTypeDefsContextMap);
565 if (returnType == null) {
566 if (baseTypeDef instanceof EnumTypeDefinition) {
567 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
568 returnType = provideTypeForEnum(enumTypeDef, typedefName, typeDefinition, schemaContext);
570 final Module module = findParentModule(schemaContext, typeDefinition);
571 Restrictions r = BindingGeneratorUtil.getRestrictions(typeDefinition);
572 if (module != null) {
573 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
574 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
575 if (genTOs != null) {
576 returnType = genTOs.get(typedefName);
578 if (returnType == null) {
579 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
580 baseTypeDef, typeDefinition, r);
589 * Returns JAVA <code>Type</code> for instances of the type
590 * <code>LeafrefTypeDefinition</code> or
591 * <code>IdentityrefTypeDefinition</code>.
593 * @param typeDefinition
594 * type definition which is converted to JAVA <code>Type</code>
595 * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
597 private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
598 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
599 if (typeDefinition instanceof LeafrefTypeDefinition) {
600 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
601 if (isLeafRefSelfReference(leafref, parentNode, schemaContext)) {
602 throw new YangValidationException("Leafref " + leafref.toString() + " is referencing itself, incoming" +
603 " StackOverFlowError detected.");
605 return provideTypeForLeafref(leafref, parentNode, schemaContext, genTypeDefsContextMap);
606 } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
607 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
608 return provideTypeForIdentityref(idref, schemaContext);
615 * Converts <code>leafrefType</code> to JAVA <code>Type</code>.
617 * The path of <code>leafrefType</code> is followed to find referenced node
618 * and its <code>Type</code> is returned.
621 * leafref type definition for which is the type sought
622 * @return JAVA <code>Type</code> of data schema node which is referenced in
623 * <code>leafrefType</code>
624 * @throws IllegalArgumentException
626 * <li>if <code>leafrefType</code> equal null</li>
627 * <li>if path statement of <code>leafrefType</code> equal null</li>
631 public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode,
632 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
634 Type returnType = null;
635 Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
637 Preconditions.checkArgument(leafrefType.getPathStatement() != null,
638 "The Path Statement for Leafref Type Definition cannot be NULL!");
640 final RevisionAwareXPath xpath = leafrefType.getPathStatement();
641 final String strXPath = xpath.toString();
643 if (strXPath != null) {
644 if (strXPath.indexOf('[') == -1) {
645 final Module module = findParentModule(schemaContext, parentNode);
646 Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
648 final SchemaNode dataNode;
649 if (xpath.isAbsolute()) {
650 dataNode = findDataSchemaNode(schemaContext, module, xpath);
652 dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
654 Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
655 strXPath, getParentModule(parentNode, schemaContext).getName(), parentNode.getQName().getModule());
657 if (leafContainsEnumDefinition(dataNode)) {
658 returnType = referencedTypes.get(dataNode.getPath());
659 } else if (leafListContainsEnumDefinition(dataNode)) {
660 returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
662 returnType = resolveTypeFromDataSchemaNode(dataNode, schemaContext, genTypeDefsContextMap);
665 returnType = Types.typeForClass(Object.class);
668 Preconditions.checkArgument(returnType != null, "Failed to find leafref target: %s in module %s (%s)",
669 strXPath, getParentModule(parentNode, schemaContext).getName(), parentNode.getQName().getModule());
674 * Checks if <code>dataNode</code> is <code>LeafSchemaNode</code> and if it
675 * so then checks if it is of type <code>EnumTypeDefinition</code>.
678 * data schema node for which is checked if it is leaf and if it
680 * @return boolean value
682 * <li>true - if <code>dataNode</code> is leaf of type enumeration</li>
683 * <li>false - other cases</li>
686 private static boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
687 if (dataNode instanceof LeafSchemaNode) {
688 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
689 //CompatUtils is not used here anymore
690 if (leaf.getType() instanceof EnumTypeDefinition) {
698 * Checks if <code>dataNode</code> is <code>LeafListSchemaNode</code> and if
699 * it so then checks if it is of type <code>EnumTypeDefinition</code>.
702 * data schema node for which is checked if it is leaflist and if
704 * @return boolean value
706 * <li>true - if <code>dataNode</code> is leaflist of type
708 * <li>false - other cases</li>
711 private static boolean leafListContainsEnumDefinition(final SchemaNode dataNode) {
712 if (dataNode instanceof LeafListSchemaNode) {
713 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
714 if (leafList.getType() instanceof EnumTypeDefinition) {
722 * Converts <code>dataNode</code> to JAVA <code>Type</code>.
725 * contains information about YANG type
726 * @return JAVA <code>Type</code> representation of <code>dataNode</code>
728 private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode, final SchemaContext schemaContext,
729 Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
730 Type returnType = null;
731 if (dataNode != null) {
732 if (dataNode instanceof LeafSchemaNode) {
733 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
734 //not using CompatUtils here anymore
735 final TypeDefinition<?> type = leaf.getType();
736 returnType = javaTypeForSchemaDefType(type, leaf, null, schemaContext, genTypeDefsContextMap);
737 } else if (dataNode instanceof LeafListSchemaNode) {
738 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
739 returnType = javaTypeForSchemaDefType(leafList.getType(), leafList, null, schemaContext, genTypeDefsContextMap);
746 * Seeks for identity reference <code>idref</code> the JAVA
747 * <code>type</code>.<br />
751 * If identy which is referenced via <code>idref</code> has name <b>Idn</b>
752 * then returning type is <b>{@code Class<? extends Idn>}</b></i>
755 * identityref type definition for which JAVA <code>Type</code>
757 * @return JAVA <code>Type</code> of the identity which is refrenced through
760 private static Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref, final SchemaContext schemaContext) {
761 //TODO: incompatibility with Binding spec v2, get first or only one
762 QName baseIdQName = idref.getIdentities().iterator().next().getQName();
763 Module module = schemaContext.findModuleByNamespaceAndRevision(baseIdQName.getNamespace(),
764 baseIdQName.getRevision());
765 IdentitySchemaNode identity = null;
766 for (IdentitySchemaNode id : module.getIdentities()) {
767 if (id.getQName().equals(baseIdQName)) {
771 Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
773 final String basePackageName = BindingMapping.getRootPackageName(module);
774 final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath
775 (), BindingNamespaceType.Typedef);
776 final String genTypeName = BindingMapping.getClassName(identity.getQName());
778 Type baseType = Types.typeForClass(Class.class);
779 Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
780 return Types.parameterizedTypeFor(baseType, paramType);
784 * Converts <code>typedef</code> to the generated TO builder.
786 * @param basePackageName
787 * string with name of package to which the module belongs
789 * type definition from which is the generated TO builder created
790 * @return generated TO builder which contains data from
791 * <code>typedef</code> and <code>basePackageName</code>
793 private static GeneratedTOBuilderImpl typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef, final String moduleName) {
795 final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typedef.getPath
796 (), BindingNamespaceType.Typedef);
797 final String typeDefTOName = typedef.getQName().getLocalName();
799 if ((packageName != null) && (typeDefTOName != null)) {
800 final String genTOName = BindingMapping.getClassName(typeDefTOName);
801 final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName);
802 final String typedefDescription = encodeAngleBrackets(typedef.getDescription());
804 newType.setDescription(typedefDescription);
805 newType.setReference(typedef.getReference());
806 newType.setSchemaPath((List) typedef.getPath().getPathFromRoot());
807 newType.setModuleName(moduleName);
814 private static GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto, final Restrictions r) {
815 GeneratedTOBuilder gtob = new GeneratedTOBuilderImpl(gto.getPackageName(), gto.getName());
816 GeneratedTransferObject parent = gto.getSuperType();
817 if (parent != null) {
818 gtob.setExtendsType(parent);
820 gtob.setRestrictions(r);
821 for (GeneratedProperty gp : gto.getProperties()) {
822 GeneratedPropertyBuilder gpb = gtob.addProperty(gp.getName());
823 gpb.setValue(gp.getValue());
824 gpb.setReadOnly(gp.isReadOnly());
825 gpb.setAccessModifier(gp.getAccessModifier());
826 gpb.setReturnType(gp.getReturnType());
827 gpb.setFinal(gp.isFinal());
828 gpb.setStatic(gp.isStatic());
830 return gtob.toInstance();
834 * Adds a new property with the name <code>propertyName</code> and with type
835 * <code>type</code> to <code>unonGenTransObject</code>.
837 * @param unionGenTransObject
838 * generated TO to which should be property added
840 * JAVA <code>type</code> of the property which should be added
841 * to <code>unionGentransObject</code>
842 * @param propertyName
843 * string with name of property which should be added to
844 * <code>unionGentransObject</code>
846 private static void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type, final String propertyName) {
847 if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
848 final GeneratedPropertyBuilder propBuilder = unionGenTransObject
849 .addProperty(BindingMapping.getPropertyName(propertyName));
850 propBuilder.setReturnType(type);
852 unionGenTransObject.addEqualsIdentity(propBuilder);
853 unionGenTransObject.addHashIdentity(propBuilder);
854 unionGenTransObject.addToStringProperty(propBuilder);
859 * Wraps code which handle case when union subtype is also of the type
860 * <code>UnionType</code>.
862 * In this case the new generated TO is created for union subtype (recursive
864 * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, UnionTypeDefinition,
865 * String, SchemaNode, SchemaContext, Map)}
866 * provideGeneratedTOBuilderForUnionTypeDef} and in parent TO builder
867 * <code>parentUnionGenTOBuilder</code> is created property which type is
868 * equal to new generated TO.
870 * @param parentUnionGenTOBuilder
871 * generated TO builder to which is the property with the child
872 * union subtype added
873 * @param basePackageName
874 * string with the name of the module package
875 * @param unionSubtype
876 * type definition which represents union subtype
877 * @return list of generated TO builders. The number of the builders can be
878 * bigger one due to recursive call of
879 * <code>provideGeneratedTOBuildersForUnionTypeDef</code> method.
881 private List<GeneratedTOBuilder> resolveUnionSubtypeAsUnion(final GeneratedTOBuilder
882 parentUnionGenTOBuilder, final UnionTypeDefinition unionSubtype, final String basePackageName,
883 final SchemaNode parentNode, final SchemaContext schemaContext, final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
885 final String newTOBuilderName = provideAvailableNameForGenTOBuilder(parentUnionGenTOBuilder.getName());
886 final List<GeneratedTOBuilder> subUnionGenTOBUilders = provideGeneratedTOBuildersForUnionTypeDef(
887 basePackageName, unionSubtype, newTOBuilderName, parentNode, schemaContext, genTypeDefsContextMap);
889 final GeneratedPropertyBuilder propertyBuilder;
890 propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingMapping.getPropertyName(newTOBuilderName));
891 propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
892 parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
893 parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
895 return subUnionGenTOBUilders;
899 * Converts output list of generated TO builders to one TO builder (first
900 * from list) which contains the remaining builders as its enclosing TO.
902 * @param basePackageName
903 * string with name of package to which the module belongs
905 * type definition which should be of type
906 * <code>UnionTypeDefinition</code>
908 * string with name for generated TO
909 * @return generated TO builder with the list of enclosed generated TO
912 private GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
913 final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode, final SchemaContext
914 schemaContext, final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
916 final List<GeneratedTOBuilder> builders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
917 typedef, typeDefName, parentNode, schemaContext, genTypeDefsContextMap);
918 Preconditions.checkState(!builders.isEmpty(), "No GeneratedTOBuilder objects generated from union %s", typedef);
920 final GeneratedTOBuilder resultTOBuilder = builders.remove(0);
921 for (GeneratedTOBuilder genTOBuilder : builders) {
922 resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
925 resultTOBuilder.addProperty("value").setReturnType(Types.CHAR_ARRAY);
926 return resultTOBuilder;
930 * Wraps code which handle case when union subtype is of the type
931 * <code>ExtendedType</code>.
933 * If TO for this type already exists it is used for the creation of the
934 * property in <code>parentUnionGenTOBuilder</code>. In other case the base
935 * type is used for the property creation.
937 * @param parentUnionGenTOBuilder
938 * generated TO builder in which new property is created
939 * @param unionSubtype
940 * type definition of the <code>ExtendedType</code> type which
941 * represents union subtype
942 * @param regularExpressions
943 * list of strings with the regular expressions
945 * parent Schema Node for Extended Subtype
948 private static void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder, final
949 TypeDefinition<?> unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode,
950 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
952 final String unionTypeName = unionSubtype.getQName().getLocalName();
953 final Type genTO = findGenTO(unionTypeName, unionSubtype, schemaContext, genTypeDefsContextMap);
955 updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
957 final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
958 if (unionTypeName.equals(baseType.getQName().getLocalName())) {
959 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
961 if (javaType != null) {
962 updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
965 if (baseType instanceof StringTypeDefinition) {
966 regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
972 * Returns string which contains the same value as <code>name</code> but
973 * integer suffix is incremented by one. If <code>name</code> contains no
974 * number suffix then number 1 is added.
977 * string with name of augmented node
978 * @return string with the number suffix incremented by one (or 1 is added)
980 private static String provideAvailableNameForGenTOBuilder(final String name) {
981 Matcher mtch = NUMBERS_PATTERN.matcher(name);
983 final int newSuffix = Integer.valueOf(name.substring(mtch.start())) + 1;
984 return name.substring(0, mtch.start()) + newSuffix;
991 * Searches for generated TO for <code>searchedTypeDef</code> type
992 * definition in {@link #genTypeDefsContextMap genTypeDefsContextMap}
994 * @param searchedTypeName
995 * string with name of <code>searchedTypeDef</code>
996 * @return generated TO for <code>searchedTypeDef</code> or
997 * <code>null</code> it it doesn't exist
999 private static Type findGenTO(final String searchedTypeName, final SchemaNode parentNode,
1000 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
1002 final Module typeModule = findParentModule(schemaContext, parentNode);
1003 if (typeModule != null && typeModule.getName() != null) {
1004 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(typeModule.getName());
1005 final Map<String, Type> genTOs = modulesByDate.get(typeModule.getRevision());
1006 if (genTOs != null) {
1007 return genTOs.get(searchedTypeName);
1014 * Adds enumeration to <code>typeBuilder</code>. The enumeration data are
1015 * taken from <code>enumTypeDef</code>.
1017 * @param enumTypeDef
1018 * enumeration type definition is source of enumeration data for
1019 * <code>typeBuilder</code>
1021 * string with the name of enumeration
1022 * @param typeBuilder
1023 * generated type builder to which is enumeration added
1024 * @return enumeration type which contains enumeration data form
1025 * <code>enumTypeDef</code>
1026 * @throws IllegalArgumentException
1028 * <li>if <code>enumTypeDef</code> equals null</li>
1029 * <li>if enum values of <code>enumTypeDef</code> equal null</li>
1030 * <li>if Q name of <code>enumTypeDef</code> equal null</li>
1031 * <li>if name of <code>enumTypeDef</code> equal null</li>
1032 * <li>if name of <code>typeBuilder</code> equal null</li>
1036 private static Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef, final String enumName, final GeneratedTypeBuilderBase<?> typeBuilder) {
1037 Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
1038 Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
1039 "Local Name in EnumTypeDefinition QName cannot be NULL!");
1040 Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
1042 final String enumerationName = BindingMapping.getClassName(enumName);
1044 final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
1045 final String enumTypedefDescription = encodeAngleBrackets(enumTypeDef.getDescription());
1046 enumBuilder.setDescription(enumTypedefDescription);
1047 enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
1048 return enumBuilder.toInstance(enumBuilder);
1051 private static boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode,
1052 final SchemaContext schemaContext) {
1053 final SchemaNode leafRefValueNode;
1054 final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
1055 final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(leafRefXPath.toString()
1056 .replaceAll("\\[(.*?)\\]", ""), leafRefXPath.isAbsolute());
1058 ///// skip leafrefs in augments - they're checked once augments are resolved
1059 final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
1060 boolean isAugmenting = false;
1061 DataNodeContainer current = null;
1062 DataSchemaNode dataChildByName;
1064 while (iterator.hasNext() && !isAugmenting) {
1065 final QName next = iterator.next();
1066 if (current == null) {
1067 dataChildByName = schemaContext.getDataChildByName(next);
1069 dataChildByName = current.getDataChildByName(next);
1071 if (dataChildByName != null) {
1072 isAugmenting = dataChildByName.isAugmenting();
1076 if (dataChildByName instanceof DataNodeContainer) {
1077 current = (DataNodeContainer) dataChildByName;
1085 Module parentModule = getParentModule(parentNode, schemaContext);
1086 if (!leafRefStrippedXPath.isAbsolute()) {
1087 leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
1088 parentNode, leafRefStrippedXPath);
1090 leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath);
1092 return (leafRefValueNode != null) && leafRefValueNode.equals(parentNode);