Binding v2 - Export declared regexes to generated code 49/69549/6
authorJie Han <han.jie@zte.com.cn>
Fri, 16 Mar 2018 09:40:24 +0000 (17:40 +0800)
committerRobert Varga <nite@hq.sk>
Mon, 19 Mar 2018 22:06:29 +0000 (22:06 +0000)
- Ported from:
  https://git.opendaylight.org/gerrit/#/c/68916/20

- Split out an constantTemplate which would be reused
  by renderers of class, interface and builder.

- Eliminates TypeConstants and puts PATTERN_CONSTANT_NAME
  etc. in BindingMapping.

Change-Id: Id1c0b70e5dd520d27dc764c290b0d7e7d5b14cec
Signed-off-by: Jie Han <han.jie@zte.com.cn>
14 files changed:
binding2/mdsal-binding2-generator-impl/pom.xml
binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/yang/types/TypeGenHelper.java [changed mode: 0644->0755]
binding2/mdsal-binding2-generator-impl/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/yang/types/TypeProviderImpl.java
binding2/mdsal-binding2-generator-util/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/util/TypeConstants.java [deleted file]
binding2/mdsal-binding2-java-api-generator/pom.xml
binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/javav2/java/api/generator/renderers/BaseRenderer.java
binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/javav2/java/api/generator/renderers/BuilderRenderer.java
binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/javav2/java/api/generator/renderers/ClassRenderer.java
binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/builderTemplate.scala.txt
binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/classTemplateConstructors.scala.txt
binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/classTemplateInitBlock.scala.txt [deleted file]
binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/constantsTemplate.scala.txt [new file with mode: 0644]
binding2/mdsal-binding2-spec/src/main/java/org/opendaylight/mdsal/binding/javav2/spec/runtime/CodeHelpers.java [new file with mode: 0644]
binding2/mdsal-binding2-util/src/main/java/org/opendaylight/mdsal/binding/javav2/util/BindingMapping.java

index a35b2f53ed666da41ab3c6632e4c44b2e97ba398..a9dea98ed85bc4752c064ba34aefc8474b98bab9 100644 (file)
           <artifactId>mockito-core</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-text</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
old mode 100644 (file)
new mode 100755 (executable)
index 3795a23..9e8f58a
@@ -14,7 +14,8 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findP
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -23,10 +24,8 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.TreeMap;
-import org.apache.commons.text.StringEscapeUtils;
 import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
-import org.opendaylight.mdsal.binding.javav2.generator.util.TypeConstants;
 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.EnumerationBuilderImpl;
 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
