From be0728e9f6cf1dd46dd527dfa9c6229a85589366 Mon Sep 17 00:00:00 2001 From: Ladislav Borak Date: Wed, 6 Aug 2014 14:48:49 +0200 Subject: [PATCH] Bug 1478 - Autoboxing support Change-Id: Id9c812f238c16d6bae2894364a366f6781a986e3 Signed-off-by: Ladislav Borak Signed-off-by: Robert Varga --- .../generator/impl/BindingGeneratorImpl.java | 40 ++++++++++++++ .../type/builder/EnumerationBuilderImpl.java | 6 +++ .../type/builder/GeneratedTOBuilderImpl.java | 5 ++ .../builder/GeneratedTypeBuilderImpl.java | 28 ++++++++++ .../java/api/generator/BuilderTemplate.xtend | 54 +++++++++++++++++-- .../compilation/typedef/mod-box.yang | 21 ++++++++ .../sal/binding/model/api/BoxableType.java | 34 ++++++++++++ .../sal/binding/model/api/GeneratedType.java | 2 +- .../type/builder/GeneratedTypeBuilder.java | 17 +++++- .../builder/GeneratedTypeBuilderBase.java | 1 - 10 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang create mode 100644 code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java diff --git a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java index c1fd71df23..b98c48c984 100644 --- a/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java +++ b/code-generator/binding-generator-impl/src/main/java/org/opendaylight/yangtools/sal/binding/generator/impl/BindingGeneratorImpl.java @@ -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 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); } diff --git a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java index cb7f50549e..ae80a51da4 100644 --- a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java +++ b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/EnumerationBuilderImpl.java @@ -342,6 +342,11 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En return values; } + @Override + public boolean isSuitableForBoxing() { + return false; + } + @Override public List getAnnotations() { return annotations; @@ -518,5 +523,6 @@ public final class EnumerationBuilderImpl extends AbstractBaseType implements En public String getModuleName() { return moduleName; } + } } diff --git a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java index 270b04ac81..8d1bcea0e8 100644 --- a/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java +++ b/code-generator/binding-generator-util/src/main/java/org/opendaylight/yangtools/binding/generator/util/generated/type/builder/GeneratedTOBuilderImpl.java @@ -337,5 +337,10 @@ public final class GeneratedTOBuilderImpl extends AbstractGeneratedTypeBuilder 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 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; + } } + } diff --git a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend index d322833ad8..66b72cf9e6 100644 --- a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend +++ b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend @@ -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 index 0000000000..1334298696 --- /dev/null +++ b/code-generator/binding-java-api-generator/src/test/resources/compilation/typedef/mod-box.yang @@ -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 index 0000000000..258c53df07 --- /dev/null +++ b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/BoxableType.java @@ -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, 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(); +} diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java index 0e9b51ee74..ef2fdcdd7e 100644 --- a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java +++ b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/GeneratedType.java @@ -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, diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java index 9756bd2092..ea2ab258e0 100644 --- a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java +++ b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilder.java @@ -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 { /** * Returns the new immutable instance of Generated Type. - * + * * @return the new immutable 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); } diff --git a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java index 628029f028..92874327f5 100644 --- a/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java +++ b/code-generator/binding-model-api/src/main/java/org/opendaylight/yangtools/sal/binding/model/api/type/builder/GeneratedTypeBuilderBase.java @@ -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; -- 2.36.6