Detect and repair identity/grouping/typedef conflicts 54/74554/10
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 26 Jul 2018 23:17:26 +0000 (01:17 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 27 Jul 2018 10:12:07 +0000 (12:12 +0200)
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 <robert.varga@pantheon.tech>
14 files changed:
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingGeneratorImpl.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/ModuleContext.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RenameMappingException.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/CodegenTypeProvider.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/RuntimeTypeProvider.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal332Test.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/TypeProviderIntegrationTest.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderImplTest.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderTest.java
binding/mdsal-binding-generator-impl/src/test/resources/mdsal332.yang [new file with mode: 0644]

index a70b7cf95951ae83ac301c6ae8c7fcf234f14a13..306726b674f6751f58ad51b25efcfb1105fdd46d 100644 (file)
@@ -177,9 +177,16 @@ abstract class AbstractTypeGenerator {
      */
     private final SchemaContext schemaContext;
 
-    AbstractTypeGenerator(final SchemaContext context, final AbstractTypeProvider typeProvider) {
+    /**
+     * Holds renamed elements.
+     */
+    private final Map<SchemaNode, JavaTypeName> renames;
+
+    AbstractTypeGenerator(final SchemaContext context, final AbstractTypeProvider typeProvider,
+            final Map<SchemaNode, JavaTypeName> renames) {
         this.schemaContext = requireNonNull(context);
         this.typeProvider = requireNonNull(typeProvider);
+        this.renames = requireNonNull(renames);
 
         final List<Module> contextModules = ModuleDependencySort.sort(schemaContext.getModules());
         final List<ModuleContext> 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<IdentitySchemaNode> 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)) {
index 89f5182c28552933c2b9c14b3ac97a063d540b08..b53ec144f6e0d373c54a23ea3c16d9f32bd07b46 100644 (file)
@@ -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 <code>context</code> schema nodes only for
      * modules specified in <code>modules</code>
@@ -52,17 +63,58 @@ public class BindingGeneratorImpl implements BindingGenerator, BindingRuntimeGen
     public List<Type> generateTypes(final SchemaContext context, final Set<Module> modules) {
         checkContext(context);
         checkArgument(modules != null, "Set of Modules cannot be NULL.");
-        return new CodegenTypeGenerator(context).toTypes(modules);
+
+        final Map<SchemaNode, JavaTypeName> 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<SchemaNode, JavaTypeName> 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<SchemaNode, JavaTypeName> 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);
+    }
 }
index 2432f8905326ae012b269059aec3596fe5ed5405..f9a4e2d9bcf123f4cc208125cc5c40de79699ebf 100644 (file)
@@ -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<SchemaNode, JavaTypeName> renames) {
+        super(context, new CodegenTypeProvider(context, renames), renames);
     }
 
     List<Type> toTypes(final Set<Module> modules) {
index 02ca4c493432b997dbdae0c666409b2f29b7eb54..872529db7557bb5b849c190b5e33fbc964406d4f 100644 (file)
@@ -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<Type, AugmentationSchemaNode> typeToAugmentation = HashBiMap.create();
     private final Map<SchemaPath, GeneratedTypeBuilder> childNodes = new HashMap<>();
     private final Map<SchemaPath, GeneratedTypeBuilder> groupings = new HashMap<>();
@@ -54,6 +63,9 @@ public final class ModuleContext {
     private final Map<SchemaPath, Type> typedefs = new HashMap<>();
     private final Module module;
 
+    // Conflict mapping
+    private final Map<JavaTypeName, SchemaNode> 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 (file)
index 0000000..c3ba3f6
--- /dev/null
@@ -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.
+ *
+ * <p>
+ * 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;
+    }
+}
index 7d150fb04587d7aa5a2f09c4cc3df5d9aba37d88..37a3cb404a12b9914f29b6e25159d2fea4bc4fa7 100644 (file)
@@ -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<SchemaNode, JavaTypeName> renames) {
+        super(context, new RuntimeTypeProvider(context, renames), renames);
     }
 
     BindingRuntimeTypes toTypeMapping() {
index 9078ae72e132cb6398e1e819437fa29f0c6a3cb7..022e7605eb387744e92632690ad072bcb0514b2f 100644 (file)
@@ -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<SchemaPath, Type> referencedTypes = new HashMap<>();
     private final Map<Module, Set<Type>> additionalTypes = new HashMap<>();
+    private final Map<SchemaNode, JavaTypeName> renames;
 
     /**
      * Creates new instance of class <code>TypeProviderImpl</code>.
      *
      * @param schemaContext
      *            contains the schema data red from YANG files
+     * @param renames
      * @throws IllegalArgumentException
      *             if <code>schemaContext</code> equal null.
      */
-    AbstractTypeProvider(final SchemaContext schemaContext) {
+    AbstractTypeProvider(final SchemaContext schemaContext, final Map<SchemaNode, JavaTypeName> 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);
index cfb5a131542229a82a7329bb9a3db9ae99e76ef1..3401f9a5fe0c20109d5b78ccde964c3f1e1f2601 100644 (file)
@@ -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 <code>TypeProviderImpl</code>.
      *
      * @param schemaContext contains the schema data read from YANG files
+     * @param renames
      * @throws IllegalArgumentException if <code>schemaContext</code> is null.
      */
-    public CodegenTypeProvider(final SchemaContext schemaContext) {
-        super(schemaContext);
+    public CodegenTypeProvider(final SchemaContext schemaContext, final Map<SchemaNode, JavaTypeName> renames) {
+        super(schemaContext, renames);
+    }
+
+    @VisibleForTesting
+    CodegenTypeProvider(final SchemaContext schemaContext) {
+        this(schemaContext, ImmutableMap.of());
     }
 
     @Override
index 19e00f8ed063cedd5b89462928d58c90ea12882a..3adc7bcb135b5fb025e4e6a99b58985c29f57fb7 100644 (file)
@@ -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<SchemaNode, JavaTypeName> 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 (file)
index 0000000..f33b0c0
--- /dev/null
@@ -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<Type> generateTypes = new BindingGeneratorImpl().generateTypes(context);
+        assertNotNull(generateTypes);
+        assertEquals(5, generateTypes.size());
+
+        final List<JavaTypeName> names = generateTypes.stream().map(Type::getIdentifier)
+                .collect(ImmutableList.toImmutableList());
+        final Set<JavaTypeName> uniqueNames = ImmutableSet.copyOf(names);
+        assertEquals(ImmutableList.copyOf(uniqueNames), names);
+    }
+}
index 0c5d04015ab8c01a616eaacc8af2e8c519532fe0..991d476467bfa47f3bd58f91e8f63b72dda51dab 100644 (file)
@@ -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();
     }
 
index a8fdcbd8f4edfaade447ad1cb7e25675732ff216..0a7a397f549985976b4ee781d58356e39dbc56d1 100644 (file)
@@ -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;
index 19bdcf4ca7c2407196721833dfe216b8ff19d912..e138a62aeb58d0ba06a9baabb69e6b70a6a1feb2 100644 (file)
@@ -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<? extends RangeConstraint<?>> 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 (file)
index 0000000..62aeb0c
--- /dev/null
@@ -0,0 +1,21 @@
+module mdsal332 {
+    namespace "mdsal332";
+    prefix "mdsal332";
+
+    grouping foo {
+
+    }
+
+    identity foo {
+
+    }
+
+    container foo {
+
+    }
+
+    typedef foo {
+        type string;
+    }
+}
+