Bug 5200: Yang parser doesn't fill error-app-tag and error-message in constraints 85/39385/2
authorPeter Kajsa <pkajsa@cisco.com>
Thu, 5 May 2016 15:24:26 +0000 (17:24 +0200)
committerPeter Kajsa <pkajsa@cisco.com>
Wed, 25 May 2016 06:44:32 +0000 (08:44 +0200)
Length, Pattern, Range statements may contain error-app-tag and error-message
substatements, but yang parser does not fill them correctly when corresponding
constraint objects are created. Instead yang parser always constructs constant formatted
message.

Change-Id: I69edb1fa49bcd50098f247df851c839c2f871782
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
19 files changed:
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/BaseConstraints.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/LengthConstraintImpl.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/PatternConstraintImpl.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/RangeConstraintImpl.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/LengthRestrictedTypeBuilder.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/type/RangeRestrictedTypeBuilder.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/PatternConstraintImplTest.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/TypeUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/DeclaredEffectiveStatementBase.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/AbstractConstraintEffectiveStatement.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/LengthConstraintEffectiveImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/LengthEffectiveStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/PatternConstraintEffectiveImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/PatternEffectiveStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/RangeConstraintEffectiveImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/RangeEffectiveStatementImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug5200Test.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bugs/bug5200/foo.yang [new file with mode: 0644]

index 9b904c563e53ac231b881a1ae05c79244b2e3e8c..4283ae5aeb77ed774463f80e472c8e0f26f8e125 100644 (file)
@@ -51,6 +51,33 @@ public final class BaseConstraints {
         return new LengthConstraintImpl(min, max, description, reference);
     }
 
+    /**
+     * Creates a {@link LengthConstraint}.
+     *
+     * Creates an instance of Length constraint based on supplied parameters
+     * with additional behaviour:
+     *
+     * <ul>
+     * <li>{@link LengthConstraint#getErrorAppTag()} returns <code>length-out-of-specified-bounds</code>
+     * <li>{@link LengthConstraint#getErrorMessage()} returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
+     * </ul>
+     *
+     * @see LengthConstraint
+     *
+     * @param min  length-restricting lower bound value. The value MUST NOT be negative.
+     * @param max length-restricting upper bound value. The value MUST NOT be negative.
+     * @param description Description associated with constraint. {@link Optional#absent()} if description is undefined.
+     * @param reference Reference associated with constraint. {@link Optional#absent()} if reference is undefined.
+     * @param errorAppTag error-app-tag associated with constraint.
+     * @param errorMessage error message associated with constraint.
+     * @return Instance of {@link LengthConstraint}
+     */
+    public static LengthConstraint newLengthConstraint(final Number min, final Number max,
+            final Optional<String> description, final Optional<String> reference, final String errorAppTag,
+            final String errorMessage) {
+        return new LengthConstraintImpl(min, max, description, reference, errorAppTag, errorMessage);
+    }
+
     /**
      * Creates a {@link RangeConstraint}.
      *
@@ -77,6 +104,35 @@ public final class BaseConstraints {
         return new RangeConstraintImpl(min, max, description, reference);
     }
 
+    /**
+     * Creates a {@link RangeConstraint}.
+     *
+     * Creates an instance of Range constraint based on supplied parameters
+     * with additional behaviour:
+     *
+     * <ul>
+     * <li>{@link RangeConstraint#getErrorAppTag()} returns <code>range-out-of-specified-bounds</code>
+     * <li>{@link RangeConstraint#getErrorMessage()} returns <code>The argument is out of bounds &lt;<i>min</i>, <i>max</i> &gt;</code>
+     * </ul>
+     *
+     *
+     * @see RangeConstraint
+     *
+     * @param <T> Type of constraint
+     * @param min value-restricting lower bound value. The value MUST NOT Be null.
+     * @param max value-restricting upper bound value. The value MUST NOT Be null.
+     * @param description Description associated with constraint. {@link Optional#absent()} if description is undefined.
+     * @param reference Reference associated with constraint. {@link Optional#absent()} if reference is undefined.
+     * @param errorAppTag error-app-tag associated with constraint.
+     * @param errorMessage error message associated with constraint.
+     * @return Instance of {@link RangeConstraint}
+     */
+    public static <T extends Number> RangeConstraint newRangeConstraint(final T min, final T max,
+            final Optional<String> description, final Optional<String> reference, final String errorAppTag,
+            final String errorMessage) {
+        return new RangeConstraintImpl(min, max, description, reference, errorAppTag, errorMessage);
+    }
+
     /**
      * Creates a {@link PatternConstraint}.
      *
@@ -98,4 +154,28 @@ public final class BaseConstraints {
             final Optional<String> reference) {
         return new PatternConstraintImpl(pattern, description, reference);
     }
+
+    /**
+     * Creates a {@link PatternConstraint}.
+     *
+     * Creates an instance of Pattern constraint based on supplied parameters
+     * with additional behaviour:
+     *
+     * <ul>
+     * <li>{@link PatternConstraint#getErrorAppTag()} returns <code>invalid-regular-expression</code>
+     * </ul>
+     *
+     * @see PatternConstraint
+     *
+     * @param pattern Regular expression, MUST NOT BE null.
+     * @param description Description associated with constraint.
+     * @param reference Reference associated with constraint.
+     * @param errorAppTag error-app-tag associated with constraint.
+     * @param errorMessage error message associated with constraint.
+     * @return Instance of {@link PatternConstraint}
+     */
+    public static PatternConstraint newPatternConstraint(final String pattern, final Optional<String> description,
+            final Optional<String> reference, final String errorAppTag, final String errorMessage) {
+        return new PatternConstraintImpl(pattern, description, reference, errorAppTag, errorMessage);
+    }
 }
