Bug 1478 - Autoboxing support 44/9744/5
authorLadislav Borak <lborak@cisco.com>
Wed, 6 Aug 2014 12:48:49 +0000 (14:48 +0200)
committerRobert Varga <rovarga@cisco.com>
Sat, 30 Aug 2014 07:36:17 +0000 (09:36 +0200)
Change-Id: Id9c812f238c16d6bae2894364a366f6781a986e3
Signed-off-by: Ladislav Borak <lborak@cisco.com>
Signed-off-by: Robert Varga <rovarga@cisco.com>
code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java
code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTypeBuilderImpl.java
code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend
code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang [new file with mode: 0644]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java [new file with mode: 0644]
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java
code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java

index c1fd71df23a3065cebb6206481f52b184f08a986..b98c48c9844f0b5067aeae72cd1894b9efd43b9c 100644 (file)
@@ -318,23 +318,61 @@ public class BindingGeneratorImpl implements BindingGenerator {
             genCtx.get(module).addChildNodeType(node, genType);
             groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
             processUsesAugments((DataNodeContainer) node, module);
+            if (node.isAddedByUses() || node.isAugmenting())
+                genType.setSuitableForBoxing(false);
         }
         return genType;
     }
 
+    private boolean hasWhenOrMustConstraints(final SchemaNode node) {
+        boolean hasWhenCondition;
+        boolean hasMustConstraints;
+
+        if (node instanceof ContainerSchemaNode) {
+            ContainerSchemaNode contNode = (ContainerSchemaNode)node;
+            hasWhenCondition = contNode.getConstraints().getWhenCondition() != null;
+            hasMustConstraints = !isNullOrEmpty(contNode.getConstraints().getMustConstraints());
+
+            if (hasWhenCondition || hasMustConstraints)
+                return true;
+        }
+        return false;
+    }
+
     private void containerToGenType(final Module module, final String basePackageName,
             final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
+
         if (genType != null) {
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType);
             resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes());
+
+            final String parentName = parent.getName();
+            final String childOfName = childOf.getName();
+
+            if (parent != null && !parent.getName().contains("Data"))
+                genType.setParentType(parent);
+            genType.setSuitableForBoxing(hasOnlyOneChild(node) && !hasWhenOrMustConstraints(node));
+
+            if (parentName.equals(childOfName))
+                genType.setSuitableForBoxing(false);
         }
     }
 
+    private boolean hasOnlyOneChild(final ContainerSchemaNode contNode) {
+        if (!isNullOrEmpty(contNode.getChildNodes()) && contNode.getChildNodes().size() == 1)
+            return true;
+        return false;
+    }
+
     private void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder parent,
             final GeneratedTypeBuilder childOf, final ListSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
+
         if (genType != null) {
+            if (!parent.getName().equals(childOf) && !parent.getName().contains("Data")) {
+                genType.setParentType(parent);
+            }
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), Types.listTypeFor(genType));
 
             final List<String> listKeys = listKeys(node);
@@ -856,6 +894,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         if (targetTypeBuilder == null) {
             throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
         }
+        targetTypeBuilder.setSuitableForBoxing(false);
 
         if (!(targetSchemaNode instanceof ChoiceNode)) {
             String packageName = augmentPackageName;
@@ -1156,6 +1195,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             constructGetter(parent, choiceNode.getQName().getLocalName(), choiceNode.getDescription(),
                     choiceTypeBuilder);
             choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
+            choiceTypeBuilder.setParentType(parent);
             genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
             generateTypesFromChoiceCases(module, basePackageName, choiceTypeBuilder.toInstance(), choiceNode);
         }
index cb7f50549e537e6a24f11e5407f35082b8f970ae..ae80a51da4b19351b95b5de666504cb80549f881 100644 (file)
@@ -342,6 +342,11 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
             return values;
         }
 
+        @Override
+        public boolean isSuitableForBoxing() {
+            return false;
+        }
+
         @Override
         public List<AnnotationType> getAnnotations() {
             return annotations;
@@ -518,5 +523,6 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En
         public String getModuleName() {
             return moduleName;
         }
+
     }
 }
