From 9134ff50aac46ce533308d3e44cbdc3db00d0865 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Fri, 27 Jul 2018 01:17:26 +0200 Subject: [PATCH] Detect and repair identity/grouping/typedef conflicts We are mapping four distinct YANG namespaces onto a single Java namespace, which is bound to cause conflicts. Define a hierarchy of priorities (data, typedef, grouping, identity) and rename types when a conflict is detected. JIRA: MDSAL-332 Change-Id: I8f6e5987b2057fba5b7d1534c7688725547a146c Signed-off-by: Robert Varga --- .../generator/impl/AbstractTypeGenerator.java | 45 ++++++--- .../generator/impl/BindingGeneratorImpl.java | 56 ++++++++++- .../generator/impl/CodegenTypeGenerator.java | 6 +- .../binding/generator/impl/ModuleContext.java | 92 +++++++++++++++++-- .../impl/RenameMappingException.java | 47 ++++++++++ .../generator/impl/RuntimeTypeGenerator.java | 5 +- .../yang/types/AbstractTypeProvider.java | 17 +++- .../yang/types/CodegenTypeProvider.java | 12 ++- .../yang/types/RuntimeTypeProvider.java | 11 ++- .../binding/generator/impl/Mdsal332Test.java | 38 ++++++++ .../impl/TypeProviderIntegrationTest.java | 3 +- .../yang/types/TypeProviderImplTest.java | 2 +- .../binding/yang/types/TypeProviderTest.java | 30 ++++-- .../src/test/resources/mdsal332.yang | 21 +++++ 14 files changed, 338 insertions(+), 47 deletions(-) create mode 100644 binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RenameMappingException.java create mode 100644 binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal332Test.java create mode 100644 binding/mdsal-binding-generator-impl/src/test/resources/mdsal332.yang diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java index a70b7cf959..306726b674 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java @@ -177,9 +177,16 @@ abstract class AbstractTypeGenerator { */ private final SchemaContext schemaContext; - AbstractTypeGenerator(final SchemaContext context, final AbstractTypeProvider typeProvider) { + /** + * Holds renamed elements. + */ + private final Map renames; + + AbstractTypeGenerator(final SchemaContext context, final AbstractTypeProvider typeProvider, + final Map renames) { this.schemaContext = requireNonNull(context); this.typeProvider = requireNonNull(typeProvider); + this.renames = requireNonNull(renames); final List contextModules = ModuleDependencySort.sort(schemaContext.getModules()); final List contexts = new ArrayList<>(contextModules.size()); @@ -253,7 +260,7 @@ abstract class AbstractTypeGenerator { if (typedef != null) { final Type type = typeProvider.generatedTypeForExtendedDefinitionType(typedef, typedef); if (type != null) { - context.addTypedefType(typedef.getPath(), type); + context.addTypedefType(typedef, type); context.addTypeToSchema(type,typedef); } } @@ -616,15 +623,25 @@ abstract class AbstractTypeGenerator { if (identity == null) { return; } - final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(JavaTypeName.create( - packageNameForGeneratedType(context.modulePackageName(), identity.getPath()), - BindingMapping.getClassName(identity.getQName()))); + + JavaTypeName name = renames.get(identity); + if (name == null) { + name = JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), identity.getPath()), + BindingMapping.getClassName(identity.getQName())); + } + + final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(name); final Set baseIdentities = identity.getBaseIdentities(); if (!baseIdentities.isEmpty()) { for (IdentitySchemaNode baseIdentity : baseIdentities) { - final QName qname = baseIdentity.getQName(); - final GeneratedTransferObject gto = typeProvider.newGeneratedTOBuilder(JavaTypeName.create( - BindingMapping.getRootPackageName(qname.getModule()), BindingMapping.getClassName(qname))).build(); + JavaTypeName base = renames.get(baseIdentity); + if (base == null) { + final QName qname = baseIdentity.getQName(); + base = JavaTypeName.create(BindingMapping.getRootPackageName(qname.getModule()), + BindingMapping.getClassName(qname)); + } + + final GeneratedTransferObject gto = typeProvider.newGeneratedTOBuilder(base).build(); newType.addImplementsType(gto); } } else { @@ -639,7 +656,7 @@ abstract class AbstractTypeGenerator { qnameConstant(newType, JavaTypeName.create(context.modulePackageName(), BindingMapping.MODULE_INFO_CLASS_NAME), identity.getQName().getLocalName()); - context.addIdentityType(identity.getQName(), newType); + context.addIdentityType(identity, newType); } private static Constant qnameConstant(final GeneratedTypeBuilderBase toBuilder, @@ -667,7 +684,7 @@ abstract class AbstractTypeGenerator { // node of grouping is resolved to the method. final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(context, grouping); annotateDeprecatedIfNecessary(grouping.getStatus(), genType); - context.addGroupingType(grouping.getPath(), genType); + context.addGroupingType(grouping, genType); resolveDataSchemaNodes(context, genType, genType, grouping.getChildNodes()); groupingsToGenTypes(context, grouping.getGroupings()); processUsesAugments(grouping, context); @@ -1679,8 +1696,12 @@ abstract class AbstractTypeGenerator { */ private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode, final Type baseInterface, final ModuleContext context) { - final GeneratedTypeBuilder it = addRawInterfaceDefinition( - JavaTypeName.create(packageName, BindingMapping.getClassName(schemaNode.getQName())), schemaNode); + JavaTypeName name = renames.get(schemaNode); + if (name == null) { + name = JavaTypeName.create(packageName, BindingMapping.getClassName(schemaNode.getQName())); + } + + final GeneratedTypeBuilder it = addRawInterfaceDefinition(name, schemaNode); it.addImplementsType(baseInterface); if (!(schemaNode instanceof GroupingDefinition)) { diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingGeneratorImpl.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingGeneratorImpl.java index 89f5182c28..b53ec144f6 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingGeneratorImpl.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingGeneratorImpl.java @@ -10,16 +10,27 @@ package org.opendaylight.mdsal.binding.generator.impl; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import org.opendaylight.mdsal.binding.generator.api.BindingGenerator; import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeGenerator; import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeTypes; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.model.api.Type; +import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; +import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; +import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class BindingGeneratorImpl implements BindingGenerator, BindingRuntimeGenerator { + private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class); + /** * Resolves generated types from context schema nodes only for * modules specified in modules @@ -52,17 +63,58 @@ public class BindingGeneratorImpl implements BindingGenerator, BindingRuntimeGen public List generateTypes(final SchemaContext context, final Set modules) { checkContext(context); checkArgument(modules != null, "Set of Modules cannot be NULL."); - return new CodegenTypeGenerator(context).toTypes(modules); + + final Map renames = new IdentityHashMap<>(); + for (;;) { + try { + return new CodegenTypeGenerator(context, renames).toTypes(modules); + } catch (RenameMappingException e) { + rename(renames, e); + } + } } @Override public BindingRuntimeTypes generateTypeMapping(final SchemaContext context) { checkContext(context); - return new RuntimeTypeGenerator(context).toTypeMapping(); + + final Map renames = new IdentityHashMap<>(); + for (;;) { + try { + return new RuntimeTypeGenerator(context, renames).toTypeMapping(); + } catch (RenameMappingException e) { + rename(renames, e); + } + } } private static void checkContext(final SchemaContext context) { checkArgument(context != null, "Schema Context reference cannot be NULL."); checkState(context.getModules() != null, "Schema Context does not contain defined modules."); } + + private static void rename(final Map renames, final RenameMappingException e) { + final JavaTypeName name = e.getName(); + final SchemaNode def = e.getDefinition(); + final JavaTypeName existing = renames.get(def); + if (existing != null) { + throw new IllegalStateException("Attempted to relocate " + def + " to " + name + ", already remapped to " + + existing, e); + } + + final String suffix; + if (def instanceof IdentitySchemaNode) { + suffix = "$I"; + } else if (def instanceof GroupingDefinition) { + suffix = "$G"; + } else if (def instanceof TypeDefinition) { + suffix = "$T"; + } else { + throw new IllegalStateException("Unhandled remapping of " + def + " at " + name, e); + } + + final JavaTypeName newName = name.createSibling(name.simpleName() + suffix); + renames.put(def, newName); + LOG.debug("Restarting code generation after remapping {} to {}", name, newName); + } } diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java index 2432f89053..f9a4e2d9bc 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java @@ -11,8 +11,10 @@ import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.enc import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder; @@ -26,8 +28,8 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; final class CodegenTypeGenerator extends AbstractTypeGenerator { - CodegenTypeGenerator(final SchemaContext context) { - super(context, new CodegenTypeProvider(context)); + CodegenTypeGenerator(final SchemaContext context, final Map renames) { + super(context, new CodegenTypeProvider(context, renames), renames); } List toTypes(final Set modules) { diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/ModuleContext.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/ModuleContext.java index 02ca4c4934..872529db75 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/ModuleContext.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/ModuleContext.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import javax.annotation.concurrent.NotThreadSafe; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder; @@ -32,13 +33,21 @@ import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode; import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus; +import org.opendaylight.yangtools.yang.model.api.GroupingDefinition; +import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode; import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.NotificationDefinition; +import org.opendaylight.yangtools.yang.model.api.OperationDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @NotThreadSafe public final class ModuleContext { + private static final Logger LOG = LoggerFactory.getLogger(ModuleContext.class); + private final BiMap typeToAugmentation = HashBiMap.create(); private final Map childNodes = new HashMap<>(); private final Map groupings = new HashMap<>(); @@ -54,6 +63,9 @@ public final class ModuleContext { private final Map typedefs = new HashMap<>(); private final Module module; + // Conflict mapping + private final Map nameMapping = new HashMap<>(); + private GeneratedTypeBuilder moduleNode; private String modulePackageName; @@ -137,25 +149,39 @@ public final class ModuleContext { genTOs.add(b); } - public void addChildNodeType(final SchemaNode p, final GeneratedTypeBuilder b) { - childNodes.put(p.getPath(), b); - typeToSchema.put(b,p); + public void addChildNodeType(final SchemaNode def, final GeneratedTypeBuilder b) { + checkNamingConflict(def, b.getIdentifier()); + childNodes.put(def.getPath(), b); + typeToSchema.put(b, def); } - public void addGroupingType(final SchemaPath p, final GeneratedTypeBuilder b) { - groupings.put(p, b); + public void addGroupingType(final GroupingDefinition def, final GeneratedTypeBuilder b) { + checkNamingConflict(def, b.getIdentifier()); + groupings.put(def.getPath(), b); } - public void addTypedefType(final SchemaPath p, final Type t) { - typedefs.put(p, t); + public void addTypedefType(final TypeDefinition def, final Type t) { + final JavaTypeName name = t.getIdentifier(); + final SchemaNode existingDef = nameMapping.putIfAbsent(name, def); + if (existingDef != null) { + if (!(existingDef instanceof TypeDefinition)) { + throw resolveNamingConfict(existingDef, def, name); + } + + // This seems to be fine + LOG.debug("GeneratedType conflict between {} and {} on {}", def, existingDef, name); + } + + typedefs.put(def.getPath(), t); } public void addCaseType(final SchemaPath p, final GeneratedTypeBuilder b) { cases.put(p, b); } - public void addIdentityType(final QName name,final GeneratedTypeBuilder b) { - identities.put(name, b); + public void addIdentityType(final IdentitySchemaNode def, final GeneratedTypeBuilder b) { + checkNamingConflict(def, b.getIdentifier()); + identities.put(def.getQName(), b); } public void addTopLevelNodeType(final GeneratedTypeBuilder b) { @@ -242,4 +268,52 @@ public final class ModuleContext { return innerTypes.get(path); } + private void checkNamingConflict(final SchemaNode def, final JavaTypeName name) { + final SchemaNode existingDef = nameMapping.putIfAbsent(name, def); + if (existingDef != null) { + if (def.equals(existingDef)) { + if (LOG.isDebugEnabled()) { + // TODO: this should not really be happening + LOG.debug("Duplicate definition on {} as {}", name, def, new Throwable()); + } + } else { + throw resolveNamingConfict(existingDef, def, name); + } + } + } + + private static IllegalStateException resolveNamingConfict(final SchemaNode existing, final SchemaNode incoming, + final JavaTypeName name) { + if (existing instanceof IdentitySchemaNode) { + if (incoming instanceof GroupingDefinition || incoming instanceof TypeDefinition + || incoming instanceof DataSchemaNode || incoming instanceof NotificationDefinition + || incoming instanceof OperationDefinition) { + return new RenameMappingException(name, existing); + } + } else if (existing instanceof GroupingDefinition) { + if (incoming instanceof IdentitySchemaNode) { + return new RenameMappingException(name, incoming); + } + if (incoming instanceof TypeDefinition || incoming instanceof DataSchemaNode + || incoming instanceof NotificationDefinition || incoming instanceof OperationDefinition) { + return new RenameMappingException(name, existing); + } + } else if (existing instanceof TypeDefinition) { + if (incoming instanceof GroupingDefinition || incoming instanceof IdentitySchemaNode) { + return new RenameMappingException(name, incoming); + } + if (incoming instanceof DataSchemaNode || incoming instanceof NotificationDefinition + || incoming instanceof OperationDefinition) { + return new RenameMappingException(name, existing); + } + } else { + if (incoming instanceof GroupingDefinition || incoming instanceof IdentitySchemaNode + || incoming instanceof TypeDefinition) { + return new RenameMappingException(name, incoming); + } + } + + return new IllegalStateException(String.format("Unhandled GeneratedType conflict between %s and %s on %s", + incoming, existing, name)); + } } diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RenameMappingException.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RenameMappingException.java new file mode 100644 index 0000000000..c3ba3f6b8e --- /dev/null +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RenameMappingException.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.generator.impl; + +import static java.util.Objects.requireNonNull; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; + +/** + * Exception thrown from ModuleContext when it detects a Java namespace clash between generated classes. This can occur + * because we are mapping multiple YANG namespaces to a single Java class namespace. + * + *

+ * While handling this case via an exception (and related mechanics) is a bit slow, it works with minimal disturbance + * of existing logic. The situation should not be very common and hence it should provide an acceptable performance + * envelope. + * + * @author Robert Varga + */ +@NonNullByDefault +final class RenameMappingException extends IllegalStateException { + private static final long serialVersionUID = 1L; + + private final JavaTypeName name; + private final SchemaNode definition; + + RenameMappingException(final JavaTypeName name, final SchemaNode definition) { + super("Remap " + name + " occupant " + definition); + this.name = requireNonNull(name); + this.definition = requireNonNull(definition); + } + + JavaTypeName getName() { + return name; + } + + SchemaNode getDefinition() { + return definition; + } +} diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java index 7d150fb045..37a3cb404a 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeTypes; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase; @@ -32,8 +33,8 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; final class RuntimeTypeGenerator extends AbstractTypeGenerator { - RuntimeTypeGenerator(final SchemaContext context) { - super(context, new RuntimeTypeProvider(context)); + RuntimeTypeGenerator(final SchemaContext context, final Map renames) { + super(context, new RuntimeTypeProvider(context, renames), renames); } BindingRuntimeTypes toTypeMapping() { diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java index 9078ae72e1..022e7605eb 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java @@ -7,6 +7,7 @@ */ package org.opendaylight.mdsal.binding.yang.types; +import static java.util.Objects.requireNonNull; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath; import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule; @@ -113,19 +114,22 @@ public abstract class AbstractTypeProvider implements TypeProvider { */ private final Map referencedTypes = new HashMap<>(); private final Map> additionalTypes = new HashMap<>(); + private final Map renames; /** * Creates new instance of class TypeProviderImpl. * * @param schemaContext * contains the schema data red from YANG files + * @param renames * @throws IllegalArgumentException * if schemaContext equal null. */ - AbstractTypeProvider(final SchemaContext schemaContext) { + AbstractTypeProvider(final SchemaContext schemaContext, final Map renames) { Preconditions.checkArgument(schemaContext != null, "Schema Context cannot be null!"); this.schemaContext = schemaContext; + this.renames = requireNonNull(renames); resolveTypeDefsFromContext(); } @@ -1168,9 +1172,14 @@ public abstract class AbstractTypeProvider implements TypeProvider { */ private GeneratedTOBuilder typedefToTransferObject(final String basePackageName, final TypeDefinition typedef, final String moduleName) { - final GeneratedTOBuilder newType = newGeneratedTOBuilder(JavaTypeName.create( - BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typedef.getPath()), - BindingMapping.getClassName(typedef.getQName().getLocalName()))); + JavaTypeName name = renames.get(typedef); + if (name == null) { + name = JavaTypeName.create( + BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, typedef.getPath()), + BindingMapping.getClassName(typedef.getQName().getLocalName())); + } + + final GeneratedTOBuilder newType = newGeneratedTOBuilder(name); newType.setSchemaPath(typedef.getPath()); newType.setModuleName(moduleName); addCodegenInformation(newType, typedef); diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/CodegenTypeProvider.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/CodegenTypeProvider.java index cfb5a13154..3401f9a5fe 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/CodegenTypeProvider.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/CodegenTypeProvider.java @@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.yang.types; import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.encodeAngleBrackets; import com.google.common.annotations.Beta; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import java.util.List; @@ -26,6 +27,7 @@ import org.opendaylight.mdsal.binding.model.util.generated.type.builder.CodegenG import org.opendaylight.mdsal.binding.model.util.generated.type.builder.CodegenGeneratedTypeBuilder; import org.opendaylight.yangtools.yang.binding.RegexPatterns; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.ModifierKind; @@ -46,10 +48,16 @@ public class CodegenTypeProvider extends AbstractTypeProvider { * Creates new instance of class TypeProviderImpl. * * @param schemaContext contains the schema data read from YANG files + * @param renames * @throws IllegalArgumentException if schemaContext is null. */ - public CodegenTypeProvider(final SchemaContext schemaContext) { - super(schemaContext); + public CodegenTypeProvider(final SchemaContext schemaContext, final Map renames) { + super(schemaContext, renames); + } + + @VisibleForTesting + CodegenTypeProvider(final SchemaContext schemaContext) { + this(schemaContext, ImmutableMap.of()); } @Override diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/RuntimeTypeProvider.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/RuntimeTypeProvider.java index 19e00f8ed0..3adc7bcb13 100644 --- a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/RuntimeTypeProvider.java +++ b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/RuntimeTypeProvider.java @@ -8,6 +8,7 @@ package org.opendaylight.mdsal.binding.yang.types; import com.google.common.annotations.Beta; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import java.util.List; import java.util.Map; @@ -21,6 +22,7 @@ import org.opendaylight.mdsal.binding.model.util.generated.type.builder.RuntimeE import org.opendaylight.mdsal.binding.model.util.generated.type.builder.RuntimeGeneratedTOBuilder; import org.opendaylight.mdsal.binding.model.util.generated.type.builder.RuntimeGeneratedTypeBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaNode; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition; import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint; @@ -31,8 +33,13 @@ import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint; */ @Beta public final class RuntimeTypeProvider extends AbstractTypeProvider { - public RuntimeTypeProvider(final SchemaContext schemaContext) { - super(schemaContext); + public RuntimeTypeProvider(final SchemaContext schemaContext, final Map renames) { + super(schemaContext, renames); + } + + @VisibleForTesting + RuntimeTypeProvider(final SchemaContext schemaContext) { + this(schemaContext, ImmutableMap.of()); } @Override diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal332Test.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal332Test.java new file mode 100644 index 0000000000..f33b0c05fc --- /dev/null +++ b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal332Test.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.mdsal.binding.generator.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import java.util.List; +import java.util.Set; +import org.junit.Test; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; +import org.opendaylight.mdsal.binding.model.api.Type; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class Mdsal332Test { + + @Test + public void mdsal332Test() { + final SchemaContext context = YangParserTestUtils.parseYangResource("/mdsal332.yang"); + + final List generateTypes = new BindingGeneratorImpl().generateTypes(context); + assertNotNull(generateTypes); + assertEquals(5, generateTypes.size()); + + final List names = generateTypes.stream().map(Type::getIdentifier) + .collect(ImmutableList.toImmutableList()); + final Set uniqueNames = ImmutableSet.copyOf(names); + assertEquals(ImmutableList.copyOf(uniqueNames), names); + } +} diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/TypeProviderIntegrationTest.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/TypeProviderIntegrationTest.java index 0c5d04015a..991d476467 100644 --- a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/TypeProviderIntegrationTest.java +++ b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/TypeProviderIntegrationTest.java @@ -10,6 +10,7 @@ package org.opendaylight.mdsal.binding.generator.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import com.google.common.collect.ImmutableMap; import java.util.Set; import org.junit.Before; import org.junit.BeforeClass; @@ -40,7 +41,7 @@ public class TypeProviderIntegrationTest { @Before public void init() { - provider = new CodegenTypeProvider(context); + provider = new CodegenTypeProvider(context, ImmutableMap.of()); m = context.findModule("test", Revision.of("2013-10-08")).get(); } diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderImplTest.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderImplTest.java index a8fdcbd8f4..0a7a397f54 100644 --- a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderImplTest.java +++ b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderImplTest.java @@ -19,8 +19,8 @@ import static org.mockito.Mockito.reset; import java.net.URI; import java.util.NoSuchElementException; import org.junit.Test; -import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.api.JavaTypeName; +import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.util.generated.type.builder.CodegenGeneratedTypeBuilder; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderTest.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderTest.java index 19bdcf4ca7..e138a62aeb 100644 --- a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderTest.java +++ b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderTest.java @@ -137,7 +137,8 @@ public class TypeProviderTest { provider.javaTypeForSchemaDefinitionType(testTypedef, null, null); } - private static LeafSchemaNode provideLeafNodeFromTopLevelContainer(final Module module, final String containerName, final String leafNodeName) { + private static LeafSchemaNode provideLeafNodeFromTopLevelContainer(final Module module, final String containerName, + final String leafNodeName) { final QName containerNode = QName.create(module.getQNameModule(), containerName); final DataSchemaNode rootNode = module.getDataChildByName(containerNode); assertNotNull("Container foo is not present in root of module "+ module.getName(), rootNode); @@ -151,7 +152,8 @@ public class TypeProviderTest { return (LeafSchemaNode) node; } - private static LeafListSchemaNode provideLeafListNodeFromTopLevelContainer(final Module module, final String containerName, final String leafListNodeName) { + private static LeafListSchemaNode provideLeafListNodeFromTopLevelContainer(final Module module, + final String containerName, final String leafListNodeName) { final QName containerNode = QName.create(module.getQNameModule(), containerName); final DataSchemaNode rootNode = module.getDataChildByName(containerNode); assertNotNull("Container foo is not present in root of module " + module.getName(), rootNode); @@ -168,7 +170,8 @@ public class TypeProviderTest { @Test public void javaTypeForSchemaDefinitionExtTypeTest() { final TypeProvider provider = new CodegenTypeProvider(this.schemaContext); - final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "foo", "yang-int8-type"); + final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "foo", + "yang-int8-type"); final TypeDefinition leafType = leaf.getType(); final Type result = provider.javaTypeForSchemaDefinitionType(leafType, leaf); @@ -177,7 +180,8 @@ public class TypeProviderTest { final GeneratedTransferObject genTO = (GeneratedTransferObject) result; assertEquals("base-yang-types", genTO.getModuleName()); - assertEquals("org.opendaylight.yang.gen.v1.urn.opendaylight.org.test.base.yang.types.rev140914", genTO.getPackageName()); + assertEquals("org.opendaylight.yang.gen.v1.urn.opendaylight.org.test.base.yang.types.rev140914", + genTO.getPackageName()); assertEquals("YangInt8", genTO.getName()); assertEquals(1, genTO.getProperties().size()); } @@ -185,7 +189,8 @@ public class TypeProviderTest { @Test public void javaTypeForSchemaDefinitionRestrictedExtTypeTest() { final TypeProvider provider = new CodegenTypeProvider(this.schemaContext); - final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "foo", "restricted-int8-type"); + final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "foo", + "restricted-int8-type"); final TypeDefinition leafType = leaf.getType(); final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(leafType); @@ -195,7 +200,8 @@ public class TypeProviderTest { assertTrue(result instanceof GeneratedTransferObject); final GeneratedTransferObject genTO = (GeneratedTransferObject) result; - assertEquals("org.opendaylight.yang.gen.v1.urn.opendaylight.org.test.base.yang.types.rev140914", genTO.getPackageName()); + assertEquals("org.opendaylight.yang.gen.v1.urn.opendaylight.org.test.base.yang.types.rev140914", + genTO.getPackageName()); assertEquals("YangInt8Restricted", genTO.getName()); assertEquals(1, genTO.getProperties().size()); final Optional> rangeConstraints = genTO.getRestrictions().getRangeConstraint(); @@ -211,7 +217,8 @@ public class TypeProviderTest { final AbstractTypeProvider provider = new RuntimeTypeProvider(this.schemaContext); final Module testTypeProvider = resolveModule("test-type-provider"); - final TypeDefinition emptyPatternString = resolveTypeDefinitionFromModule(testTypeProvider, "empty-pattern-string"); + final TypeDefinition emptyPatternString = resolveTypeDefinitionFromModule(testTypeProvider, + "empty-pattern-string"); assertNotNull(emptyPatternString); final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(emptyPatternString); @@ -427,7 +434,8 @@ public class TypeProviderTest { @Test public void javaTypeForSchemaDefinitionForExtUnionWithSimpleTypesTest() { final TypeProvider provider = new RuntimeTypeProvider(this.schemaContext); - final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "use-of-unions", "simple-int-types-union"); + final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "use-of-unions", + "simple-int-types-union"); final TypeDefinition leafType = leaf.getType(); final Type result = provider.javaTypeForSchemaDefinitionType(leafType, leaf); @@ -440,7 +448,8 @@ public class TypeProviderTest { @Test public void javaTypeForSchemaDefinitionForExtComplexUnionWithInnerUnionTypesTest() { final TypeProvider provider = new RuntimeTypeProvider(this.schemaContext); - final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "use-of-unions", "complex-union"); + final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "use-of-unions", + "complex-union"); final TypeDefinition leafType = leaf.getType(); final Type result = provider.javaTypeForSchemaDefinitionType(leafType, leaf); @@ -453,7 +462,8 @@ public class TypeProviderTest { @Test public void javaTypeForSchemaDefinitionForExtUnionWithInnerUnionAndSimpleTypeTest() { final TypeProvider provider = new RuntimeTypeProvider(this.schemaContext); - final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "use-of-unions", "complex-string-int-union"); + final LeafSchemaNode leaf = provideLeafNodeFromTopLevelContainer(this.testTypeProviderModule, "use-of-unions", + "complex-string-int-union"); final TypeDefinition leafType = leaf.getType(); final Type result = provider.javaTypeForSchemaDefinitionType(leafType, leaf); diff --git a/binding/mdsal-binding-generator-impl/src/test/resources/mdsal332.yang b/binding/mdsal-binding-generator-impl/src/test/resources/mdsal332.yang new file mode 100644 index 0000000000..62aeb0c2bc --- /dev/null +++ b/binding/mdsal-binding-generator-impl/src/test/resources/mdsal332.yang @@ -0,0 +1,21 @@ +module mdsal332 { + namespace "mdsal332"; + prefix "mdsal332"; + + grouping foo { + + } + + identity foo { + + } + + container foo { + + } + + typedef foo { + type string; + } +} + -- 2.36.6