index ca75b0c6158a7c554aa09dc6f71d19f46934f90b..58f24dc190b3abb1ef9a98c8a4d476254079daac 100644 (file)
@@ -38,14 +38,19 @@ final class LengthConstraintImpl implements LengthConstraint, Immutable {
 
     LengthConstraintImpl(final Number min, final Number max, final Optional<String> description,
             final Optional<String> reference) {
-        super();
+        this(min, max, description, reference, "length-out-of-specified-bounds", "The argument is out of bounds <"
+                + min + ", " + max + ">");
+    }
+
+    LengthConstraintImpl(final Number min, final Number max, final Optional<String> description,
+            final Optional<String> reference, final String errorAppTag, final String errorMessage) {
         this.min = Preconditions.checkNotNull(min, "min must not be null.");
         this.max = Preconditions.checkNotNull(max, "max must not be null");
         this.description = description.orNull();
         this.reference = reference.orNull();
-
-        this.errorAppTag = "length-out-of-specified-bounds";
-        this.errorMessage = "The argument is out of bounds <" + min + ", " + max + ">";
+        this.errorAppTag = errorAppTag != null ? errorAppTag : "length-out-of-specified-bounds";
+        this.errorMessage = errorMessage != null ? errorMessage : "The argument is out of bounds <" + min + ", " + max
+                + ">";
     }
 
     @Override
index eecc2a01f5295f45bc14ed966c9b61740a94a50a..cd0ca2cf2431afb1977e82ab1cf45ebcad300e10 100644 (file)
@@ -34,17 +34,19 @@ final class PatternConstraintImpl implements PatternConstraint, Immutable {
     private final String errorAppTag;
     private final String errorMessage;
 
-    public PatternConstraintImpl(final String regex, final Optional<String> description,
-            final Optional<String> reference) {
-        super();
+    PatternConstraintImpl(final String regex, final Optional<String> description, final Optional<String> reference) {
+        this(regex, description, reference, "invalid-regular-expression", String.format(
+                "String %s is not valid regular expression.", regex));
+    }
+
+    PatternConstraintImpl(final String regex, final Optional<String> description, final Optional<String> reference,
+            final String errorAppTag, final String errorMessage) {
         this.regex = Preconditions.checkNotNull(regex, "regex must not be null.");
         this.description = description.orNull();
         this.reference = reference.orNull();
-
-        // FIXME: Lookup better suitable error tag.
-        errorAppTag = "invalid-regular-expression";
-        // TODO: add erro message
-        errorMessage = "";
+        this.errorAppTag = errorAppTag != null ? errorAppTag : "invalid-regular-expression";
+        this.errorMessage = errorMessage != null ? errorMessage : String.format(
+                "String %s is not valid regular expression.", regex);
     }
 
     @Override
index f8db0870528abaa1cd85efdf79da137b9f359d3d..132d52a1db05d7baf46e58613217e18f413373dc 100644 (file)
@@ -11,7 +11,6 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import java.util.Objects;
 import org.opendaylight.yangtools.concepts.Immutable;
-import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 
 /**
@@ -38,14 +37,19 @@ final class RangeConstraintImpl implements RangeConstraint, Immutable {
 
     RangeConstraintImpl(final Number min, final Number max, final Optional<String> description,
             final Optional<String> reference) {
-        super();
+        this(min, max, description, reference, "range-out-of-specified-bounds", "The argument is out of bounds <" + min
+                + ", " + max + ">");
+    }
+
+    RangeConstraintImpl(final Number min, final Number max, final Optional<String> description,
+            final Optional<String> reference, final String errorAppTag, final String errorMessage) {
         this.min = Preconditions.checkNotNull(min, "min must not be null.");
         this.max = Preconditions.checkNotNull(max, "max must not be null.");
         this.description = description.orNull();
         this.reference = reference.orNull();
-
-        this.errorAppTag = "range-out-of-specified-bounds";
-        this.errorMessage = "The argument is out of bounds <" + min + ", " + max + ">";
+        this.errorAppTag = errorAppTag != null ? errorAppTag : "range-out-of-specified-bounds";
+        this.errorMessage = errorMessage != null ? errorMessage : "The argument is out of bounds <" + min + ", " + max
+                + ">";
     }
 
     @Override
index fe217561b1c8df84d1a585cf1da01c0338ddab02..eb590a91287d42a3937183ab506233dce3afc4e4 100644 (file)
@@ -63,7 +63,7 @@ public abstract class LengthRestrictedTypeBuilder<T extends TypeDefinition<T>> e
                         ((UnresolvedNumber)min).resolveLength(baseLengthConstraints) : min;
 
                 builder.add(BaseConstraints.newLengthConstraint(rMin, rMax, Optional.fromNullable(c.getDescription()),
-                    Optional.fromNullable(c.getReference())));
+                    Optional.fromNullable(c.getReference()), c.getErrorAppTag(), c.getErrorMessage()));
             } else {
                 builder.add(c);
             }
@@ -101,7 +101,7 @@ public abstract class LengthRestrictedTypeBuilder<T extends TypeDefinition<T>> e
                         c, clazz.getSimpleName()), e);
                 }
                 builder.add(BaseConstraints.newLengthConstraint(min, max, Optional.fromNullable(c.getDescription()),
-                    Optional.fromNullable(c.getReference())));
+                    Optional.fromNullable(c.getReference()), c.getErrorAppTag(), c.getErrorMessage()));
             } else {
                 builder.add(c);
             }
index ebebbe3e42c4a46926fc2fdb091e18b418cee7e5..e461d48abc705bd39f098f18c1b8e20a48a2e4cb 100644 (file)
@@ -64,7 +64,7 @@ public abstract class RangeRestrictedTypeBuilder<T extends TypeDefinition<T>> ex
                         ((UnresolvedNumber)min).resolveRange(baseRangeConstraints) : min;
 
                 builder.add(BaseConstraints.newRangeConstraint(rMin, rMax, Optional.fromNullable(c.getDescription()),
-                    Optional.fromNullable(c.getReference())));
+                    Optional.fromNullable(c.getReference()), c.getErrorAppTag(), c.getErrorMessage()));
             } else {
                 builder.add(c);
             }
@@ -103,7 +103,7 @@ public abstract class RangeRestrictedTypeBuilder<T extends TypeDefinition<T>> ex
                         c, clazz.getSimpleName()), e);
                 }
                 builder.add(BaseConstraints.newRangeConstraint(min, max, Optional.fromNullable(c.getDescription()),
-                    Optional.fromNullable(c.getReference())));
+                    Optional.fromNullable(c.getReference()), c.getErrorAppTag(), c.getErrorMessage()));
             } else {
                 builder.add(c);
             }
index 536d5a24de723d0befe4109b0533f04c6e0d1b53..305fea505c5e65d57fd82a1a345735e5403cc4b3 100644 (file)
@@ -35,7 +35,7 @@ public class PatternConstraintImplTest {
         assertNotNull("Object of PatternConstraintImpl shouldn't be null.", patternConstraint);
         assertEquals("Description should be 'test description'.", "test description", patternConstraint.getDescription());
         assertEquals("Error app tag shouldn't be null.", "invalid-regular-expression", patternConstraint.getErrorAppTag());
-        assertTrue("Error message should be empty.", patternConstraint.getErrorMessage().isEmpty());
+        assertNotNull(patternConstraint.getErrorMessage());
         assertEquals("Reference should be equals 'RFC 6020'.", "RFC 6020", patternConstraint.getReference());
         assertEquals("Regular expression should be equls '\\D'.", "\\D", patternConstraint.getRegularExpression());
         assertNotEquals("Hash codes shouldn't be equals.", patternConstraint.hashCode(), patternConstraint2.hashCode());
index 05b7f67c333ceab95ede69325755457f7db658c5..6b5f8439df66415bf61a180ffbdd23af8080f1f3 100644 (file)
@@ -71,6 +71,12 @@ public final class StmtContextUtils {
         return producesDeclared(ctx, declaredType) ? (AT) ctx.getStatementArgument() : null;
     }
 
+    public static <AT, DT extends DeclaredStatement<AT>> AT firstSubstatementAttributeOf(
+            final StmtContext<?, ?, ?> ctx, final Class<DT> declaredType) {
+        AT firstAttribute = firstAttributeOf(ctx.effectiveSubstatements(), declaredType);
+        return firstAttribute != null ? firstAttribute : firstAttributeOf(ctx.declaredSubstatements(), declaredType);
+    }
+
     @SuppressWarnings("unchecked")
     public static <AT,DT extends DeclaredStatement<AT>> StmtContext<AT, ?, ?> findFirstDeclaredSubstatement(
             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
index cd579073d68808a41ac0fed62a7f096efd65fd0e..11f460ae540a802d3b9338c026aaf3b80a510823 100644 (file)
@@ -157,13 +157,13 @@ public final class TypeUtils {
     }
 
     public static List<LengthConstraint> parseLengthListFromString(final StmtContext<?, ?, ?> ctx,
-            final String rangeArgument) {
+            final String lengthArgument) {
         Optional<String> description = Optional.absent();
         Optional<String> reference = Optional.absent();
 
-        List<LengthConstraint> rangeConstraints = new ArrayList<>();
+        List<LengthConstraint> lengthConstraints = new ArrayList<>();
 
-        for (final String singleRange : PIPE_SPLITTER.split(rangeArgument)) {
+        for (final String singleRange : PIPE_SPLITTER.split(lengthArgument)) {
             final Iterator<String> boundaries = TWO_DOTS_SPLITTER.splitToList(singleRange).iterator();
             final Number min = parseIntegerConstraintValue(ctx, boundaries.next());
 
@@ -183,15 +183,15 @@ public final class TypeUtils {
             }
 
             // some of intervals overlapping
-            if (rangeConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(rangeConstraints).getMax()) != 1) {
+            if (lengthConstraints.size() > 1 && compareNumbers(min, Iterables.getLast(lengthConstraints).getMax()) != 1) {
                 throw new InferenceException(ctx.getStatementSourceReference(),
-                    "Some of the length ranges in %s are not disjoint", rangeArgument);
+                    "Some of the length ranges in %s are not disjoint", lengthArgument);
             }
 
-            rangeConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference));
+            lengthConstraints.add(new LengthConstraintEffectiveImpl(min, max, description, reference));
         }
 
-        return rangeConstraints;
+        return lengthConstraints;
     }
 
     public static boolean isYangTypeBodyStmtString(final String typeName) {
index 2c96fba980b1a8e1a3b4d0bc6a08cbe2ad4fd28e..212a65e8137163f6383125cadf80cbb037e8375f 100644 (file)
@@ -62,7 +62,7 @@ public abstract class DeclaredEffectiveStatementBase<A, D extends DeclaredStatem
     }
 
     @Override
-    public final A argument() {
+    public A argument() {
         return argument;
     }
 
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/AbstractConstraintEffectiveStatement.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/type/AbstractConstraintEffectiveStatement.java
new file mode 100644 (file)
index 0000000..4bc14b4
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ * 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
+ */
+package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
+
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DescriptionEffectiveStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ErrorAppTagEffectiveStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ErrorMessageEffectiveStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ReferenceEffectiveStatementImpl;
+
+abstract class AbstractConstraintEffectiveStatement<A, D extends DeclaredStatement<A>> extends
+        DeclaredEffectiveStatementBase<A, D> {
+    private final String description;
+    private final String reference;
+    private final String errorAppTag;
+    private final String errorMessage;
+    private final A constraints;
+
+    public AbstractConstraintEffectiveStatement(final StmtContext<A, D, ?> ctx, ConstraintFactory<A> constraintFactory) {
+        super(ctx);
+        String descriptionInit = null;
+        String referenceInit = null;
+        String errorAppTagInit = null;
+        String errorMessageInit = null;
+
+        for (EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+            if (stmt instanceof DescriptionEffectiveStatementImpl) {
+                descriptionInit = ((DescriptionEffectiveStatementImpl) stmt).argument();
+            }
+            if (stmt instanceof ReferenceEffectiveStatementImpl) {
+                referenceInit = ((ReferenceEffectiveStatementImpl) stmt).argument();
+            }
+            if (stmt instanceof ErrorAppTagEffectiveStatementImpl) {
+                errorAppTagInit = ((ErrorAppTagEffectiveStatementImpl) stmt).argument();
+            }
+            if (stmt instanceof ErrorMessageEffectiveStatementImpl) {
+                errorMessageInit = ((ErrorMessageEffectiveStatementImpl) stmt).argument();
+            }
+        }
+
+        this.description = descriptionInit;
+        this.reference = referenceInit;
+        this.errorAppTag = errorAppTagInit;
+        this.errorMessage = errorMessageInit;
+        this.constraints = constraintFactory.createConstraints(this, super.argument());
+    }
+
+    @Override
+    public final A argument() {
+        return constraints;
+    }
+
+    public final boolean isCustomizedStatement() {
+        return this.description != null || this.reference != null || this.errorAppTag != null
+                || this.errorMessage != null;
+    }
+
+    public final String getDescription() {
+        return description;
+    }
+
+    public final String getReference() {
+        return reference;
+    }
+
+    public final String getErrorAppTag() {
+        return errorAppTag;
+    }
+
+    public final String getErrorMessage() {
+        return errorMessage;
+    }
+}
+
+abstract class ConstraintFactory<A> {
+    abstract protected A createConstraints(AbstractConstraintEffectiveStatement<A, ?> stmt, A argument);
+}
+
+abstract class ListConstraintFactory<A> extends ConstraintFactory<List<A>> {
+    @Override
+    protected List<A> createConstraints(AbstractConstraintEffectiveStatement<List<A>, ?> stmt, List<A> argument) {
+        if (!stmt.isCustomizedStatement()) {
+            return ImmutableList.copyOf(argument);
+        }
+
+        List<A> customizedConstraints = new ArrayList<>();
+        for (A constraint : argument) {
+            customizedConstraints.add(createCustomizedConstraint(constraint, stmt));
+        }
+        return customizedConstraints;
+    }
+
+    abstract protected A createCustomizedConstraint(A constraint, AbstractConstraintEffectiveStatement<List<A>, ?> stmt);
+}
+
+final class LengthConstraintFactory extends ListConstraintFactory<LengthConstraint> {
+    @Override
+    protected LengthConstraint createCustomizedConstraint(LengthConstraint lengthConstraint,
+            AbstractConstraintEffectiveStatement<List<LengthConstraint>, ?> stmt) {
+        return new LengthConstraintEffectiveImpl(lengthConstraint.getMin(), lengthConstraint.getMax(),
+                stmt.getDescription(), stmt.getReference(), stmt.getErrorAppTag(), stmt.getErrorMessage());
+    }
+}
+
+final class RangeConstraintFactory extends ListConstraintFactory<RangeConstraint> {
+    @Override
+    protected RangeConstraint createCustomizedConstraint(RangeConstraint rangeConstraint,
+            AbstractConstraintEffectiveStatement<List<RangeConstraint>, ?> stmt) {
+        return new RangeConstraintEffectiveImpl(rangeConstraint.getMin(), rangeConstraint.getMax(),
+                stmt.getDescription(), stmt.getReference(), stmt.getErrorAppTag(), stmt.getErrorMessage());
+    }
+}
+
+final class PatternConstraintFactory extends ConstraintFactory<PatternConstraint> {
+    @Override
+    protected PatternConstraint createConstraints(AbstractConstraintEffectiveStatement<PatternConstraint, ?> stmt, PatternConstraint argument) {
+        if (!stmt.isCustomizedStatement()) {
+            return argument;
+        } else {
+            return createCustomizedConstraint(argument, stmt);
+        }
+    }
+
+    private PatternConstraint createCustomizedConstraint(PatternConstraint patternConstraint,
+            AbstractConstraintEffectiveStatement<?, ?> stmt) {
+        return new PatternConstraintEffectiveImpl(patternConstraint.getRegularExpression(), stmt.getDescription(),
+                stmt.getReference(), stmt.getErrorAppTag(), stmt.getErrorMessage());
+    }
+}
\ No newline at end of file
index 32ca55e4465b9722f164e380258eef9616044d28..98e11ecf65f328e030513e0b694ab7e4cea226fc 100644 (file)
@@ -25,16 +25,20 @@ public class LengthConstraintEffectiveImpl implements LengthConstraint {
 
     public LengthConstraintEffectiveImpl(final Number min, final Number max, final Optional<String> description,
             final Optional<String> reference) {
+        this(min, max, description.orNull(), reference.orNull(), "length-out-of-specified-bounds", "The argument is out of bounds <"
+                + min + ", " + max + ">");
+    }
 
+    public LengthConstraintEffectiveImpl(final Number min, final Number max, final String description,
+            final String reference, final String errorAppTag, final String errorMessage) {
         super();
-
         this.min = Preconditions.checkNotNull(min, "min must not be null.");
         this.max = Preconditions.checkNotNull(max, "max must not be null");
-        this.description = description.orNull();
-        this.reference = reference.orNull();
-
-        this.errorAppTag = "length-out-of-specified-bounds";
-        this.errorMessage = "The argument is out of bounds <" + min + ", " + max + ">";
+        this.description = description;
+        this.reference = reference;
+        this.errorAppTag = errorAppTag != null ? errorAppTag : "length-out-of-specified-bounds";
+        this.errorMessage = errorMessage != null ? errorMessage : "The argument is out of bounds <" + min + ", " + max
+                + ">";
     }
 
     @Override
index 84e7c993acefa842d6de5099963b81f3432c1224..19a71c04aeb3453b556f965bb1070eb2ec6191e2 100644 (file)
@@ -11,10 +11,10 @@ import java.util.List;
 import org.opendaylight.yangtools.yang.model.api.stmt.LengthStatement;
 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
 
-public class LengthEffectiveStatementImpl extends DeclaredEffectiveStatementBase<List<LengthConstraint>, LengthStatement> {
+public class LengthEffectiveStatementImpl extends
+        AbstractConstraintEffectiveStatement<List<LengthConstraint>, LengthStatement> {
     public LengthEffectiveStatementImpl(final StmtContext<List<LengthConstraint>, LengthStatement, ?> ctx) {
-        super(ctx);
+        super(ctx, new LengthConstraintFactory());
     }
 }
\ No newline at end of file
index 184ebc401bd57f76d1aa0ef2a1e43fa7265f10f8..d8799648f621afc21a084bf0a08df6e8950dda15 100644 (file)
@@ -17,21 +17,24 @@ public class PatternConstraintEffectiveImpl implements PatternConstraint {
     private final String regEx;
     private final String description;
     private final String reference;
-
     private final String errorAppTag;
     private final String errorMessage;
 
     public PatternConstraintEffectiveImpl(final String regex, final Optional<String> description,
             final Optional<String> reference) {
+        this(regex, description.orNull(), reference.orNull(), "invalid-regular-expression", String.format(
+                "String %s is not valid regular expression.", regex));
+    }
 
+    public PatternConstraintEffectiveImpl(final String regex, final String description, final String reference,
+            final String errorAppTag, final String errorMessage) {
         super();
-
         this.regEx = Preconditions.checkNotNull(regex, "regex must not be null.");
-        this.description = description.orNull();
-        this.reference = reference.orNull();
-
-        errorAppTag = "invalid-regular-expression";
-        errorMessage = String.format("String %s is not valid regular expression.", regex);
+        this.description = description;
+        this.reference = reference;
+        this.errorAppTag = errorAppTag != null ? errorAppTag : "invalid-regular-expression";
+        this.errorMessage = errorMessage != null ? errorMessage : String.format(
+                "String %s is not valid regular expression.", regex);
     }
 
     @Override
index fb59877b8b1e837f77dec8e3373a8c3f8d260e30..eeb4d4c3baab732be8ea2a7009f5f47cf5f2c486 100644 (file)
@@ -10,10 +10,10 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
 import org.opendaylight.yangtools.yang.model.api.stmt.PatternStatement;
 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
 
-public class PatternEffectiveStatementImpl extends DeclaredEffectiveStatementBase<PatternConstraint, PatternStatement> {
+public class PatternEffectiveStatementImpl extends
+        AbstractConstraintEffectiveStatement<PatternConstraint, PatternStatement> {
     public PatternEffectiveStatementImpl(final StmtContext<PatternConstraint, PatternStatement, ?> ctx) {
-        super(ctx);
+        super(ctx, new PatternConstraintFactory());
     }
 }
\ No newline at end of file
index 4308ecb07b80cca83b9ac4f6762f04f65c31c1d4..6283689c55ff634e67389a775b53c937424a17ce 100644 (file)
@@ -26,16 +26,20 @@ public class RangeConstraintEffectiveImpl implements RangeConstraint {
 
     public RangeConstraintEffectiveImpl(final Number min, final Number max, final Optional<String> description,
             final Optional<String> reference) {
+        this(min, max, description.orNull(), reference.orNull(), "range-out-of-specified-bounds",
+                "The argument is out of bounds <" + min + ", " + max + ">");
+    }
 
+    public RangeConstraintEffectiveImpl(final Number min, final Number max, final String description,
+            final String reference, final String errorAppTag, final String errorMessage) {
         super();
-
         this.min = Preconditions.checkNotNull(min, "min must not be null.");
         this.max = Preconditions.checkNotNull(max, "max must not be null.");
-        this.description = description.orNull();
-        this.reference = reference.orNull();
-
-        this.errorAppTag = "range-out-of-specified-bounds";
-        this.errorMessage = "The argument is out of bounds <" + min + ", " + max + ">";
+        this.description = description;
+        this.reference = reference;
+        this.errorAppTag = errorAppTag != null ? errorAppTag : "range-out-of-specified-bounds";
+        this.errorMessage = errorMessage != null ? errorMessage : "The argument is out of bounds <" + min + ", " + max
+                + ">";
     }
 
     @Override
index 72f08e34a79c0a07a9872b296dcd9df51c0f0b1c..dec4c9ed22a65fa9c70d5eb8ef59f2d2a49603ec 100644 (file)
@@ -11,10 +11,10 @@ import java.util.List;
 import org.opendaylight.yangtools.yang.model.api.stmt.RangeStatement;
 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
 
-public class RangeEffectiveStatementImpl extends DeclaredEffectiveStatementBase<List<RangeConstraint>, RangeStatement> {
+public class RangeEffectiveStatementImpl extends
+        AbstractConstraintEffectiveStatement<List<RangeConstraint>, RangeStatement> {
     public RangeEffectiveStatementImpl(final StmtContext<List<RangeConstraint>, RangeStatement, ?> ctx) {
-        super(ctx);
+        super(ctx, new RangeConstraintFactory());
     }
 }
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug5200Test.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/test/Bug5200Test.java
new file mode 100644 (file)
index 0000000..409359e
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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
+ */
+package org.opendaylight.yangtools.yang.stmt.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+public class Bug5200Test {
+    private static final String NS = "foo";
+    private static final String REV = "2016-05-05";
+
+    @Test
+    public void test() throws SourceException, FileNotFoundException, ReactorException, URISyntaxException {
+        SchemaContext context = StmtTestUtils.parseYangSources("/bugs/bug5200");
+        assertNotNull(context);
+
+        QName root = QName.create(NS, REV, "root");
+        QName myLeaf = QName.create(NS, REV, "my-leaf");
+        QName myLeaf2 = QName.create(NS, REV, "my-leaf-2");
+
+        SchemaNode myLeafNode = SchemaContextUtil.findDataSchemaNode(context, SchemaPath.create(true, root, myLeaf));
+        SchemaNode myLeaf2Node = SchemaContextUtil.findDataSchemaNode(context, SchemaPath.create(true, root, myLeaf2));
+
+        assertTrue(myLeafNode instanceof LeafSchemaNode);
+        assertTrue(myLeaf2Node instanceof LeafSchemaNode);
+
+        TypeDefinition<?> myLeafType = ((LeafSchemaNode) myLeafNode).getType();
+        TypeDefinition<?> myLeaf2Type = ((LeafSchemaNode) myLeaf2Node).getType();
+
+        assertTrue(myLeafType instanceof StringTypeDefinition);
+        assertTrue(myLeaf2Type instanceof IntegerTypeDefinition);
+
+        List<LengthConstraint> lengthConstraints = ((StringTypeDefinition) myLeafType).getLengthConstraints();
+        List<PatternConstraint> patternConstraints = ((StringTypeDefinition) myLeafType).getPatternConstraints();
+
+        assertEquals(1, lengthConstraints.size());
+        assertEquals(1, patternConstraints.size());
+
+        LengthConstraint lenghtConstraint = lengthConstraints.iterator().next();
+        assertEquals("lenght constraint error-app-tag", lenghtConstraint.getErrorAppTag());
+        assertEquals("lenght constraint error-app-message", lenghtConstraint.getErrorMessage());
+
+        PatternConstraint patternConstraint = patternConstraints.iterator().next();
+        assertEquals("pattern constraint error-app-tag", patternConstraint.getErrorAppTag());
+        assertEquals("pattern constraint error-app-message", patternConstraint.getErrorMessage());
+
+        List<RangeConstraint> rangeConstraints = ((IntegerTypeDefinition) myLeaf2Type).getRangeConstraints();
+        assertEquals(1, rangeConstraints.size());
+
+        RangeConstraint rangeConstraint = rangeConstraints.iterator().next();
+        assertEquals("range constraint error-app-tag", rangeConstraint.getErrorAppTag());
+        assertEquals("range constraint error-app-message", rangeConstraint.getErrorMessage());
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/bugs/bug5200/foo.yang b/yang/yang-parser-impl/src/test/resources/bugs/bug5200/foo.yang
new file mode 100644 (file)
index 0000000..d007127
--- /dev/null
@@ -0,0 +1,32 @@
+module foo {
+    yang-version 1;
+    namespace "foo";
+    prefix foo;
+
+    revision 2016-05-05 {
+        description "Bug 5200 test.";
+    }
+
+    container root {
+        leaf my-leaf {
+            type string {
+                length "1..255" {
+                    error-app-tag "lenght constraint error-app-tag";
+                    error-message "lenght constraint error-app-message";
+                }
+                pattern "[a-z]+" {
+                    error-app-tag "pattern constraint error-app-tag";
+                    error-message "pattern constraint error-app-message";
+                }
+            }
+        }
+        leaf my-leaf-2 {
+            type int32 {
+                range "1..100" {
+                    error-app-tag "range constraint error-app-tag";
+                    error-message "range constraint error-app-message";
+                }
+            }
+        }
+    }
+}