index 270b04ac81161374d337fe03f012d96691939920..8d1bcea0e80be00fd1ccc4bc9923747474b6f076 100644 (file)
@@ -337,5 +337,10 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder<G
         public String getModuleName() {
             return moduleName;
         }
+
+        @Override
+        public boolean isSuitableForBoxing() {
+            return false;
+        }
     }
 }
index 92c5629eab8861674bb2532957d4ab0bb9239256..5b14461dbbd8d029d5af60a323b3c84a2a6d5beb 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.yangtools.binding.generator.util.generated.type.builder;
 
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
+import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 
@@ -18,6 +19,8 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
     private String reference;
     private String moduleName;
     private Iterable<QName> schemaPath;
+    private boolean isSuitableForBoxing;
+    private GeneratedTypeBuilder parentType;
 
     public GeneratedTypeBuilderImpl(final String packageName, final String name) {
         super(packageName, name);
@@ -49,6 +52,21 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         this.reference = reference;
     }
 
+    @Override
+    public void setSuitableForBoxing(boolean value) {
+        this.isSuitableForBoxing = value;
+    }
+
+    @Override
+    public void setParentType(GeneratedTypeBuilder parent) {
+        this.parentType = parent;
+    }
+
+    @Override
+    public Type getParent() {
+        return this.parentType;
+    }
+
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder();
@@ -86,6 +104,8 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         private final String reference;
         private final String moduleName;
         private final Iterable<QName> schemaPath;
+        private final boolean isSuitableForBoxing;
+        private final GeneratedTypeBuilder parentType;
 
         public GeneratedTypeImpl(GeneratedTypeBuilderImpl builder) {
             super(builder);
@@ -94,6 +114,8 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
             this.reference = builder.reference;
             this.moduleName = builder.moduleName;
             this.schemaPath = builder.schemaPath;
+            this.isSuitableForBoxing = builder.isSuitableForBoxing;
+            this.parentType = builder.parentType;
         }
 
         @Override
@@ -115,5 +137,11 @@ public final class GeneratedTypeBuilderImpl extends AbstractGeneratedTypeBuilder
         public String getModuleName() {
             return moduleName;
         }
+
+        @Override
+        public boolean isSuitableForBoxing() {
+            return isSuitableForBoxing;
+        }
     }
+
 }
index d322833ad81ab9c69e8309462779a1f24c1a37fc..66b72cf9e62647a475bc359744bff63b7386f67a 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
 import org.opendaylight.yangtools.sal.binding.model.api.Type
 import org.opendaylight.yangtools.yang.binding.Augmentable
+import org.opendaylight.yangtools.yang.binding.ChildOf
 import org.opendaylight.yangtools.yang.binding.DataObject
 import org.opendaylight.yangtools.yang.binding.Identifiable
 
