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) {
165 public Map<String, Map<Date, Map<String, Type>>> getGenTypeDefsContextMap() {
166 return genTypeDefsContextMap;
170 * Passes through all modules and through all its type definitions and
171 * convert it to generated types.
173 * The modules are firstly sorted by mutual dependencies. The modules are
174 * sequentially passed. All type definitions of a module are at the
175 * beginning sorted so that type definition with less amount of references
176 * to other type definition are processed first.<br />
177 * For each module is created mapping record in the map
178 * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap}
179 * which map current module name to the map which maps type names to
180 * returned types (generated types).
183 private void resolveTypeDefsFromContext(final SchemaContext schemaContext, Map<String, Map<Date, Map<String,
184 Type>>> genTypeDefsContextMap, Map<Module, Set<Type>> additionalTypes) {
186 final Set<Module> modules = schemaContext.getModules();
187 Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
188 final Module[] modulesArray = new Module[modules.size()];
190 for (Module modul : modules) {
191 modulesArray[i++] = modul;
193 final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
196 for (final Module module : modulesSortedByDependency) {
197 Map<Date, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
198 if (dateTypeMap == null) {
199 dateTypeMap = new HashMap<>();
201 dateTypeMap.put(module.getRevision(), Collections.emptyMap());
202 genTypeDefsContextMap.put(module.getName(), dateTypeMap);
205 modulesSortedByDependency.stream().filter(module -> module != null).forEach(module -> {
206 final String basePackageName = getRootPackageName(module);
207 final List<TypeDefinition<?>> typeDefinitions = getAllTypedefs(module);
208 final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
209 if (listTypeDefinitions != null) {
210 for (final TypeDefinition<?> typedef : listTypeDefinitions) {
211 typedefToGeneratedType(basePackageName, module, typedef, genTypeDefsContextMap,
212 additionalTypes, schemaContext);
219 * Converts <code>typeDefinition</code> to concrete JAVA <code>Type</code>.
221 * @param typeDefinition
222 * type definition which should be converted to JAVA
224 * @return JAVA <code>Type</code> which represents
225 * <code>typeDefinition</code>
226 * @throws IllegalArgumentException
228 * <li>if <code>typeDefinition</code> equal null</li>
229 * <li>if Q name of <code>typeDefinition</code></li>
230 * <li>if name of <code>typeDefinition</code></li>
233 public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
234 Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
235 Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
236 "Type Definitions Local Name cannot be NULL!");
238 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
239 if (!(baseTypeDef instanceof LeafrefTypeDefinition) && !(baseTypeDef instanceof IdentityrefTypeDefinition)) {
240 final Module module = findParentModule(schemaContext, parentNode);
242 if (module != null) {
243 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
244 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
245 if (genTOs != null) {
246 return genTOs.get(typeDefinition.getQName().getLocalName());
254 * Puts <code>refType</code> to map with key <code>refTypePath</code>
257 * schema path used as the map key
259 * type which represents the map value
260 * @throws IllegalArgumentException
262 * <li>if <code>refTypePath</code> equal null</li>
263 * <li>if <code>refType</code> equal null</li>
267 public void putReferencedType(final SchemaPath refTypePath, final Type refType) {
268 Preconditions.checkArgument(refTypePath != null,
269 "Path reference of Enumeration Type Definition cannot be NULL!");
270 Preconditions.checkArgument(refType != null, "Reference to Enumeration Type cannot be NULL!");
271 referencedTypes.put(refTypePath, refType);
275 * Converts <code>typeDef</code> which should be of the type
276 * <code>BitsTypeDefinition</code> to <code>GeneratedTOBuilder</code>.
278 * All the bits of the typeDef are added to returning generated TO as
281 * @param basePackageName
282 * string with name of package to which the module belongs
284 * type definition from which is the generated TO builder created
286 * string with the name for generated TO builder
287 * @return generated TO builder which represents <code>typeDef</code>
288 * @throws IllegalArgumentException
290 * <li>if <code>typeDef</code> equals null</li>
291 * <li>if <code>basePackageName</code> equals null</li>
294 public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName, final
295 TypeDefinition<?> typeDef, final String typeDefName, final String moduleName) {
297 Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
298 Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
300 if (typeDef instanceof BitsTypeDefinition) {
301 BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
303 final String typeName = BindingMapping.getClassName(typeDefName);
304 final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
305 final String typedefDescription = encodeAngleBrackets(typeDef.getDescription());
307 genTOBuilder.setDescription(typedefDescription);
308 genTOBuilder.setReference(typeDef.getReference());
309 genTOBuilder.setSchemaPath((List) typeDef.getPath().getPathFromRoot());
310 genTOBuilder.setModuleName(moduleName);
311 genTOBuilder.setBaseType(typeDef);
313 final List<Bit> bitList = bitsTypeDefinition.getBits();
314 GeneratedPropertyBuilder genPropertyBuilder;
315 for (final Bit bit : bitList) {
316 String name = bit.getName();
317 genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
318 genPropertyBuilder.setReadOnly(true);
319 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
321 genTOBuilder.addEqualsIdentity(genPropertyBuilder);
322 genTOBuilder.addHashIdentity(genPropertyBuilder);
323 genTOBuilder.addToStringProperty(genPropertyBuilder);
332 * Converts <code>typedef</code> to generated TO with
333 * <code>typeDefName</code>. Every union type from <code>typedef</code> is
334 * added to generated TO builder as property.
336 * @param basePackageName
337 * string with name of package to which the module belongs
339 * type definition which should be of type
340 * <code>UnionTypeDefinition</code>
342 * string with name for generated TO
343 * @return generated TO builder which represents <code>typedef</code>
344 * @throws NullPointerException
346 * <li>if <code>basePackageName</code> is null</li>
347 * <li>if <code>typedef</code> is null</li>
348 * <li>if Qname of <code>typedef</code> is null</li>
351 public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
352 final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode, final SchemaContext
353 schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
354 Preconditions.checkNotNull(basePackageName, "Base Package Name cannot be NULL!");
355 Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
356 Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
358 final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
359 final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
360 final Module module = findParentModule(schemaContext, parentNode);
362 final GeneratedTOBuilderImpl unionGenTOBuilder;
363 if (typeDefName != null && !typeDefName.isEmpty()) {
364 final String typeName = BindingMapping.getClassName(typeDefName);
365 unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
366 final String typedefDescription = encodeAngleBrackets(typedef.getDescription());
367 unionGenTOBuilder.setDescription(typedefDescription);
368 unionGenTOBuilder.setReference(typedef.getReference());
369 unionGenTOBuilder.setSchemaPath((List) typedef.getPath().getPathFromRoot());
370 unionGenTOBuilder.setModuleName(module.getName());
372 unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef, module.getName());
375 generatedTOBuilders.add(unionGenTOBuilder);
376 unionGenTOBuilder.setIsUnion(true);
377 final List<String> regularExpressions = new ArrayList<>();
378 for (final TypeDefinition<?> unionType : unionTypes) {
379 final String unionTypeName = unionType.getQName().getLocalName();
380 if (unionType.getBaseType() != null) {
381 resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, regularExpressions,
382 parentNode, schemaContext, genTypeDefsContextMap);
383 } else if (unionType instanceof UnionTypeDefinition) {
384 generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionTypeDefinition) unionType,
385 basePackageName, parentNode, schemaContext, genTypeDefsContextMap));
386 } else if (unionType instanceof EnumTypeDefinition) {
387 final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
388 unionTypeName, unionGenTOBuilder);
389 updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
391 final Type javaType = javaTypeForSchemaDefType(unionType, parentNode, null, schemaContext,
392 genTypeDefsContextMap);
393 updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
396 if (!regularExpressions.isEmpty()) {
397 addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
400 //storeGenTO(typedef, unionGenTOBuilder, parentNode);
402 return generatedTOBuilders;
405 public Map<Module, Set<Type>> getAdditionalTypes() {
406 return additionalTypes;
409 public static void addUnitsToGenTO(final GeneratedTOBuilder to, final String units) {
410 if (!Strings.isNullOrEmpty(units)) {
411 to.addConstant(Types.STRING, "Units", "\"" + units + "\"");
412 GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("UNITS");
413 prop.setReturnType(Types.STRING);
414 to.addToStringProperty(prop);
418 private Type javaTypeForSchemaDefType(final TypeDefinition<?> typeDefinition, final SchemaNode
419 parentNode, final Restrictions r, final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
420 Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
421 String typedefName = typeDefinition.getQName().getLocalName();
422 Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
424 // Deal with base types
425 if (typeDefinition.getBaseType() == null) {
426 // We have to deal with differing handling of decimal64. The old parser used a fixed Decimal64 type
427 // and generated an enclosing ExtendedType to hold any range constraints. The new parser instantiates
428 // a base type which holds these constraints.
429 if (typeDefinition instanceof DecimalTypeDefinition) {
430 final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode, r);
436 // Deal with leafrefs/identityrefs
437 Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode, schemaContext, genTypeDefsContextMap);
442 ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition, parentNode);
444 LOG.debug("Failed to resolve Java type for {}", typeDefinition);
450 Type returnType = javaTypeForExtendedType(typeDefinition, schemaContext, genTypeDefsContextMap);
451 if (r != null && returnType instanceof GeneratedTransferObject) {
452 GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
453 Module module = findParentModule(schemaContext, parentNode);
454 String basePackageName = BindingMapping.getRootPackageName(module);
455 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typeDefinition
456 .getPath(), BindingNamespaceType.Typedef);
457 String genTOName = BindingMapping.getClassName(typedefName);
458 String name = packageName + "." + genTOName;
459 if (!(returnType.getFullyQualifiedName().equals(name))) {
460 returnType = shadedTOWithRestrictions(gto, r);
468 * @param basePackageName
469 * string with name of package to which the module belongs
471 * string with the name of the module for to which the
472 * <code>typedef</code> belongs
474 * type definition of the node for which should be creted JAVA
475 * <code>Type</code> (usually generated TO)
476 * @return JAVA <code>Type</code> representation of <code>typedef</code> or
477 * <code>null</code> value if <code>basePackageName</code> or
478 * <code>modulName</code> or <code>typedef</code> or Q name of
479 * <code>typedef</code> equals <code>null</code>
481 private Type typedefToGeneratedType(final String basePackageName, final Module module, final
482 TypeDefinition<?> typedef, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap, Map<Module,
483 Set<Type>> additionalTypes, final SchemaContext schemaContext) {
484 final String moduleName = module.getName();
485 final Date moduleRevision = module.getRevision();
486 if ((basePackageName != null) && (moduleName != null) && (typedef != null)) {
487 final String typedefName = typedef.getQName().getLocalName();
488 final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
489 if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
490 && !(innerTypeDefinition instanceof IdentityrefTypeDefinition)) {
492 if (innerTypeDefinition.getBaseType() != null) {
493 returnType = provideGeneratedTOFromExtendedType(typedef, innerTypeDefinition, basePackageName,
494 module.getName(), schemaContext, genTypeDefsContextMap);
495 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
496 final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
497 (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef, schemaContext, genTypeDefsContextMap);
498 genTOBuilder.setTypedef(true);
499 genTOBuilder.setIsUnion(true);
500 addUnitsToGenTO(genTOBuilder, typedef.getUnits());
501 makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
502 returnType = genTOBuilder.toInstance();
504 GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
505 genTOBuilder.getName() + "Builder");
506 unionBuilder.setIsUnionBuilder(true);
507 MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
508 method.setReturnType(returnType);
509 method.addParameter(Types.STRING, "defaultValue");
510 method.setAccessModifier(AccessModifier.PUBLIC);
511 method.setStatic(true);
512 Set<Type> types = additionalTypes.get(module);
514 types = Sets.newHashSet(unionBuilder.toInstance());
515 additionalTypes.put(module, types);
517 types.add(unionBuilder.toInstance());
519 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
520 // enums are automatically Serializable
521 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
522 // TODO units for typedef enum
523 returnType = provideTypeForEnum(enumTypeDef, typedefName, typedef, schemaContext);
524 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
525 final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
526 final GeneratedTOBuilder genTOBuilder =
527 provideGeneratedTOBuilderForBitsTypeDefinition(
528 basePackageName, bitsTypeDefinition, typedefName, module.getName());
529 genTOBuilder.setTypedef(true);
530 addUnitsToGenTO(genTOBuilder, typedef.getUnits());
531 makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
532 returnType = genTOBuilder.toInstance();
534 final Type javaType = javaTypeForSchemaDefType(innerTypeDefinition, typedef, null,
535 schemaContext, genTypeDefsContextMap);
536 returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType, module.getName());
538 if (returnType != null) {
539 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(moduleName);
540 Map<String, Type> typeMap = modulesByDate.get(moduleRevision);
541 if (typeMap != null) {
542 if (typeMap.isEmpty()) {
543 typeMap = new HashMap<>(4);
544 modulesByDate.put(moduleRevision, typeMap);
546 typeMap.put(typedefName, returnType);
556 * Returns JAVA <code>Type</code> for instances of the type
557 * <code>ExtendedType</code>.
559 * @param typeDefinition
560 * type definition which is converted to JAVA <code>Type</code>
561 * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
563 private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition, final SchemaContext
564 schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
566 final String typedefName = typeDefinition.getQName().getLocalName();
567 final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
568 Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition, schemaContext, genTypeDefsContextMap);
569 if (returnType == null) {
570 if (baseTypeDef instanceof EnumTypeDefinition) {
571 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
572 returnType = provideTypeForEnum(enumTypeDef, typedefName, typeDefinition, schemaContext);
574 final Module module = findParentModule(schemaContext, typeDefinition);
575 Restrictions r = BindingGeneratorUtil.getRestrictions(typeDefinition);
576 if (module != null) {
577 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(module.getName());
578 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
579 if (genTOs != null) {
580 returnType = genTOs.get(typedefName);
582 if (returnType == null) {
583 returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
584 baseTypeDef, typeDefinition, r);
593 * Returns JAVA <code>Type</code> for instances of the type
594 * <code>LeafrefTypeDefinition</code> or
595 * <code>IdentityrefTypeDefinition</code>.
597 * @param typeDefinition
598 * type definition which is converted to JAVA <code>Type</code>
599 * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
601 private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
602 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
603 if (typeDefinition instanceof LeafrefTypeDefinition) {
604 final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
605 if (isLeafRefSelfReference(leafref, parentNode, schemaContext)) {
606 throw new YangValidationException("Leafref " + leafref.toString() + " is referencing itself, incoming" +
607 " StackOverFlowError detected.");
609 return provideTypeForLeafref(leafref, parentNode, schemaContext, genTypeDefsContextMap);
610 } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
611 final IdentityrefTypeDefinition idref = (IdentityrefTypeDefinition) typeDefinition;
612 return provideTypeForIdentityref(idref, schemaContext);
619 * Converts <code>leafrefType</code> to JAVA <code>Type</code>.
621 * The path of <code>leafrefType</code> is followed to find referenced node
622 * and its <code>Type</code> is returned.
625 * leafref type definition for which is the type sought
626 * @return JAVA <code>Type</code> of data schema node which is referenced in
627 * <code>leafrefType</code>
628 * @throws IllegalArgumentException
630 * <li>if <code>leafrefType</code> equal null</li>
631 * <li>if path statement of <code>leafrefType</code> equal null</li>
635 public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode,
636 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
638 Type returnType = null;
639 Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
641 Preconditions.checkArgument(leafrefType.getPathStatement() != null,
642 "The Path Statement for Leafref Type Definition cannot be NULL!");
644 final RevisionAwareXPath xpath = leafrefType.getPathStatement();
645 final String strXPath = xpath.toString();
647 if (strXPath != null) {
648 if (strXPath.indexOf('[') == -1) {
649 final Module module = findParentModule(schemaContext, parentNode);
650 Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
652 final SchemaNode dataNode;
653 if (xpath.isAbsolute()) {
654 dataNode = findDataSchemaNode(schemaContext, module, xpath);
656 dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
658 Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
659 strXPath, getParentModule(parentNode, schemaContext).getName(), parentNode.getQName().getModule());
661 if (leafContainsEnumDefinition(dataNode)) {
662 returnType = referencedTypes.get(dataNode.getPath());
663 } else if (leafListContainsEnumDefinition(dataNode)) {
664 returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
666 returnType = resolveTypeFromDataSchemaNode(dataNode, schemaContext, genTypeDefsContextMap);
669 returnType = Types.typeForClass(Object.class);
672 Preconditions.checkArgument(returnType != null, "Failed to find leafref target: %s in module %s (%s)",
673 strXPath, getParentModule(parentNode, schemaContext).getName(), parentNode.getQName().getModule());
678 * Checks if <code>dataNode</code> is <code>LeafSchemaNode</code> and if it
679 * so then checks if it is of type <code>EnumTypeDefinition</code>.
682 * data schema node for which is checked if it is leaf and if it
684 * @return boolean value
686 * <li>true - if <code>dataNode</code> is leaf of type enumeration</li>
687 * <li>false - other cases</li>
690 private static boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
691 if (dataNode instanceof LeafSchemaNode) {
692 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
693 //CompatUtils is not used here anymore
694 if (leaf.getType() instanceof EnumTypeDefinition) {
702 * Checks if <code>dataNode</code> is <code>LeafListSchemaNode</code> and if
703 * it so then checks if it is of type <code>EnumTypeDefinition</code>.
706 * data schema node for which is checked if it is leaflist and if
708 * @return boolean value
710 * <li>true - if <code>dataNode</code> is leaflist of type
712 * <li>false - other cases</li>
715 private static boolean leafListContainsEnumDefinition(final SchemaNode dataNode) {
716 if (dataNode instanceof LeafListSchemaNode) {
717 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
718 if (leafList.getType() instanceof EnumTypeDefinition) {
726 * Converts <code>dataNode</code> to JAVA <code>Type</code>.
729 * contains information about YANG type
730 * @return JAVA <code>Type</code> representation of <code>dataNode</code>
732 private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode, final SchemaContext schemaContext,
733 Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
734 Type returnType = null;
735 if (dataNode != null) {
736 if (dataNode instanceof LeafSchemaNode) {
737 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
738 //not using CompatUtils here anymore
739 final TypeDefinition<?> type = leaf.getType();
740 returnType = javaTypeForSchemaDefType(type, leaf, null, schemaContext, genTypeDefsContextMap);
741 } else if (dataNode instanceof LeafListSchemaNode) {
742 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
743 returnType = javaTypeForSchemaDefType(leafList.getType(), leafList, null, schemaContext, genTypeDefsContextMap);
750 * Seeks for identity reference <code>idref</code> the JAVA
751 * <code>type</code>.<br />
755 * If identy which is referenced via <code>idref</code> has name <b>Idn</b>
756 * then returning type is <b>{@code Class<? extends Idn>}</b></i>
759 * identityref type definition for which JAVA <code>Type</code>
761 * @return JAVA <code>Type</code> of the identity which is refrenced through
764 private static Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref, final SchemaContext schemaContext) {
765 //TODO: incompatibility with Binding spec v2, get first or only one
766 QName baseIdQName = idref.getIdentities().iterator().next().getQName();
767 Module module = schemaContext.findModuleByNamespaceAndRevision(baseIdQName.getNamespace(),
768 baseIdQName.getRevision());
769 IdentitySchemaNode identity = null;
770 for (IdentitySchemaNode id : module.getIdentities()) {
771 if (id.getQName().equals(baseIdQName)) {
775 Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
777 final String basePackageName = BindingMapping.getRootPackageName(module);
778 final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath
779 (), BindingNamespaceType.Typedef);
780 final String genTypeName = BindingMapping.getClassName(identity.getQName());
782 Type baseType = Types.typeForClass(Class.class);
783 Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
784 return Types.parameterizedTypeFor(baseType, paramType);
788 * Converts <code>typedef</code> to the generated TO builder.
790 * @param basePackageName
791 * string with name of package to which the module belongs
793 * type definition from which is the generated TO builder created
794 * @return generated TO builder which contains data from
795 * <code>typedef</code> and <code>basePackageName</code>
797 private static GeneratedTOBuilderImpl typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef, final String moduleName) {
799 final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typedef.getPath
800 (), BindingNamespaceType.Typedef);
801 final String typeDefTOName = typedef.getQName().getLocalName();
803 if ((packageName != null) && (typeDefTOName != null)) {
804 final String genTOName = BindingMapping.getClassName(typeDefTOName);
805 final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName);
806 final String typedefDescription = encodeAngleBrackets(typedef.getDescription());
808 newType.setDescription(typedefDescription);
809 newType.setReference(typedef.getReference());
810 newType.setSchemaPath((List) typedef.getPath().getPathFromRoot());
811 newType.setModuleName(moduleName);
818 private static GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto, final Restrictions r) {
819 GeneratedTOBuilder gtob = new GeneratedTOBuilderImpl(gto.getPackageName(), gto.getName());
820 GeneratedTransferObject parent = gto.getSuperType();
821 if (parent != null) {
822 gtob.setExtendsType(parent);
824 gtob.setRestrictions(r);
825 for (GeneratedProperty gp : gto.getProperties()) {
826 GeneratedPropertyBuilder gpb = gtob.addProperty(gp.getName());
827 gpb.setValue(gp.getValue());
828 gpb.setReadOnly(gp.isReadOnly());
829 gpb.setAccessModifier(gp.getAccessModifier());
830 gpb.setReturnType(gp.getReturnType());
831 gpb.setFinal(gp.isFinal());
832 gpb.setStatic(gp.isStatic());
834 return gtob.toInstance();
838 * Adds a new property with the name <code>propertyName</code> and with type
839 * <code>type</code> to <code>unonGenTransObject</code>.
841 * @param unionGenTransObject
842 * generated TO to which should be property added
844 * JAVA <code>type</code> of the property which should be added
845 * to <code>unionGentransObject</code>
846 * @param propertyName
847 * string with name of property which should be added to
848 * <code>unionGentransObject</code>
850 private static void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type, final String propertyName) {
851 if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
852 final GeneratedPropertyBuilder propBuilder = unionGenTransObject
853 .addProperty(BindingMapping.getPropertyName(propertyName));
854 propBuilder.setReturnType(type);
856 unionGenTransObject.addEqualsIdentity(propBuilder);
857 unionGenTransObject.addHashIdentity(propBuilder);
858 unionGenTransObject.addToStringProperty(propBuilder);
863 * Wraps code which handle case when union subtype is also of the type
864 * <code>UnionType</code>.
866 * In this case the new generated TO is created for union subtype (recursive
868 * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, UnionTypeDefinition,
869 * String, SchemaNode, SchemaContext, Map)}
870 * provideGeneratedTOBuilderForUnionTypeDef} and in parent TO builder
871 * <code>parentUnionGenTOBuilder</code> is created property which type is
872 * equal to new generated TO.
874 * @param parentUnionGenTOBuilder
875 * generated TO builder to which is the property with the child
876 * union subtype added
877 * @param basePackageName
878 * string with the name of the module package
879 * @param unionSubtype
880 * type definition which represents union subtype
881 * @return list of generated TO builders. The number of the builders can be
882 * bigger one due to recursive call of
883 * <code>provideGeneratedTOBuildersForUnionTypeDef</code> method.
885 private List<GeneratedTOBuilder> resolveUnionSubtypeAsUnion(final GeneratedTOBuilder
886 parentUnionGenTOBuilder, final UnionTypeDefinition unionSubtype, final String basePackageName,
887 final SchemaNode parentNode, final SchemaContext schemaContext, final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
889 final String newTOBuilderName = provideAvailableNameForGenTOBuilder(parentUnionGenTOBuilder.getName());
890 final List<GeneratedTOBuilder> subUnionGenTOBUilders = provideGeneratedTOBuildersForUnionTypeDef(
891 basePackageName, unionSubtype, newTOBuilderName, parentNode, schemaContext, genTypeDefsContextMap);
893 final GeneratedPropertyBuilder propertyBuilder;
894 propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingMapping.getPropertyName(newTOBuilderName));
895 propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
896 parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
897 parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
899 return subUnionGenTOBUilders;
903 * Converts output list of generated TO builders to one TO builder (first
904 * from list) which contains the remaining builders as its enclosing TO.
906 * @param basePackageName
907 * string with name of package to which the module belongs
909 * type definition which should be of type
910 * <code>UnionTypeDefinition</code>
912 * string with name for generated TO
913 * @return generated TO builder with the list of enclosed generated TO
916 private GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
917 final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode, final SchemaContext
918 schemaContext, final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
920 final List<GeneratedTOBuilder> builders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
921 typedef, typeDefName, parentNode, schemaContext, genTypeDefsContextMap);
922 Preconditions.checkState(!builders.isEmpty(), "No GeneratedTOBuilder objects generated from union %s", typedef);
924 final GeneratedTOBuilder resultTOBuilder = builders.remove(0);
925 for (GeneratedTOBuilder genTOBuilder : builders) {
926 resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
929 resultTOBuilder.addProperty("value").setReturnType(Types.CHAR_ARRAY);
930 return resultTOBuilder;
934 * Wraps code which handle case when union subtype is of the type
935 * <code>ExtendedType</code>.
937 * If TO for this type already exists it is used for the creation of the
938 * property in <code>parentUnionGenTOBuilder</code>. In other case the base
939 * type is used for the property creation.
941 * @param parentUnionGenTOBuilder
942 * generated TO builder in which new property is created
943 * @param unionSubtype
944 * type definition of the <code>ExtendedType</code> type which
945 * represents union subtype
946 * @param regularExpressions
947 * list of strings with the regular expressions
949 * parent Schema Node for Extended Subtype
952 private static void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder, final
953 TypeDefinition<?> unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode,
954 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
956 final String unionTypeName = unionSubtype.getQName().getLocalName();
957 final Type genTO = findGenTO(unionTypeName, unionSubtype, schemaContext, genTypeDefsContextMap);
959 updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
961 final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
962 if (unionTypeName.equals(baseType.getQName().getLocalName())) {
963 final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
965 if (javaType != null) {
966 updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
969 if (baseType instanceof StringTypeDefinition) {
970 regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
976 * Returns string which contains the same value as <code>name</code> but
977 * integer suffix is incremented by one. If <code>name</code> contains no
978 * number suffix then number 1 is added.
981 * string with name of augmented node
982 * @return string with the number suffix incremented by one (or 1 is added)
984 private static String provideAvailableNameForGenTOBuilder(final String name) {
985 Matcher mtch = NUMBERS_PATTERN.matcher(name);
987 final int newSuffix = Integer.valueOf(name.substring(mtch.start())) + 1;
988 return name.substring(0, mtch.start()) + newSuffix;
995 * Searches for generated TO for <code>searchedTypeDef</code> type
996 * definition in {@link #genTypeDefsContextMap genTypeDefsContextMap}
998 * @param searchedTypeName
999 * string with name of <code>searchedTypeDef</code>
1000 * @return generated TO for <code>searchedTypeDef</code> or
1001 * <code>null</code> it it doesn't exist
1003 private static Type findGenTO(final String searchedTypeName, final SchemaNode parentNode,
1004 final SchemaContext schemaContext, Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap) {
1006 final Module typeModule = findParentModule(schemaContext, parentNode);
1007 if (typeModule != null && typeModule.getName() != null) {
1008 final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(typeModule.getName());
1009 final Map<String, Type> genTOs = modulesByDate.get(typeModule.getRevision());
1010 if (genTOs != null) {
1011 return genTOs.get(searchedTypeName);
1018 * Adds enumeration to <code>typeBuilder</code>. The enumeration data are
1019 * taken from <code>enumTypeDef</code>.
1021 * @param enumTypeDef
1022 * enumeration type definition is source of enumeration data for
1023 * <code>typeBuilder</code>
1025 * string with the name of enumeration
1026 * @param typeBuilder
1027 * generated type builder to which is enumeration added
1028 * @return enumeration type which contains enumeration data form
1029 * <code>enumTypeDef</code>
1030 * @throws IllegalArgumentException
1032 * <li>if <code>enumTypeDef</code> equals null</li>
1033 * <li>if enum values of <code>enumTypeDef</code> equal null</li>
1034 * <li>if Q name of <code>enumTypeDef</code> equal null</li>
1035 * <li>if name of <code>enumTypeDef</code> equal null</li>
1036 * <li>if name of <code>typeBuilder</code> equal null</li>
1040 private static Enumeration addInnerEnumerationToTypeBuilder(final EnumTypeDefinition enumTypeDef, final String enumName, final GeneratedTypeBuilderBase<?> typeBuilder) {
1041 Preconditions.checkArgument(enumTypeDef != null, "EnumTypeDefinition reference cannot be NULL!");
1042 Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
1043 "Local Name in EnumTypeDefinition QName cannot be NULL!");
1044 Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
1046 final String enumerationName = BindingMapping.getClassName(enumName);
1048 final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
1049 final String enumTypedefDescription = encodeAngleBrackets(enumTypeDef.getDescription());
1050 enumBuilder.setDescription(enumTypedefDescription);
1051 enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
1052 return enumBuilder.toInstance(enumBuilder);
1055 private static boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode,
1056 final SchemaContext schemaContext) {
1057 final SchemaNode leafRefValueNode;
1058 final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
1059 final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(leafRefXPath.toString()
1060 .replaceAll("\\[(.*?)\\]", ""), leafRefXPath.isAbsolute());
1062 ///// skip leafrefs in augments - they're checked once augments are resolved
1063 final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
1064 boolean isAugmenting = false;
1065 DataNodeContainer current = null;
1066 DataSchemaNode dataChildByName;
1068 while (iterator.hasNext() && !isAugmenting) {
1069 final QName next = iterator.next();
1070 if (current == null) {
1071 dataChildByName = schemaContext.getDataChildByName(next);
1073 dataChildByName = current.getDataChildByName(next);
1075 if (dataChildByName != null) {
1076 isAugmenting = dataChildByName.isAugmenting();
1080 if (dataChildByName instanceof DataNodeContainer) {
1081 current = (DataNodeContainer) dataChildByName;
1089 Module parentModule = getParentModule(parentNode, schemaContext);
1090 if (!leafRefStrippedXPath.isAbsolute()) {
1091 leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
1092 parentNode, leafRefStrippedXPath);
1094 leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath);
1096 return (leafRefValueNode != null) && leafRefValueNode.equals(parentNode);