@@ -214,23 +213,20 @@ final class TypeGenHelper {
      *
      * @param typedef
      *            extended type in which are the pattern constraints sought
-     * @return list of strings which represents the constraint patterns
+     * @return map of strings which represents the constraint patterns
      * @throws IllegalArgumentException
      *             if <code>typedef</code> equals null
      *
      */
-    static List<String> resolveRegExpressionsFromTypedef(final TypeDefinition<?> typedef) {
-        Preconditions.checkArgument(typedef != null, "typedef can't be null");
-
-        final List<PatternConstraint> patternConstraints;
-        if (typedef instanceof StringTypeDefinition) {
-            patternConstraints = ((StringTypeDefinition) typedef).getPatternConstraints();
-        } else {
-            patternConstraints = ImmutableList.of();
+    static Map<String, String> resolveRegExpressionsFromTypedef(final TypeDefinition<?> typedef) {
+        if (!(typedef instanceof StringTypeDefinition)) {
+            return ImmutableMap.of();
         }
 
-        final List<String> regExps = new ArrayList<>(patternConstraints.size());
-        for (final PatternConstraint patternConstraint : patternConstraints) {
+        // TODO: run diff against base ?
+        final List<PatternConstraint> patternConstraints = ((StringTypeDefinition) typedef).getPatternConstraints();
+        final Map<String, String> regExps = Maps.newHashMapWithExpectedSize(patternConstraints.size());
+        for (PatternConstraint patternConstraint : patternConstraints) {
             String regEx = patternConstraint.getJavaPatternString();
 
             // The pattern can be inverted
@@ -239,8 +235,7 @@ final class TypeGenHelper {
                 regEx = applyModifier(optModifier.get(), regEx);
             }
 
-            final String modifiedRegEx = StringEscapeUtils.escapeJava(regEx);
-            regExps.add(modifiedRegEx);
+            regExps.put(regEx, patternConstraint.getRegularExpressionString());
         }
 
         return regExps;
@@ -275,7 +270,7 @@ final class TypeGenHelper {
         final List<TypeDefinition<?>> sortedTypeDefinition = new ArrayList<>();
 
         final Map<Integer, List<TypeDefinition<?>>> typeDefinitionsDepths = new TreeMap<>();
-        for (final TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
+        for (TypeDefinition<?> unsortedTypeDefinition : unsortedTypeDefinitions) {
             final int depth = getTypeDefinitionDepth(unsortedTypeDefinition);
             final List<TypeDefinition<?>> typeDefinitionsConcreteDepth = typeDefinitionsDepths.computeIfAbsent(depth, k -> new ArrayList<>());
             typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
@@ -295,24 +290,13 @@ final class TypeGenHelper {
      * @param genTOBuilder
      *            generated TO builder to which are
      *            <code>regular expressions</code> added
-     * @param regularExpressions
+     * @param expressions
      *            list of string which represent regular expressions
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>genTOBuilder</code> equals null</li>
-     *             <li>if <code>regularExpressions</code> equals null</li>
-     *             </ul>
      */
-    static void addStringRegExAsConstant(final GeneratedTOBuilder genTOBuilder, final List<String> regularExpressions) {
-        if (genTOBuilder == null) {
-            throw new IllegalArgumentException("Generated transfer object builder can't be null");
-        }
-        if (regularExpressions == null) {
-            throw new IllegalArgumentException("List of regular expressions can't be null");
-        }
-        if (!regularExpressions.isEmpty()) {
-            genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), TypeConstants.PATTERN_CONSTANT_NAME,
-                ImmutableList.copyOf(regularExpressions));
+    static void addStringRegExAsConstant(final GeneratedTOBuilder genTOBuilder, final Map<String, String> expressions) {
+        if (!expressions.isEmpty()) {
+            genTOBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), BindingMapping.PATTERN_CONSTANT_NAME,
+                ImmutableMap.copyOf(expressions));
         }
     }
 
@@ -341,7 +325,7 @@ final class TypeGenHelper {
             final List<TypeDefinition<?>> childTypeDefinitions = ((UnionTypeDefinition) baseType).getTypes();
             int maxChildDepth = 0;
             int childDepth = 1;
-            for (final TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
+            for (TypeDefinition<?> childTypeDefinition : childTypeDefinitions) {
                 childDepth = childDepth + getTypeDefinitionDepth(childTypeDefinition);
                 if (childDepth > maxChildDepth) {
                     maxChildDepth = childDepth;
@@ -358,12 +342,12 @@ final class TypeGenHelper {
         fillRecursively(ret, module);
 
         final Set<NotificationDefinition> notifications = module.getNotifications();
-        for (final NotificationDefinition notificationDefinition : notifications) {
+        for (NotificationDefinition notificationDefinition : notifications) {
             fillRecursively(ret, notificationDefinition);
         }
 
         final Set<RpcDefinition> rpcs = module.getRpcs();
-        for (final RpcDefinition rpcDefinition : rpcs) {
+        for (RpcDefinition rpcDefinition : rpcs) {
             ret.addAll(rpcDefinition.getTypeDefinitions());
             final ContainerSchemaNode input = rpcDefinition.getInput();
             if (input != null) {
@@ -377,10 +361,10 @@ final class TypeGenHelper {
 
         final Collection<DataSchemaNode> potentials = module.getChildNodes();
 
-        for (final DataSchemaNode potential : potentials) {
+        for (DataSchemaNode potential : potentials) {
             if (potential instanceof ActionNodeContainer) {
                 final Set<ActionDefinition> actions = ((ActionNodeContainer) potential).getActions();
-                for (final ActionDefinition action: actions) {
+                for (ActionDefinition action: actions) {
                     final ContainerSchemaNode input = action.getInput();
                     if (input != null) {
                         fillRecursively(ret, input);
@@ -405,7 +389,7 @@ final class TypeGenHelper {
                 } else if (childNode instanceof ListSchemaNode) {
                     fillRecursively(list, (ListSchemaNode) childNode);
                 } else if (childNode instanceof ChoiceSchemaNode) {
-                    for (final CaseSchemaNode caseNode : ((ChoiceSchemaNode) childNode).getCases().values()) {
+                    for (CaseSchemaNode caseNode : ((ChoiceSchemaNode) childNode).getCases().values()) {
                         fillRecursively(list, caseNode);
                     }
                 }
@@ -416,7 +400,7 @@ final class TypeGenHelper {
 
         final Set<GroupingDefinition> groupings = container.getGroupings();
         if (groupings != null) {
-            for (final GroupingDefinition grouping : groupings) {
+            for (GroupingDefinition grouping : groupings) {
                 fillRecursively(list, grouping);
             }
         }
index 476e2552b41a25e5dc3af8400668ad776ecc68d0..8b46876dd58ecd5d9c495c45c3e381a4af0d89b6 100755 (executable)
@@ -212,12 +212,9 @@ public final class TypeProviderImpl implements TypeProvider {
             final String basePackageName = packageNameWithNamespacePrefix(getRootPackageName(module),
                     BindingNamespaceType.Typedef);
             final List<TypeDefinition<?>> typeDefinitions = getAllTypedefs(module);
-            final List<TypeDefinition<?>> listTypeDefinitions = sortTypeDefinitionAccordingDepth(typeDefinitions);
-            if (listTypeDefinitions != null) {
-                for (final TypeDefinition<?> typedef : listTypeDefinitions) {
-                    typedefToGeneratedType(basePackageName, module, typedef, genTypeDefsContextMap,
-                            additionalTypes, schemaContext, context);
-                }
+            for (TypeDefinition<?> typedef : sortTypeDefinitionAccordingDepth(typeDefinitions)) {
+                typedefToGeneratedType(basePackageName, module, typedef, genTypeDefsContextMap,
+                    additionalTypes, schemaContext, context);
             }
         });
     }
@@ -237,7 +234,8 @@ public final class TypeProviderImpl implements TypeProvider {
      *             <li>if name of <code>typeDefinition</code></li>
      *             </ul>
      */
-    public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
+    public Type generatedTypeForExtendedDefinitionType(final TypeDefinition<?> typeDefinition,
+            final SchemaNode parentNode) {
         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
         Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
                 "Type Definitions Local Name cannot be NULL!");
@@ -247,7 +245,8 @@ public final class TypeProviderImpl implements TypeProvider {
             final Module module = findParentModule(this.schemaContext, parentNode);
 
             if (module != null) {
-                final Map<Optional<Revision>, Map<String, Type>> modulesByDate = this.genTypeDefsContextMap.get(module.getName());
+                final Map<Optional<Revision>, Map<String, Type>> modulesByDate =
+                    this.genTypeDefsContextMap.get(module.getName());
                 final Map<String, Type> genTOs = modulesByDate.get(module.getRevision());
                 if (genTOs != null) {
                     return genTOs.get(typeDefinition.getQName().getLocalName());
@@ -300,7 +299,8 @@ public final class TypeProviderImpl implements TypeProvider {
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName,
-            final TypeDefinition<?> typeDef, final String typeDefName, final String moduleName, final ModuleContext context) {
+            final TypeDefinition<?> typeDef, final String typeDefName, final String moduleName,
+            final ModuleContext context) {
 
         Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
@@ -322,8 +322,8 @@ public final class TypeProviderImpl implements TypeProvider {
             GeneratedPropertyBuilder genPropertyBuilder;
             for (final Bit bit : bitList) {
                 final String name = bit.getName();
-                genPropertyBuilder =
-                        genTOBuilder.addProperty(JavaIdentifierNormalizer.normalizeSpecificIdentifier(name, JavaIdentifier.METHOD));
+                genPropertyBuilder = genTOBuilder.addProperty(
+                    JavaIdentifierNormalizer.normalizeSpecificIdentifier(name, JavaIdentifier.METHOD));
                 genPropertyBuilder.setReadOnly(true);
                 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
 
@@ -360,7 +360,9 @@ public final class TypeProviderImpl implements TypeProvider {
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
             final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode,
-            final SchemaContext schemaContext, final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap, final ModuleContext context) {
+            final SchemaContext schemaContext,
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final ModuleContext context) {
         Preconditions.checkNotNull(basePackageName, "Base Package Name cannot be NULL!");
         Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
         Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
@@ -380,11 +382,11 @@ public final class TypeProviderImpl implements TypeProvider {
 
         generatedTOBuilders.add(unionGenTOBuilder);
         unionGenTOBuilder.setIsUnion(true);
-        final List<String> regularExpressions = new ArrayList<>();
+        final Map<String, String> expressions = new HashMap<>();
         for (final TypeDefinition<?> unionType : unionTypes) {
             final String unionTypeName = unionType.getQName().getLocalName();
             if (unionType.getBaseType() != null) {
-                resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, regularExpressions,
+                resolveExtendedSubtypeAsUnion(unionGenTOBuilder, unionType, expressions,
                         parentNode, schemaContext, genTypeDefsContextMap);
             } else if (unionType instanceof UnionTypeDefinition) {
                 generatedTOBuilders.add(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionTypeDefinition) unionType,
@@ -400,8 +402,8 @@ public final class TypeProviderImpl implements TypeProvider {
                 updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
             }
         }
-        if (!regularExpressions.isEmpty()) {
-            addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
+        if (!expressions.isEmpty()) {
+            addStringRegExAsConstant(unionGenTOBuilder, expressions);
         }
 
         //storeGenTO(typedef, unionGenTOBuilder, parentNode);
@@ -424,7 +426,8 @@ public final class TypeProviderImpl implements TypeProvider {
 
     private Type javaTypeForSchemaDefType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
             final Restrictions r, final SchemaContext schemaContext,
-            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap, final ModuleContext context) {
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final ModuleContext context) {
         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
         final String typedefName = typeDefinition.getQName().getLocalName();
         Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
@@ -494,7 +497,8 @@ public final class TypeProviderImpl implements TypeProvider {
     private Type typedefToGeneratedType(final String basePackageName, final Module module,
             final TypeDefinition<?> typedef,
             final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
-            final Map<Module, Set<Type>> additionalTypes, final SchemaContext schemaContext, final ModuleContext context) {
+            final Map<Module, Set<Type>> additionalTypes, final SchemaContext schemaContext,
+            final ModuleContext context) {
         final String moduleName = module.getName();
         final Optional<Revision> moduleRevision = module.getRevision();
         if (basePackageName != null && moduleName != null && typedef != null) {
@@ -594,7 +598,8 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
     private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
-            final SchemaContext schemaContext, final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final SchemaContext schemaContext,
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
             final ModuleContext context) {
         if (typeDefinition instanceof LeafrefTypeDefinition) {
             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
@@ -627,9 +632,9 @@ public final class TypeProviderImpl implements TypeProvider {
      *
      */
     public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode,
-            final SchemaContext schemaContext, final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final SchemaContext schemaContext,
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
             final ModuleContext context) {
-
         Type returnType = null;
         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
 
@@ -734,7 +739,8 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return JAVA <code>Type</code> representation of <code>dataNode</code>
      */
     private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode, final SchemaContext schemaContext,
-            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap, final ModuleContext context) {
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final ModuleContext context) {
         Type returnType = null;
         if (dataNode != null) {
             if (dataNode instanceof LeafSchemaNode) {
@@ -766,7 +772,8 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return JAVA <code>Type</code> of the identity which is refrenced through
      *         <code>idref</code>
      */
-    private static Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref, final SchemaContext schemaContext) {
+    private static Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref,
+            final SchemaContext schemaContext) {
         //TODO: incompatibility with Binding spec v2, get first or only one
         final QName baseIdQName = idref.getIdentities().iterator().next().getQName();
         final Module module = schemaContext.findModule(baseIdQName.getModule()).orElse(null);
@@ -823,7 +830,8 @@ public final class TypeProviderImpl implements TypeProvider {
      *            string with name of property which should be added to
      *            <code>unionGentransObject</code>
      */
-    private static void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type, final String propertyName) {
+    private static void updateUnionTypeAsProperty(final GeneratedTOBuilder unionGenTransObject, final Type type,
+            final String propertyName) {
         if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
             final GeneratedPropertyBuilder propBuilder = unionGenTransObject
                     .addProperty(JavaIdentifierNormalizer.normalizeSpecificIdentifier(propertyName, JavaIdentifier.METHOD));
@@ -859,17 +867,17 @@ public final class TypeProviderImpl implements TypeProvider {
      */
     private GeneratedTOBuilder resolveUnionSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
             final UnionTypeDefinition unionSubtype, final String basePackageName, final SchemaNode parentNode,
-            final SchemaContext schemaContext, final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final SchemaContext schemaContext,
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
             final ModuleContext context) {
-
         final String newTOBuilderName = provideAvailableNameForGenTOBuilder(parentUnionGenTOBuilder.getName());
         final GeneratedTOBuilder subUnionGenTOBUilder = provideGeneratedTOBuilderForUnionTypeDef(
                 basePackageName, unionSubtype, newTOBuilderName, parentNode, schemaContext, genTypeDefsContextMap,
                 context);
 
         final GeneratedPropertyBuilder propertyBuilder;
-        propertyBuilder = parentUnionGenTOBuilder
-                .addProperty(JavaIdentifierNormalizer.normalizeSpecificIdentifier(newTOBuilderName, JavaIdentifier.METHOD));
+        propertyBuilder = parentUnionGenTOBuilder.addProperty(
+            JavaIdentifierNormalizer.normalizeSpecificIdentifier(newTOBuilderName, JavaIdentifier.METHOD));
         propertyBuilder.setReturnType(subUnionGenTOBUilder);
         parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
         parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
@@ -893,7 +901,8 @@ public final class TypeProviderImpl implements TypeProvider {
      */
     public GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
             final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode,
-            final SchemaContext schemaContext, final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
+            final SchemaContext schemaContext,
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap,
             final ModuleContext context) {
 
         final List<GeneratedTOBuilder> builders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
@@ -963,49 +972,50 @@ public final class TypeProviderImpl implements TypeProvider {
      * @param unionSubtype
      *            type definition of the <code>ExtendedType</code> type which
      *            represents union subtype
-     * @param regularExpressions
-     *            list of strings with the regular expressions
+     * @param expressions
+     *            map of strings with the regular expressions
      * @param parentNode
      *            parent Schema Node for Extended Subtype
      *
      */
     private void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
-            final TypeDefinition<?> unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode,
-            final SchemaContext schemaContext, final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap) {
-
+            final TypeDefinition<?> unionSubtype, final Map<String, String> expressions, final SchemaNode parentNode,
+            final SchemaContext schemaContext,
+            final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap) {
         final String unionTypeName = unionSubtype.getQName().getLocalName();
         final Type genTO = findGenTO(unionTypeName, unionSubtype, schemaContext, genTypeDefsContextMap);
         if (genTO != null) {
             updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, unionTypeName);
-        } else {
-            final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
-            if (unionTypeName.equals(baseType.getQName().getLocalName())) {
-                final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
-                        parentNode, null);
-                if (javaType != null) {
-                    updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
-                }
-            } else if (baseType instanceof LeafrefTypeDefinition) {
-                final Type javaType = javaTypeForSchemaDefinitionType(baseType,
-                        parentNode, null);
-                boolean typeExist = false;
-                for (final GeneratedPropertyBuilder generatedPropertyBuilder : parentUnionGenTOBuilder
-                        .getProperties()) {
-                    final Type origType = ((GeneratedPropertyBuilderImpl) generatedPropertyBuilder).getReturnType();
-                    if (origType != null && javaType != null && javaType == origType) {
-                        typeExist = true;
-                        break;
-                    }
-                }
-                if (!typeExist && javaType != null) {
-                    updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, new StringBuilder(javaType.getName())
-                            .append(parentUnionGenTOBuilder.getName()).append("Value").toString());
+            return;
+        }
+
+        final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
+        if (unionTypeName.equals(baseType.getQName().getLocalName())) {
+            final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
+                    parentNode, null);
+            if (javaType != null) {
+                updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
+            }
+        } else if (baseType instanceof LeafrefTypeDefinition) {
+            final Type javaType = javaTypeForSchemaDefinitionType(baseType,
+                    parentNode, null);
+            boolean typeExist = false;
+            for (final GeneratedPropertyBuilder generatedPropertyBuilder : parentUnionGenTOBuilder
+                    .getProperties()) {
+                final Type origType = ((GeneratedPropertyBuilderImpl) generatedPropertyBuilder).getReturnType();
+                if (origType != null && javaType != null && javaType == origType) {
+                    typeExist = true;
+                    break;
                 }
             }
-            if (baseType instanceof StringTypeDefinition) {
-                regularExpressions.addAll(resolveRegExpressionsFromTypedef(unionSubtype));
+            if (!typeExist && javaType != null) {
+                updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType,
+                    javaType.getName() + parentUnionGenTOBuilder.getName() + "Value");
             }
         }
+        if (baseType instanceof StringTypeDefinition) {
+            expressions.putAll(resolveRegExpressionsFromTypedef(unionSubtype));
+        }
     }
 
     /**
diff --git a/binding2/mdsal-binding2-generator-util/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/util/TypeConstants.java b/binding2/mdsal-binding2-generator-util/src/main/java/org/opendaylight/mdsal/binding/javav2/generator/util/TypeConstants.java
deleted file mode 100644 (file)
index dc0dea8..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2017 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.mdsal.binding.javav2.generator.util;
-
-import com.google.common.annotations.Beta;
-
-/**
- *
- * Contains constants used in relations with <code>Type</code>.
- */
-@Beta
-public final class TypeConstants {
-
-    /**
-     * Name of the class constant which hold list of the regular expression
-     * strings.
-     */
-    public static final String PATTERN_CONSTANT_NAME = "PATTERN_CONSTANTS";
-
-    /**
-     * Creation of new instance is prohibited.
-     */
-    private TypeConstants() {
-    }
-}
index 23c30ca5a3ab26cbecb363ae6e295c9687f9f17b..5917a0854078167e5d9dc8bb99393b2554cf7421 100755 (executable)
             <artifactId>twirl-api_2.12</artifactId>
             <version>1.3.13</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
index 3958b589734946e1e39cac03e1ab96408963ce7e..a35676bfa77e133242d8f2f3f30ed9a4ea45e01a 100644 (file)
@@ -246,6 +246,7 @@ public abstract class BaseRenderer {
         return null;
     }
 
+    //FIXME: this should be deprecated in favor of contantsTemplate
     /**
      * @param constant constant to emit
      * @return string with constant wrapped in code
index 07ae4bd5c9b63f40dc04b7634128aa4bf52b5571..d2ef788708a846bcb4daeb0cbe5263ce3b1bba87 100644 (file)
@@ -22,7 +22,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -48,11 +47,13 @@ import org.opendaylight.mdsal.binding.javav2.spec.base.IdentifiableItem;
 import org.opendaylight.mdsal.binding.javav2.spec.base.Instantiable;
 import org.opendaylight.mdsal.binding.javav2.spec.base.Item;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.binding.javav2.spec.runtime.CodeHelpers;
 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentation;
 import org.opendaylight.mdsal.binding.javav2.spec.structural.AugmentationHolder;
 import org.opendaylight.yangtools.concepts.Builder;
 import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
 
 public class BuilderRenderer extends BaseRenderer {
 
@@ -287,6 +288,9 @@ public class BuilderRenderer extends BaseRenderer {
         importedNames.put("instantiable", importedName(Instantiable.class));
         importedNames.put("item", importedName(Item.class));
         importedNames.put("identifiableItem", importedName(IdentifiableItem.class));
+        importedNames.put("qname", importedName(QName.class));
+        importedNames.put("codeHelpers", importedName(CodeHelpers.class));
+
         if (getType().getParentType() != null) {
             importedNames.put("parent", importedName(getType().getParentType()));
             parentTypeForBuilderName = getType().getParentType().getFullyQualifiedName();
index 578af596cd2a47112a012db00840e49269bc91a0..f0a99cae4d57ef82e4379ad56224055f5f4aab22 100644 (file)
@@ -10,8 +10,6 @@ package org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers;
 
 import static org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.fieldName;
 import static org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.setterMethod;
-import static org.opendaylight.mdsal.binding.javav2.util.BindingMapping.MEMBER_PATTERN_LIST;
-import static org.opendaylight.mdsal.binding.javav2.util.BindingMapping.PATTERN_CONSTANT_NAME;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Collections2;
@@ -29,14 +27,13 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.regex.Pattern;
 import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.AbstractRangeGenerator;
 import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.LengthGenerator;
 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplate;
 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateConstructors;
-import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateInitBlock;
 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateRestrictions;
 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateUnionConstr;
+import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.constantsTemplate;
 import org.opendaylight.mdsal.binding.javav2.model.api.Constant;
 import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
@@ -44,6 +41,7 @@ import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
+import org.opendaylight.yangtools.yang.common.QName;
 
 public class ClassRenderer extends BaseRenderer {
     protected final GeneratedTransferObject genTO;
@@ -146,6 +144,7 @@ public class ClassRenderer extends BaseRenderer {
         importedNames.put("lists", importedName(Lists.class));
         importedNames.put("illegalArgumentException", importedName(IllegalArgumentException.class));
         importedNames.put("boolean", importedName(Boolean.class));
+        importedNames.put("qname", importedName(QName.class));
 
         final List<String> implementsListBuilder = new LinkedList<>();
         if (!getType().getImplements().isEmpty()) {
@@ -173,39 +172,7 @@ public class ClassRenderer extends BaseRenderer {
         }
         final String enumerations = String.join("\n", enumList);
 
-        final StringBuilder sb1 = new StringBuilder();
-        final String initBlock = classTemplateInitBlock.render(importedName(Pattern.class)).body();
-        if (!consts.isEmpty()) {
-            for (Constant constant : consts) {
-                if (PATTERN_CONSTANT_NAME.equals(constant.getName())) {
-                    if (constant.getValue() instanceof List<?>) {
-                        sb1.append("private static final ")
-                            .append(importedName(Pattern.class))
-                            .append("[] ")
-                            .append(MEMBER_PATTERN_LIST)
-                            .append(";\npublic static final ")
-                            .append(importedName(List.class))
-                            .append("<String> ")
-                            .append(PATTERN_CONSTANT_NAME)
-                            .append(" = ")
-                            .append(importedName(ImmutableList.class))
-                            .append(".of(");
-                        final List<String> constantList = new LinkedList<>();
-                        for (Object item : (List) constant.getValue()) {
-                            if (item instanceof String) {
-                                constantList.add("\"" + item + "\"");
-                            }
-                        }
-                        sb1.append(String.join(", ", constantList));
-                        sb1.append(");")
-                                .append(initBlock);
-                    }
-                } else {
-                    sb1.append(emitConstant(constant));
-                }
-            }
-        }
-        final String constants = sb1.toString();
+        final String constants = constantsTemplate.render(getType(), importedNames, this::importedName).body();
 
         if (genTO.getSuperType() != null) {
             importedNames.put("superType", importedName(genTO.getSuperType()));
index 9a79a4e135a16bbcb8593a2a10e53c9f9f6cb183..f9c732b612e36ac91c3ef5c403c1d017339a3387 100644 (file)
@@ -161,12 +161,8 @@ public class @{genType.getName}Builder implements @{getSimpleNameForBuilder} <@{
                         }
                     }
                 }
-                if (!isValidArg) {
-                    throw new IllegalArgumentException(
-                      "expected one of: @{toListOfNames(getAllIfcs(genType.asInstanceOf[GeneratedType]))} \n" +
-                      "but was: " + arg
-                    );
-                }
+
+                @{importedNames.get("codeHelpers")}.validValue(isValidArg, arg, "@{toListOfNames(getAllIfcs(genType.asInstanceOf[GeneratedType]))}");
             }
         }
     }
@@ -253,7 +249,6 @@ public class @{genType.getName}Builder implements @{getSimpleNameForBuilder} <@{
     }
 }
 
-
 @generateSetters() = {
     @for(field <- properties) {
         @if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
@@ -326,10 +321,7 @@ public class @{genType.getName}Builder implements @{getSimpleNameForBuilder} <@{
         @if(addOverride) {@@Override}
         public <E extends @{importedNames.get("augmentation")}<? super @{genType.getName}>> E get@{toFirstUpper(augmentField.getName)}
         (@{importedNames.get("class")}<E> augmentationType) {
-            if (augmentationType == null) {
-                throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
-            }
-            return (E) @{augmentField.getName}.get(augmentationType);
+            return (E) @{augmentField.getName}.get(@{importedNames.get("codeHelpers")}.nonNullValue(augmentationType, "augmentationType"));
         }
     }
 }
index fc9aed44d52644bc1ce69423da089d9ba65cf27c..15b0d7867defefd52a37b432ba70789c477829f5 100644 (file)
@@ -10,7 +10,7 @@
 @import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.fieldName
 @import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject
 @import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty
-@import org.opendaylight.mdsal.binding.javav2.util.BindingMapping.PATTERN_CONSTANT_NAME
+@import org.opendaylight.mdsal.binding.javav2.util.BindingMapping
 
 @(genTo: GeneratedTransferObject, allProperties: List[GeneratedProperty], properties: List[GeneratedProperty],
 parentProperties: List[GeneratedProperty], importedNames: Map[String, String], argumentsDeclaration: String,
@@ -31,10 +31,8 @@ unionConstructor: String, genRestrictions: String)
         @if(genTo.isTypedef && !allProperties.isEmpty && allProperties.size == 1 && allProperties.get(0).getName.equals("value")) {
         @{importedNames.get("preconditions")}.checkNotNull(_value, "Supplied value may not be null");
             @for(currentConstant <- genTo.getConstantDefinitions) {
-                @if(PATTERN_CONSTANT_NAME.equals(currentConstant.getName) && currentConstant.getValue.isInstanceOf[List[_]]) {
-                    for (Pattern p : patterns) {
-                        @{importedNames.get("preconditions")}.checkArgument(p.matcher(_value).matches(), "Supplied value \"%s\" does not match required pattern \"%s\"", _value, p);
-                    }
+                @if(BindingMapping.PATTERN_CONSTANT_NAME.equals(currentConstant.getName)) {
+                    @{importedNames.get("CodeHelpers")}.checkPattern(_value, @{BindingMapping.MEMBER_PATTERN_LIST}, @{BindingMapping.MEMBER_REGEX_LIST});
                 }
             }
         }
diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/classTemplateInitBlock.scala.txt b/binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/classTemplateInitBlock.scala.txt
deleted file mode 100644 (file)
index a564792..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-@*
- * Copyright (c) 2016 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
- *@
-
-@import org.opendaylight.mdsal.binding.javav2.util.BindingMapping.MEMBER_PATTERN_LIST
-@import org.opendaylight.mdsal.binding.javav2.util.BindingMapping.PATTERN_CONSTANT_NAME
-
-@(patterName: String)
-static {
-    final @{patterName} a[] = new @{patterName}[@{PATTERN_CONSTANT_NAME}.size()];
-    int i = 0;
-    for (String regEx : @{PATTERN_CONSTANT_NAME}) {
-        a[i++] = Pattern.compile(regEx);
-    }
-
-    @{MEMBER_PATTERN_LIST} = a;
-}
\ No newline at end of file
diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/constantsTemplate.scala.txt b/binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding/javav2/java/api/generator/constantsTemplate.scala.txt
new file mode 100644 (file)
index 0000000..dc68bb4
--- /dev/null
@@ -0,0 +1,51 @@
+@*
+ * Copyright (c) 2018 ZTE, 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
+ *@
+
+@import org.apache.commons.text.StringEscapeUtils.escapeJava
+@import org.opendaylight.mdsal.binding.javav2.model.api.Type
+@import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType
+@import org.opendaylight.mdsal.binding.javav2.model.api.Constant
+@import org.opendaylight.mdsal.binding.javav2.util.BindingMapping
+@import org.opendaylight.mdsal.binding.javav2.generator.util.Types
+@import org.opendaylight.yangtools.yang.common.QName;
+@import org.opendaylight.yangtools.yang.common.Revision;
+
+@(genType: GeneratedType, importedNames: Map[String, String], importedName: Function[Type, String])
+@for(c <- genType.getConstantDefinitions) {
+    @if(c.getName == BindingMapping.PATTERN_CONSTANT_NAME) {
+        @defining(c.getValue.asInstanceOf[Map[String, String]]) { cValue =>
+        public static final @{importedNames.get("list")}<@{importedNames.get("string")}> @{BindingMapping.PATTERN_CONSTANT_NAME} = @{importedNames.get("immutableList")}.of(
+            @{(cValue.keySet map {escapeJava}).mkString("\"", "\", \"", "\"")});
+        @if(cValue.size == 1) {
+            private static final @{importedNames.get("pattern")} @{BindingMapping.MEMBER_PATTERN_LIST} = @{importedNames.get("pattern")}.compile(@{BindingMapping.PATTERN_CONSTANT_NAME}.get(0));
+            private static final String @{BindingMapping.MEMBER_REGEX_LIST} = "@{escapeJava(cValue.values.stream.findFirst.get)}";
+        } else {
+            private static final @{importedNames.get("pattern")}[] @{BindingMapping.MEMBER_PATTERN_LIST} = @{importedNames.get("codeHelpers")}.compilePatterns(@{BindingMapping.PATTERN_CONSTANT_NAME});
+            private static final String[] @{BindingMapping.MEMBER_REGEX_LIST} = {
+                @{(cValue.keySet map {escapeJava}).mkString("\"", "\", \"", "\"")}
+            };
+        }
+        }
+    } else {
+        public static final @{importedName(c.getType())} @{c.getName} =
+        @if(c.getValue.isInstanceOf[QName]) {
+            @defining(c.getValue.asInstanceOf[QName]) { qname =>
+            @{importedNames.get("qname")}.create("@{qname.getNamespace}",
+            @defining(qname.getRevision()) { rev =>
+                @if(rev.isPresent()) {
+                    "@{rev.get}"
+                } else {
+                    "null";
+                }
+            }, "@{qname.getLocalName}").intern();
+            }
+        } else {
+            @{c.getValue};
+        }
+    }
+}
\ No newline at end of file
diff --git a/binding2/mdsal-binding2-spec/src/main/java/org/opendaylight/mdsal/binding/javav2/spec/runtime/CodeHelpers.java b/binding2/mdsal-binding2-spec/src/main/java/org/opendaylight/mdsal/binding/javav2/spec/runtime/CodeHelpers.java
new file mode 100644 (file)
index 0000000..197cc42
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2018 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.mdsal.binding.javav2.spec.runtime;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.base.VerifyException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Helper methods for generated binding code. This class concentrates useful primitives generated code may call
+ * to perform specific shared functions. This allows for generated classes to be leaner. Methods in this class follows
+ * general API stability requirements of the Binding Specification.
+ *
+ * @author Robert Varga
+ */
+public final class CodeHelpers {
+    private static final String NEGATED_PATTERN_PREFIX = "^(?!";
+    private static final String NEGATED_PATTERN_SUFFIX = ").*$";
+
+    private CodeHelpers() {
+        // Hidden
+    }
+
+    /**
+     * Require that an a value-related expression is true.
+     *
+     * @param expression Expression to evaluate
+     * @param value Value being validated
+     * @param options Valid value options checked
+     * @throws IllegalArgumentException if expression is false
+     */
+    public static void validValue(final boolean expression, final Object value, final String options) {
+        checkArgument(expression, "expected one of: %s \n%but was: %s", options, value);
+    }
+
+    /**
+     * Require an argument being received. This is similar to {@link java.util.Objects#requireNonNull(Object)}, but
+     * throws an IllegalArgumentException.
+     *
+     * <p>
+     * Implementation note: we expect argName to be a string literal or a constant, so that it's non-nullness can be
+     *                      quickly discovered for a call site (where we are going to be inlined).
+     *
+     * @param value Value itself
+     * @param name Symbolic name
+     * @return non-null value
+     * @throws IllegalArgumentException if value is null
+     * @throws NullPointerException if name is null
+     */
+    // FIXME: another advantage is that it is JDT-annotated, but we could live without that. At some point we should
+    //        schedule a big ISE-to-NPE conversion and just use Objects.requireNonNull() instead.
+    public static <T> @NonNull T nonNullValue(@Nullable final T value, final @NonNull String name) {
+        requireNonNull(name);
+        checkArgument(value != null, "%s must not be null", name);
+        return value;
+    }
+
+    /**
+     * Append a named value to a ToStringHelper. If the value is null, this method does nothing.
+     *
+     * @param helper Helper to append to
+     * @param name Name of the value
+     * @param value Value to append
+     * @throws NullPointerException if the name or helper is null
+     */
+    public static void appendValue(final @NonNull ToStringHelper helper, final @NonNull String name,
+            final @Nullable Object value) {
+        if (value != null) {
+            helper.add(name, value);
+        }
+    }
+
+    /**
+     * Append a named value to a ToStringHelper. If the value is null, this method does nothing.
+     *
+     * @param helper Helper to append to
+     * @param name Name of the value
+     * @param value Value to append
+     * @throws NullPointerException if the name or helper is null
+     */
+    public static void appendValue(final ToStringHelper helper, final String name, final byte[] value) {
+        if (value != null) {
+            helper.add(name, Arrays.toString(value));
+        }
+    }
+
+    /**
+     * Compile a list of pattern regular expressions and return them as an array. The list must hold at least two
+     * expressions.
+     *
+     * @param patterns Patterns to compile
+     * @return Compiled patterns in an array
+     * @throws NullPointerException if the list or any of its elements is null
+     * @throws VerifyException if the list has fewer than two elements
+     */
+    public static @NonNull Pattern[] compilePatterns(final @NonNull List<String> patterns) {
+        final int size = patterns.size();
+        verify(size > 1, "Patterns has to have at least 2 elements");
+        final @NonNull Pattern[] result = new Pattern[size];
+        for (int i = 0; i < size; ++i) {
+            result[i] = Pattern.compile(patterns.get(i));
+        }
+        return result;
+    }
+
+    /**
+     * Check whether a specified string value matches a specified pattern. This method handles the distinction between
+     * modeled XSD expression and enforcement {@link Pattern} which may reflect negation.
+     *
+     * @param value Value to be checked.
+     * @param pattern Enforcement pattern
+     * @param regex Source regular expression, as defined in YANG model
+     * @throws IllegalArgumentException if the value does not match the pattern
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public static void checkPattern(final String value, final Pattern pattern, final String regex) {
+        if (!pattern.matcher(value).matches()) {
+            final String match = isNegatedPattern(pattern.toString()) ? "matches forbidden"
+                : "does not match required";
+            throw new IllegalArgumentException("Supplied value \"" + value + "\" " + match + " pattern \""
+                    + regex + "\"");
+        }
+    }
+
+    private static boolean isNegatedPattern(final String pattern) {
+        return pattern.startsWith(NEGATED_PATTERN_PREFIX) && pattern.endsWith(NEGATED_PATTERN_SUFFIX);
+    }
+
+    /**
+     * Check whether a specified string value matches specified patterns. This method handles the distinction between
+     * modeled XSD expression and enforcement {@link Pattern} which may reflect negation.
+     *
+     * @param value Value to be checked.
+     * @param patterns Enforcement patterns
+     * @param regexes Source regular expression, as defined in YANG model. Size and order must match patterns.
+     * @throws IllegalArgumentException if the value does not match the pattern
+     * @throws NullPointerException if any of the arguments are null
+     * @throws VerifyException if the size of patterns and regexes does not match
+     */
+    public static void checkPattern(final String value, final Pattern[] patterns, final String[] regexes) {
+        verify(patterns.length == regexes.length, "Patterns and regular expression lengths have to match");
+        for (int i = 0; i < patterns.length; ++i) {
+            checkPattern(value, patterns[i], regexes[i]);
+        }
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a length violation.
+     *
+     * @param expected String describing expected lengths
+     * @param actual Actual observed object
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidLength(final String expected, final Object actual) {
+        throw new IllegalArgumentException("Invalid length: " + actual + ", expected: " + expected + ".");
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a length violation.
+     *
+     * @param expected String describing expected lengths
+     * @param actual Actual observed byte array
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidLength(final String expected, final byte[] actual) {
+        throwInvalidLength(expected, Arrays.toString(actual));
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a range violation.
+     *
+     * @param expected String describing expected ranges
+     * @param actual Actual observed object
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidRange(final String expected, final Object actual) {
+        throw new IllegalArgumentException("Invalid range: " + actual + ", expected: " + expected + ".");
+    }
+
+    /**
+     * Throw an IllegalArgument exception describing a range violation.
+     *
+     * @param expected Objects describing expected ranges
+     * @param actual Actual observed byte array
+     * @throws IllegalArgumentException always
+     */
+    public static void throwInvalidRange(final Object[] expected, final Object actual) {
+        throwInvalidRange(Arrays.toString(expected), actual);
+    }
+}
index 8500f5e452d135a31af059dc1d5db49e891b5193..ebaa3fca17a973f737447d8ad372c48935b2f4a8 100644 (file)
@@ -47,6 +47,7 @@ public final class BindingMapping {
     public static final String MODEL_BINDING_PROVIDER_CLASS_NAME = "$YangModelBindingProvider";
     public static final String PATTERN_CONSTANT_NAME = "PATTERN_CONSTANTS";
     public static final String MEMBER_PATTERN_LIST = "patterns";
+    public static final String MEMBER_REGEX_LIST = "regexes";
     public static final String RPC_INPUT_SUFFIX = "Input";
     public static final String RPC_OUTPUT_SUFFIX = "Output";