@@ -225,9 +226,9 @@ class BuilderTemplate extends BaseTemplate {
 
             «generateSetters»
 
-            public «type.name» build() {
-                return new «type.name»«IMPL»(this);
-            }
+            «generateBuildMethod»
+
+            «generateBuildBoxedMethod»
 
             private static final class «type.name»«IMPL» implements «type.name» {
 
@@ -251,6 +252,53 @@ class BuilderTemplate extends BaseTemplate {
         }
     '''
 
+    def private generateBuildMethod() '''
+        public «type.name» build() {
+            return new «type.name»«IMPL»(this);
+        }
+    '''
+
+    def private generateBuildBoxedMethod() {
+        if(type.suitableForBoxing && type.parentType != null && isContainerAndIsNotList(type)) {
+            val parentTypeBuilder = createParentTypeBuilder()
+            if (countMatches(parentTypeBuilder, "org") < 2) {
+                return '''
+                    public «type.parentType.importedName» buildBoxed() {
+                        return new «parentTypeBuilder»().set«type.name»(build()).build();
+                    }
+                '''
+            }
+        }
+        return ''
+    }
+
+    def private int countMatches(String string, String subString) {
+        if (string.nullOrEmpty || subString.nullOrEmpty) {
+            return 0
+        }
+        var int count = 0;
+        var int idx = 0;
+        while ((idx = string.indexOf(subString, idx)) != -1) {
+            count = count + 1;
+            idx = idx + subString.length();
+        }
+        return count;
+    }
+
+    def private createParentTypeBuilder() {
+        return type.parentType.packageName + "." + type.parentType.importedName + "Builder"
+    }
+
+    def private boolean isContainerAndIsNotList(GeneratedType type) {
+        val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))
+        val implementsChildOf = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(ChildOf), type))
+
+        if (implementsChildOf && !isList) {
+            return true
+        }
+        return false;
+    }
+
     /**
      * Generate default constructor and constructor for every implemented interface from uses statements.
      */
diff --git a/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang b/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang
new file mode 100644 (file)
index 0000000..1334298
--- /dev/null
@@ -0,0 +1,21 @@
+
+module mod-box {
+    yang-version 1;
+    namespace "urn:opendaylight:mod:box";
+    prefix "box";
+
+    revision 2014-08-05 {
+   }
+
+       container cont1 {
+           choice choice1 {
+                       case case1 {
+                               container cont2 {
+                                       leaf leaf1 {
+                                               type string;
+                                       }
+                               }
+                       }
+           }
+       }
+}
diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java
new file mode 100644 (file)
index 0000000..258c53d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. 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.yangtools.sal.binding.model.api;
+
+/**
+ * Implementing this interface allows an object to hold information about that if
+ * is generated type suitable for boxing.
+ *
+ * Example:
+ * choice foo-choice {
+ *   case foo-case {
+ *     container foo {
+ *           ...
+ *     }
+ *   }
+ * }
+ *
+ * Suitable type have to implements ChildOf<T>, where !(T instanceof Identifiable) and
+ * T does not place any structural requirements (must/when) on existence/value Foo.
+ */
+public interface BoxableType {
+
+    /**
+     * Check if generated type is suitable for boxing.
+     *
+     * @return true if generated type is suitable for boxing, false otherwise.
+     */
+    boolean isSuitableForBoxing();
+}
index 0e9b51ee741f42bb5952961421d046c7c52efa2a..ef2fdcdd7e6d4e942526937a670a28c5828dccf3 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  * definitions MUST be public, so there is no need to specify the scope of
  * visibility.
  */
-public interface GeneratedType extends Type, DocumentedType {
+public interface GeneratedType extends Type, DocumentedType, BoxableType {
 
     /**
      * Returns the parent type if Generated Type is defined as enclosing type,
index 9756bd209250b207e0689bc841fd1ce5bc185903..ea2ab258e06f12a06e7c2bf8f9ea71bf021f7f39 100644 (file)
@@ -12,16 +12,29 @@ import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
 /**
  * Generated Type Builder interface is helper interface for building and
  * defining the GeneratedType.
- * 
+ *
  * @see GeneratedType
  */
 public interface GeneratedTypeBuilder extends GeneratedTypeBuilderBase<GeneratedTypeBuilder> {
 
     /**
      * Returns the <code>new</code> <i>immutable</i> instance of Generated Type.
-     * 
+     *
      * @return the <code>new</code> <i>immutable</i> instance of Generated Type.
      */
     GeneratedType toInstance();
 
+    /**
+     * Set true if generated type is suitable for boxing, false otherwise.
+     *
+     * @param value
+     */
+    public void setSuitableForBoxing(boolean value);
+
+    /**
+     * Set parent for current generated type.
+     *
+     * @param parent
+     */
+    public void setParentType(GeneratedTypeBuilder parent);
 }
index 628029f02869760998d3f33618832b2f70a428c2..92874327f5e462877294480457ea0c1e91e27e65 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.yangtools.sal.binding.model.api.type.builder;
 
 import java.util.List;
-
 import org.opendaylight.yangtools.sal.binding.model.api.Constant;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.common.QName;