From 404cde59571b8340099e90990bfdd29dedba8899 Mon Sep 17 00:00:00 2001 From: Ivan Martiniak Date: Tue, 12 Jul 2022 11:18:39 +0200 Subject: [PATCH] Add BitsTypeObject The new interface BitsTypeObject, besides grouping bits type objects, helps clarify which bits are restricted. Method validValues() returns constant containing valid bits. The logic of the creation of this constant is contained in the AbstractTypeObjectGenerator.java. Method getValue() was included in this interface and its generation was adjusted for restricted and standard bits types separately. Related test classes were adjusted as well. JIRA: MDSAL-743 Change-Id: I74820e7a041e137902c774655517ea8d1e4bccd9 Signed-off-by: Ivan Martiniak Signed-off-by: Robert Varga --- .../reactor/AbstractTypeObjectGenerator.java | 13 ++-- .../impl/reactor/TypedefGenerator.java | 31 +++++++++ .../impl/Mdsal406TypeObjectTest.java | 7 +- .../java/api/generator/BaseTemplate.xtend | 6 +- .../java/api/generator/ClassTemplate.xtend | 66 ++++++++++++++----- .../api/generator/TypedefCompilationTest.java | 6 +- .../mdsal/binding/model/ri/BindingTypes.java | 2 + .../mdsal/binding/model/ri/TypeConstants.java | 17 +++-- .../mdsal/binding/model/ri/Types.java | 13 ++++ .../opendaylight-of-migration-test-model.yang | 14 +++- .../yang/binding/BitsTypeObject.java | 32 +++++++++ 11 files changed, 170 insertions(+), 37 deletions(-) create mode 100644 binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BitsTypeObject.java diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java index 44b7892cac..048cf5a1d8 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java @@ -589,8 +589,8 @@ abstract class AbstractTypeObjectGenerator, R final boolean isTypedef = this instanceof TypedefGenerator; final QName arg = type.argument(); if (TypeDefinitions.BITS.equals(arg)) { - return createBits(builderFactory, statement(), typeName(), currentModule(), extractTypeDefinition(), - isTypedef); + return createBits(builderFactory, statement(), typeName(), currentModule(), + (BitsTypeDefinition) extractTypeDefinition(), isTypedef); } else if (TypeDefinitions.ENUMERATION.equals(arg)) { return createEnumeration(builderFactory, statement(), typeName(), currentModule(), (EnumTypeDefinition) extractTypeDefinition()); @@ -608,14 +608,14 @@ abstract class AbstractTypeObjectGenerator, R private static @NonNull GeneratedTransferObject createBits(final TypeBuilderFactory builderFactory, final EffectiveStatement definingStatement, final JavaTypeName typeName, final ModuleGenerator module, - final TypeDefinition typedef, final boolean isTypedef) { + final BitsTypeDefinition typedef, final boolean isTypedef) { final GeneratedTOBuilder builder = builderFactory.newGeneratedTOBuilder(typeName); builder.setTypedef(isTypedef); - builder.addImplementsType(BindingTypes.TYPE_OBJECT); + builder.addImplementsType(BindingTypes.BITS_TYPE_OBJECT); builder.setBaseType(typedef); YangSourceDefinition.of(module.statement(), definingStatement).ifPresent(builder::setYangSourceDefinition); - for (Bit bit : ((BitsTypeDefinition) typedef).getBits()) { + for (Bit bit : typedef.getBits()) { final String name = bit.getName(); GeneratedPropertyBuilder genPropertyBuilder = builder.addProperty(BindingMapping.getPropertyName(name)); genPropertyBuilder.setReadOnly(true); @@ -625,6 +625,7 @@ abstract class AbstractTypeObjectGenerator, R builder.addHashIdentity(genPropertyBuilder); builder.addToStringProperty(genPropertyBuilder); } + builder.addConstant(Types.immutableSetTypeFor(Types.STRING), TypeConstants.VALID_NAMES_NAME, typedef); // builder.setSchemaPath(typedef.getPath()); builder.setModuleName(module.statement().argument().getLocalName()); @@ -733,7 +734,7 @@ abstract class AbstractTypeObjectGenerator, R } else if (TypeDefinitions.BITS.equals(subName)) { final GeneratedTransferObject subBits = createBits(builderFactory, definingStatement, typeName.createEnclosed(BindingMapping.getClassName(localName), "$"), module, - subType.getTypeDefinition(), isTypedef); + (BitsTypeDefinition) subType.getTypeDefinition(), isTypedef); builder.addEnclosingTransferObject(subBits); generatedType = subBits; } else if (TypeDefinitions.IDENTITYREF.equals(subName)) { diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java index d523b60f8d..6b0e06271a 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java @@ -8,6 +8,7 @@ package org.opendaylight.mdsal.binding.generator.impl.reactor; import static com.google.common.base.Verify.verify; +import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import java.util.ArrayList; @@ -19,9 +20,12 @@ 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.GeneratedTOBuilder; import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase; +import org.opendaylight.mdsal.binding.model.ri.TypeConstants; +import org.opendaylight.mdsal.binding.model.ri.Types; import org.opendaylight.mdsal.binding.runtime.api.TypedefRuntimeType; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement; +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition; import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; /** @@ -92,10 +96,37 @@ final class TypedefGenerator extends AbstractTypeObjectGenerator generateTypes = DefaultBindingGenerator.generateFor(CONTEXT); assertNotNull(generateTypes); @@ -62,8 +63,8 @@ public class Mdsal406TypeObjectTest { assertNotNull(typedefType.getImplements()); Type objectType = typedefType.getImplements().stream() .filter(type -> type.getFullyQualifiedName() - .equals("org.opendaylight.yangtools.yang.binding.TypeObject")).findAny().get(); - assertEquals(TYPE_OBJECT, objectType); + .equals("org.opendaylight.yangtools.yang.binding.BitsTypeObject")).findAny().get(); + assertEquals(BITS_TYPE_OBJECT, objectType); } @Test diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BaseTemplate.xtend b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BaseTemplate.xtend index 0afcd92f20..d57fab88a5 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BaseTemplate.xtend +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BaseTemplate.xtend @@ -86,7 +86,11 @@ abstract class BaseTemplate extends JavaFileTemplate { ''' final protected def getterMethodName(GeneratedProperty field) { - return '''«BindingMapping.GETTER_PREFIX»«field.name.toFirstUpper»''' + return field.name.getterMethodName + } + + final protected def getterMethodName(String propName) { + return '''«BindingMapping.GETTER_PREFIX»«propName.toFirstUpper»''' } /** diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend index 8b59b92460..df7be75af6 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend @@ -23,12 +23,13 @@ import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT32_TYPE import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT64_TYPE import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT8_TYPE import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.SCALAR_TYPE_OBJECT +import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.BITS_TYPE_OBJECT import static org.opendaylight.mdsal.binding.model.ri.Types.STRING; import static extension org.apache.commons.text.StringEscapeUtils.escapeJava -import static extension org.opendaylight.mdsal.binding.model.ri.BindingTypes.isBitsType import com.google.common.base.Preconditions import com.google.common.collect.ImmutableList +import com.google.common.collect.ImmutableSet import com.google.common.collect.Lists import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import java.util.ArrayList @@ -51,6 +52,7 @@ import org.opendaylight.mdsal.binding.model.ri.TypeConstants import org.opendaylight.mdsal.binding.model.ri.Types import org.opendaylight.mdsal.binding.spec.naming.BindingMapping import org.opendaylight.yangtools.yang.common.Empty +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition /** * Template for generating JAVA class. @@ -73,6 +75,11 @@ class ClassTemplate extends BaseTemplate { */ static val BOOLEAN = JavaTypeName.create(Boolean) + /** + * {@code com.google.common.collect.ImmutableSet} as a JavaTypeName. + */ + static val IMMUTABLE_SET = JavaTypeName.create(ImmutableSet) + protected val List properties protected val List finalProperties protected val List parentProperties @@ -179,8 +186,8 @@ class ClassTemplate extends BaseTemplate { «propertyMethods» - «IF genTO.isBitsType» - «generateGetValueForBitsTypeDef» + «IF isBitsTypeObject» + «validNamesAndValues» «ENDIF» «generateHashCode» @@ -208,6 +215,19 @@ class ClassTemplate extends BaseTemplate { return false } + def private isBitsTypeObject() { + var wlk = genTO + while (wlk !== null) { + for (impl : wlk.implements) { + if (BITS_TYPE_OBJECT.identifier.equals(impl.identifier)) { + return true + } + } + wlk = wlk.superType + } + return false + } + def private defaultProperties() ''' «FOR field : properties SEPARATOR "\n"» «field.getterMethod» @@ -224,20 +244,29 @@ class ClassTemplate extends BaseTemplate { } ''' - /** - * Template method which generates the method getValue() for typedef, - * which base type is BitsDefinition. - * - * @return string with the getValue() method definition in JAVA format - */ - def protected generateGetValueForBitsTypeDef() ''' + def private validNamesAndValues() { + for (c : consts) { + if (TypeConstants.VALID_NAMES_NAME.equals(c.name)) { + return validNamesAndValues(c.value as BitsTypeDefinition) + } + } + return "" + } - public boolean[] getValue() { - return new boolean[]{ - «FOR property: genTO.properties SEPARATOR ','» - «property.fieldName» - «ENDFOR» - }; + def private validNamesAndValues(BitsTypeDefinition typedef) ''' + + @«OVERRIDE.importedName» + public «IMMUTABLE_SET.importedName»<«STRING.importedName»> validNames() { + return «TypeConstants.VALID_NAMES_NAME»; + } + + @«OVERRIDE.importedName» + public boolean[] values() { + return new boolean[] { + «FOR bit : typedef.bits SEPARATOR ','» + «BindingMapping.getPropertyName(bit.name).getterMethodName»() + «ENDFOR» + }; } ''' @@ -519,6 +548,11 @@ class ClassTemplate extends BaseTemplate { private static final String[] «Constants.MEMBER_REGEX_LIST» = { « FOR v : cValue.values SEPARATOR ", "»"«v.escapeJava»"«ENDFOR» }; «ENDIF» + «ELSEIF TypeConstants.VALID_NAMES_NAME.equals(c.name)» + «val cValue = c.value as BitsTypeDefinition» + «val immutableSet = IMMUTABLE_SET.importedName» + protected static final «immutableSet»<«STRING.importedName»> «TypeConstants.VALID_NAMES_NAME» = «immutableSet».of(« + FOR bit : cValue.bits SEPARATOR ", "»"«bit.name»"«ENDFOR»); «ELSE» «emitConstant(c)» «ENDIF» diff --git a/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/TypedefCompilationTest.java b/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/TypedefCompilationTest.java index 4a7f3f198b..96cc85b4ef 100644 --- a/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/TypedefCompilationTest.java +++ b/binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/TypedefCompilationTest.java @@ -81,16 +81,16 @@ public class TypedefCompilationTest extends BaseCompilationTest { CompilationTestUtils.assertContainsField(bitsExtClass, "_sfmof", boolean.class); CompilationTestUtils.assertContainsField(bitsExtClass, "_sfapc", boolean.class); CompilationTestUtils.assertContainsFieldWithValue(bitsExtClass, "serialVersionUID", Long.TYPE, - -2922917845344851623L, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, + 7934653360983102096L, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class); - assertEquals(8, bitsExtClass.getDeclaredFields().length); + assertEquals(9, bitsExtClass.getDeclaredFields().length); CompilationTestUtils.assertContainsConstructor(bitsExtClass, bitsExtClass); assertEquals(2, bitsExtClass.getConstructors().length); Method defInst = CompilationTestUtils.assertContainsMethod(bitsExtClass, bitsExtClass, "getDefaultInstance", String.class); CompilationTestUtils.assertContainsDefaultMethods(bitsExtClass); - assertEquals(12, bitsExtClass.getDeclaredMethods().length); + assertEquals(13, bitsExtClass.getDeclaredMethods().length); Constructor expectedConstructor = CompilationTestUtils.assertContainsConstructor(bitsExtClass, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class, boolean.class); diff --git a/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/BindingTypes.java b/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/BindingTypes.java index d32bf1c674..7f3607a305 100644 --- a/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/BindingTypes.java +++ b/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/BindingTypes.java @@ -25,6 +25,7 @@ import org.opendaylight.yangtools.yang.binding.Action; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.BitsTypeObject; import org.opendaylight.yangtools.yang.binding.ChildOf; import org.opendaylight.yangtools.yang.binding.ChoiceIn; import org.opendaylight.yangtools.yang.binding.DataContainer; @@ -66,6 +67,7 @@ public final class BindingTypes { public static final ConcreteType RPC_OUTPUT = typeForClass(RpcOutput.class); public static final ConcreteType RPC_SERVICE = typeForClass(RpcService.class); public static final ConcreteType SCALAR_TYPE_OBJECT = typeForClass(ScalarTypeObject.class); + public static final ConcreteType BITS_TYPE_OBJECT = typeForClass(BitsTypeObject.class); public static final ConcreteType INSTANCE_IDENTIFIER = typeForClass(InstanceIdentifier.class); public static final ConcreteType KEYED_INSTANCE_IDENTIFIER = typeForClass(KeyedInstanceIdentifier.class); diff --git a/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/TypeConstants.java b/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/TypeConstants.java index 20928e6c86..0b3ebb3649 100644 --- a/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/TypeConstants.java +++ b/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/TypeConstants.java @@ -8,19 +8,17 @@ package org.opendaylight.mdsal.binding.model.ri; import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.binding.BitsTypeObject; import org.opendaylight.yangtools.yang.binding.ScalarTypeObject; /** * Contains constants used in relations with Type. */ public final class TypeConstants { - /** - * Name or prefix (multiple patterns in builder class as composed with '_' - * and upper case of the field name) of the class constant which holds the map - * of regular expressions that need to be enforced on the string value. - * The map is keyed by Pattern-compatible string and values are XSD-compatible - * strings. + * Name or prefix (multiple patterns in builder class as composed with '_' and upper case of the field name) of the + * class constant which holds the map of regular expressions that need to be enforced on the string value. The map + * is keyed by Pattern-compatible string and values are XSD-compatible strings. */ public static final @NonNull String PATTERN_CONSTANT_NAME = "PATTERN_CONSTANTS"; @@ -30,8 +28,13 @@ public final class TypeConstants { public static final @NonNull String VALUE_PROP = "value"; /** - * Creation of new instance is prohibited. + * Name of the constant holding the names of valid {@code bit}s in a {@link BitsTypeObject}. This constant is + * protected and made accessible via {@link BitsTypeObject#validNames()} and its type matches the return type + * exactly. */ + public static final @NonNull String VALID_NAMES_NAME = "VALID_NAMES"; + private TypeConstants() { + // Hidden on purpose } } diff --git a/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/Types.java b/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/Types.java index 1936f9e3fe..c106468888 100644 --- a/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/Types.java +++ b/binding/mdsal-binding-model-ri/src/main/java/org/opendaylight/mdsal/binding/model/ri/Types.java @@ -13,6 +13,7 @@ import com.google.common.annotations.Beta; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; import java.io.Serializable; import java.util.Arrays; @@ -55,6 +56,7 @@ public final class Types { private static final @NonNull ConcreteType PRIMITIVE_VOID = typeForClass(void.class); private static final @NonNull ConcreteType SERIALIZABLE = typeForClass(Serializable.class); private static final @NonNull ConcreteType SET_TYPE = typeForClass(Set.class); + private static final @NonNull ConcreteType IMMUTABLE_SET_TYPE = typeForClass(ImmutableSet.class); private static final @NonNull ParameterizedType LIST_TYPE_WILDCARD = parameterizedTypeFor(LIST_TYPE); private static final @NonNull ParameterizedType SET_TYPE_WILDCARD = parameterizedTypeFor(SET_TYPE); @@ -181,6 +183,17 @@ public final class Types { return parameterizedTypeFor(SET_TYPE, valueType); } + /** + * Returns an instance of {@link ParameterizedType} describing the typed {@link ImmutableSet}<V> with concrete + * type of value. + * + * @param valueType Value Type + * @return Description of generic type instance of ImmutableSet + */ + public static @NonNull ParameterizedType immutableSetTypeFor(final Type valueType) { + return parameterizedTypeFor(IMMUTABLE_SET_TYPE, valueType); + } + /** * Returns an instance of {@link ParameterizedType} describing the typed {@link Set}<?>. * diff --git a/binding/mdsal-binding-test-model/src/main/yang/opendaylight-of-migration-test-model.yang b/binding/mdsal-binding-test-model/src/main/yang/opendaylight-of-migration-test-model.yang index 0b74a4461f..8d1be665b2 100644 --- a/binding/mdsal-binding-test-model/src/main/yang/opendaylight-of-migration-test-model.yang +++ b/binding/mdsal-binding-test-model/src/main/yang/opendaylight-of-migration-test-model.yang @@ -1,5 +1,5 @@ module opendaylight-of-migration-test-model { - + yang-version 1.1; namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:of-migration-test-model"; prefix of-migration-test; @@ -25,6 +25,18 @@ module opendaylight-of-migration-test-model { } } + typedef derived-bit-flags { + type bit-flags; + } + + typedef restricted-bit-flags { + type derived-bit-flags { + bit FLAG_ONE; + bit FLAG_THREE; + bit FLAG_FIVE; + } + } + typedef custom-enum { type enumeration { enum type1; diff --git a/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BitsTypeObject.java b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BitsTypeObject.java new file mode 100644 index 0000000000..7453ece999 --- /dev/null +++ b/binding/yang-binding/src/main/java/org/opendaylight/yangtools/yang/binding/BitsTypeObject.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 PANTHEON.tech, 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.yangtools.yang.binding; + +import com.google.common.collect.ImmutableSet; +import org.eclipse.jdt.annotation.NonNull; + +/** + * Interface implemented by all {@link TypeObject}s generated for {@code type bits}. + */ +public interface BitsTypeObject extends TypeObject { + /** + * Return the set of strings which are valid {@code bit} names for this type. The iteration order of the returned + * set is required to match effective bit {@code position} assignment. + * + * @return The names of valid bits for this type. + */ + @NonNull ImmutableSet validNames(); + + /** + * Return the bit values. Returned array contains all bits from {@link #validNames()} in the interation order of + * that set. Note that the array is packed, e.g. unassigned positions are skipped over. + * + * @return Array of values. + */ + boolean @NonNull [] values(); +} -- 2.36.6