import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
import javax.annotation.Nonnull;
/**
*/
VERSION_1_1("1.1", "RFC7950");
+ private static final Map<String, YangVersion> YANG_VERSION_MAP = Maps.uniqueIndex(Arrays.asList(values()),
+ YangVersion::toString);
+
private final String str;
private String reference;
*
* @param str String to parse
* @return YANG version
- * @throws IllegalArgumentException if the string is malformed
* @throws NullPointerException if the string is null
*/
- public static YangVersion parse(@Nonnull final String str) {
- switch (str) {
- case "1":
- return VERSION_1;
- case "1.1":
- return VERSION_1_1;
- default:
- throw new IllegalArgumentException("Invalid YANG version '" + str + "'");
- }
+ public static Optional<YangVersion> parse(@Nonnull final String str) {
+ return Optional.ofNullable(YANG_VERSION_MAP.get(Preconditions.checkNotNull(str)));
}
/**
import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModifierStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.MustStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
MANDATORY(MandatoryStatement.class, "mandatory", "value"),
MAX_ELEMENTS(MaxElementsStatement.class, "max-elements", "value"),
MIN_ELEMENTS(MinElementsStatement.class, "min-elements", "value"),
+ MODIFIER(ModifierStatement.class, "modifier", "value"),
MODULE(ModuleStatement.class, "module", "name"),
MUST(MustStatement.class, "must", "condition"),
NAMESPACE(NamespaceStatement.class, "namespace", "uri"),
package org.opendaylight.yangtools.yang.model.api.type;
import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
import javax.annotation.Nonnull;
/**
* Enum describing the effect of a YANG modifier statement.
*
- * As of YANG 1.1 (RFC7950) there is only one modifier value
- * available and that is "invert-match".
- * If there are more possible values added in the future,
+ * As of YANG 1.1 (RFC7950) there is only one modifier value available and that
+ * is "invert-match". If there are more possible values added in the future,
* this enum can be extended with more enum constants.
*/
public enum ModifierKind {
-
INVERT_MATCH("invert-match");
+ private static final Map<String, ModifierKind> MODIFIER_KIND_MAP = Maps.uniqueIndex(
+ Arrays.asList(ModifierKind.values()), ModifierKind::getKeyword);
+
private final String keyword;
- ModifierKind(final String keyword) {
+ private ModifierKind(final String keyword) {
this.keyword = Preconditions.checkNotNull(keyword);
}
public @Nonnull String getKeyword() {
return keyword;
}
+
+ /**
+ * Returns ModifierKind based on supplied Yang keyword
+ *
+ * @param keyword
+ * Yang keyword in string form
+ * @return ModifierKind based on supplied Yang keyword
+ * @throws NullPointerException if keyword is null
+ */
+ public static Optional<ModifierKind> parse(final String keyword) {
+ return Optional.ofNullable(MODIFIER_KIND_MAP.get(Preconditions.checkNotNull(keyword)));
+ }
}
import com.google.common.base.Optional;
import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
* with additional behaviour:
*
* <ul>
- * <li>{@link PatternConstraint#getErrorAppTag()} returns <code>invalid-regular-expression</code>
+ * <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 pattern
+ * Regular expression, MUST NOT BE null.
+ * @param description
+ * Description associated with constraint.
+ * @param reference
+ * Reference associated with constraint.
* @return Instance of {@link PatternConstraint}
*/
public static PatternConstraint newPatternConstraint(final String pattern, final Optional<String> description,
* with additional behaviour:
*
* <ul>
- * <li>{@link PatternConstraint#getErrorAppTag()} returns <code>invalid-regular-expression</code>
+ * <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.
+ * @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.
+ * @param modifier
+ * Modifier of pattern 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);
+ final Optional<String> reference, final String errorAppTag, final String errorMessage,
+ final Optional<ModifierKind> modifier) {
+ return new PatternConstraintImpl(pattern, description, reference, errorAppTag, errorMessage, modifier);
}
}
*/
package org.opendaylight.yangtools.yang.model.util;
+import com.google.common.base.MoreObjects;
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.ModifierKind;
import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
/**
private final String errorAppTag;
private final String errorMessage;
+ private final ModifierKind modifier;
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));
+ "String %s is not valid regular expression.", regex), Optional.absent());
}
PatternConstraintImpl(final String regex, final Optional<String> description, final Optional<String> reference,
- final String errorAppTag, final String errorMessage) {
+ final String errorAppTag, final String errorMessage, final Optional<ModifierKind> modifier) {
this.regex = Preconditions.checkNotNull(regex, "regex must not be null.");
this.description = description.orNull();
this.reference = reference.orNull();
this.errorAppTag = errorAppTag != null ? errorAppTag : "invalid-regular-expression";
this.errorMessage = errorMessage != null ? errorMessage : String.format(
"String %s is not valid regular expression.", regex);
+ this.modifier = modifier.orNull();
}
@Override
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + Objects.hashCode(description);
- result = prime * result + Objects.hashCode(errorAppTag);
- result = prime * result + Objects.hashCode(errorMessage);
- result = prime * result + Objects.hashCode(reference);
- result = prime * result + regex.hashCode();
- return result;
+ return Objects.hash(description, errorAppTag, errorMessage, reference, regex, modifier);
}
@Override
final PatternConstraintImpl other = (PatternConstraintImpl) obj;
return Objects.equals(description, other.description) && Objects.equals(errorAppTag, other.errorAppTag)
&& Objects.equals(errorMessage, other.errorMessage) && Objects.equals(reference, other.reference)
- && Objects.equals(regex, other.regex);
+ && Objects.equals(regex, other.regex) && Objects.equals(modifier, other.modifier);
}
@Override
public String toString() {
- return "PatternConstraintImpl [regex=" +
- regex +
- ", description=" +
- description +
- ", reference=" +
- reference +
- ", errorAppTag=" +
- errorAppTag +
- ", errorMessage=" +
- errorMessage +
- "]";
+ return MoreObjects.toStringHelper(this).add("regex", regex).add("description", description)
+ .add("reference", reference).add("errorAppTag", errorAppTag).add("errorMessage", errorMessage)
+ .add("modifier", modifier).toString();
}
}
\ No newline at end of file
package org.opendaylight.yangtools.yang.parser.spi.source;
import com.google.common.base.Preconditions;
+import java.util.Optional;
import javax.annotation.Nonnull;
/**
return obj;
}
+ /**
+ * Throw an instance of this exception if an optional is not present. If it is present, this method will return
+ * the unwrapped value.
+ *
+ * @param opt Optional to be checked
+ * @param source Statement source reference
+ * @param format Format string, according to {@link String#format(String, Object...)}.
+ * @param args Format string arguments, according to {@link String#format(String, Object...)}
+ * @return Object unwrapped from the opt optional
+ * @throws SourceException if the optional is not present
+ */
+ @Nonnull public static <T> T unwrap(final Optional<T> opt, @Nonnull final StatementSourceReference source,
+ @Nonnull final String format, final Object... args) {
+ throwIf(!opt.isPresent(), source, format, args);
+ return opt.get();
+ }
+
private static String createMessage(@Nonnull final String message, @Nonnull final StatementSourceReference source) {
Preconditions.checkNotNull(message);
Preconditions.checkNotNull(source);
import org.opendaylight.yangtools.yang.model.api.stmt.DescriptionStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ErrorAppTagStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ErrorMessageStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModifierStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.PatternStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceStatement;
import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
try {
Pattern.compile(pattern);
- } catch (PatternSyntaxException e) {
+ } catch (final PatternSyntaxException e) {
LOG.debug("Pattern \"{}\" failed to compile at {}", pattern, ctx.getStatementSourceReference(), e);
return null;
}
return firstDeclared(DescriptionStatement.class);
}
+ @Override
+ public ModifierStatement getModifierStatement() {
+ return firstDeclared(ModifierStatement.class);
+ }
+
@Override
public ReferenceStatement getReference() {
return firstDeclared(ReferenceStatement.class);
public PatternConstraint getValue() {
return argument();
}
-
}
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.IncludeStatementRfc7950Support;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.InputStatementRfc7950Support;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ListStatementRfc7950Support;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ModifierStatementImpl;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.ModuleStatementRfc7950Support;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.NotificationStatementRfc7950Support;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.OutputStatementRfc7950Support;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.PatternStatementRfc7950Support;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.RefineStatementRfc7950Support;
import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.SubmoduleStatementRfc7950Support;
.addVersionSpecificSupport(VERSION_1, new EnumStatementImpl.Definition())
.addVersionSpecificSupport(VERSION_1_1, new EnumStatementRfc7950Support())
.addSupport(new LengthStatementImpl.Definition())
- .addSupport(new PatternStatementImpl.Definition())
+ .addVersionSpecificSupport(VERSION_1, new PatternStatementImpl.Definition())
+ .addVersionSpecificSupport(VERSION_1_1, new PatternStatementRfc7950Support())
+ .addVersionSpecificSupport(VERSION_1_1, new ModifierStatementImpl.Definition())
.addSupport(new RangeStatementImpl.Definition())
.addVersionSpecificSupport(VERSION_1, new ContainerStatementImpl.Definition())
.addVersionSpecificSupport(VERSION_1_1, new ContainerStatementRfc7950Support())
@Override
public YangVersion parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
- try {
- return YangVersion.parse(value);
- } catch (IllegalArgumentException e) {
- throw new SourceException("Unsupported YANG version " + value, ctx.getStatementSourceReference(), e);
- }
+ return SourceException.unwrap(YangVersion.parse(value), ctx.getStatementSourceReference(),
+ "Unsupported YANG version %s", value);
}
@Override
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.ModifierKind;
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.ErrorAppTagEffectiveStatementImpl;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ErrorMessageEffectiveStatementImpl;
import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ReferenceEffectiveStatementImpl;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.effective.ModifierEffectiveStatementImpl;
abstract class AbstractConstraintEffectiveStatement<A, D extends DeclaredStatement<A>> extends
DeclaredEffectiveStatementBase<A, D> {
private final String reference;
private final String errorAppTag;
private final String errorMessage;
+ private final ModifierKind modifier;
private final A constraints;
- public AbstractConstraintEffectiveStatement(final StmtContext<A, D, ?> ctx, final ConstraintFactory<A> constraintFactory) {
+ public AbstractConstraintEffectiveStatement(final StmtContext<A, D, ?> ctx,
+ final ConstraintFactory<A> constraintFactory) {
super(ctx);
String descriptionInit = null;
String referenceInit = null;
String errorAppTagInit = null;
String errorMessageInit = null;
+ ModifierKind modifierInit = null;
- for (EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
+ for (final EffectiveStatement<?, ?> stmt : effectiveSubstatements()) {
if (stmt instanceof DescriptionEffectiveStatementImpl) {
descriptionInit = ((DescriptionEffectiveStatementImpl) stmt).argument();
}
if (stmt instanceof ErrorMessageEffectiveStatementImpl) {
errorMessageInit = ((ErrorMessageEffectiveStatementImpl) stmt).argument();
}
+ if (stmt instanceof ModifierEffectiveStatementImpl) {
+ modifierInit = ((ModifierEffectiveStatementImpl) stmt).argument();
+ }
}
this.description = descriptionInit;
this.reference = referenceInit;
this.errorAppTag = errorAppTagInit;
this.errorMessage = errorMessageInit;
+ this.modifier = modifierInit;
this.constraints = constraintFactory.createConstraints(this, super.argument());
}
public final boolean isCustomizedStatement() {
return this.description != null || this.reference != null || this.errorAppTag != null
- || this.errorMessage != null;
+ || this.errorMessage != null || this.modifier != null;
}
public final String getDescription() {
return description;
}
+ public final ModifierKind getModifier() {
+ return modifier;
+ }
+
public final String getReference() {
return reference;
}
abstract class ListConstraintFactory<A> extends ConstraintFactory<List<A>> {
@Override
- protected List<A> createConstraints(final AbstractConstraintEffectiveStatement<List<A>, ?> stmt, final List<A> argument) {
+ protected List<A> createConstraints(final AbstractConstraintEffectiveStatement<List<A>, ?> stmt,
+ final List<A> argument) {
if (!stmt.isCustomizedStatement()) {
return ImmutableList.copyOf(argument);
}
final List<A> customizedConstraints = new ArrayList<>(argument.size());
- for (A constraint : argument) {
+ for (final A constraint : argument) {
customizedConstraints.add(createCustomizedConstraint(constraint, stmt));
}
return ImmutableList.copyOf(customizedConstraints);
final class PatternConstraintFactory extends ConstraintFactory<PatternConstraint> {
@Override
- protected PatternConstraint createConstraints(final AbstractConstraintEffectiveStatement<PatternConstraint, ?> stmt, final PatternConstraint argument) {
+ protected PatternConstraint createConstraints(
+ final AbstractConstraintEffectiveStatement<PatternConstraint, ?> stmt, final PatternConstraint argument) {
if (!stmt.isCustomizedStatement()) {
return argument;
}
private static PatternConstraint createCustomizedConstraint(final PatternConstraint patternConstraint,
final AbstractConstraintEffectiveStatement<?, ?> stmt) {
return new PatternConstraintEffectiveImpl(patternConstraint.getRegularExpression(), stmt.getDescription(),
- stmt.getReference(), stmt.getErrorAppTag(), stmt.getErrorMessage());
+ stmt.getReference(), stmt.getErrorAppTag(), stmt.getErrorMessage(), stmt.getModifier());
}
}
\ No newline at end of file
*/
package org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.type;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import java.util.Objects;
+import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
public class PatternConstraintEffectiveImpl implements PatternConstraint {
private final String reference;
private final String errorAppTag;
private final String errorMessage;
+ private final ModifierKind modifier;
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));
+ "String %s is not valid regular expression.", regex), null);
}
public PatternConstraintEffectiveImpl(final String regex, final String description, final String reference,
- final String errorAppTag, final String errorMessage) {
+ final String errorAppTag, final String errorMessage, final ModifierKind modifier) {
super();
this.regEx = Preconditions.checkNotNull(regex, "regex must not be null.");
this.description = description;
this.errorAppTag = errorAppTag != null ? errorAppTag : "invalid-regular-expression";
this.errorMessage = errorMessage != null ? errorMessage : String.format(
"String %s is not valid regular expression.", regex);
+ this.modifier = modifier;
}
@Override
return errorMessage;
}
+ @Override
+ public ModifierKind getModifier() {
+ return modifier;
+ }
+
@Override
public String getReference() {
return reference;
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + Objects.hashCode(description);
- result = prime * result + Objects.hashCode(errorAppTag);
- result = prime * result + Objects.hashCode(errorMessage);
- result = prime * result + Objects.hashCode(reference);
- result = prime * result + regEx.hashCode();
- return result;
+ return Objects.hash(description, errorAppTag, errorMessage, reference, regEx, modifier);
}
@Override
return false;
}
final PatternConstraintEffectiveImpl other = (PatternConstraintEffectiveImpl) obj;
- if (!Objects.equals(description, other.description)) {
- return false;
- }
- if (!Objects.equals(errorAppTag, other.errorAppTag)) {
- return false;
- }
- if (!Objects.equals(errorMessage, other.errorMessage)) {
- return false;
- }
- if (!Objects.equals(reference, other.reference)) {
- return false;
- }
- if (!Objects.equals(regEx, other.regEx)) {
- return false;
- }
- return true;
+ return Objects.equals(description, other.description) && Objects.equals(errorAppTag, other.errorAppTag)
+ && Objects.equals(errorMessage, other.errorMessage) && Objects.equals(reference, other.reference)
+ && Objects.equals(regEx, other.regEx) && Objects.equals(modifier, other.modifier);
}
@Override
public String toString() {
- return PatternConstraintEffectiveImpl.class.getSimpleName() + " [regex=" + regEx + ", description="
- + description + ", reference=" + reference + ", errorAppTag=" + errorAppTag + ", errorMessage="
- + errorMessage + "]";
+ return MoreObjects.toStringHelper(this).add("regex", regEx).add("description", description)
+ .add("reference", reference).add("errorAppTag", errorAppTag).add("errorMessage", errorMessage)
+ .add("modifier", modifier).toString();
}
}
--- /dev/null
+/*
+ * 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.rfc7950;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModifierStatement;
+import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
+import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractDeclaredStatement;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc7950.effective.ModifierEffectiveStatementImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 Modifier statement.
+ */
+@Beta
+public final class ModifierStatementImpl extends AbstractDeclaredStatement<ModifierKind> implements ModifierStatement {
+ private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(
+ YangStmtMapping.MODIFIER).build();
+
+ protected ModifierStatementImpl(final StmtContext<ModifierKind, ModifierStatement, ?> context) {
+ super(context);
+ }
+
+ public static class Definition
+ extends
+ AbstractStatementSupport<ModifierKind, ModifierStatement, EffectiveStatement<ModifierKind, ModifierStatement>> {
+
+ public Definition() {
+ super(YangStmtMapping.MODIFIER);
+ }
+
+ @Override
+ public ModifierKind parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
+ return SourceException.unwrap(ModifierKind.parse(value), ctx.getStatementSourceReference(),
+ "'%s' is not valid argument of modifier statement", value);
+ }
+
+ @Override
+ public ModifierStatement createDeclared(final StmtContext<ModifierKind, ModifierStatement, ?> ctx) {
+ return new ModifierStatementImpl(ctx);
+ }
+
+ @Override
+ public EffectiveStatement<ModifierKind, ModifierStatement> createEffective(
+ final StmtContext<ModifierKind, ModifierStatement, EffectiveStatement<ModifierKind, ModifierStatement>> ctx) {
+ return new ModifierEffectiveStatementImpl(ctx);
+ }
+
+ @Override
+ public void onFullDefinitionDeclared(
+ final StmtContext.Mutable<ModifierKind, ModifierStatement, EffectiveStatement<ModifierKind, ModifierStatement>> stmt) {
+ super.onFullDefinitionDeclared(stmt);
+ getSubstatementValidator().validate(stmt);
+ }
+
+ @Override
+ protected SubstatementValidator getSubstatementValidator() {
+ return SUBSTATEMENT_VALIDATOR;
+ }
+ }
+
+ @Nonnull
+ @Override
+ public ModifierKind getValue() {
+ return argument();
+ }
+}
--- /dev/null
+/*
+ * 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.rfc7950;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.PatternStatementImpl;
+
+/**
+ * Class providing necessary support for processing YANG 1.1 Pattern statement.
+ */
+@Beta
+public final class PatternStatementRfc7950Support extends PatternStatementImpl.Definition {
+ private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
+ .PATTERN)
+ .addOptional(YangStmtMapping.DESCRIPTION)
+ .addOptional(YangStmtMapping.ERROR_APP_TAG)
+ .addOptional(YangStmtMapping.ERROR_MESSAGE)
+ .addOptional(YangStmtMapping.MODIFIER)
+ .addOptional(YangStmtMapping.REFERENCE)
+ .build();
+
+ @Override
+ protected SubstatementValidator getSubstatementValidator() {
+ return SUBSTATEMENT_VALIDATOR;
+ }
+}
--- /dev/null
+/*
+ * 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.rfc7950.effective;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModifierStatement;
+import org.opendaylight.yangtools.yang.model.api.type.ModifierKind;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.DeclaredEffectiveStatementBase;
+
+/**
+ * YANG 1.1 Modifier effective statement implementation.
+ */
+@Beta
+public final class ModifierEffectiveStatementImpl extends
+ DeclaredEffectiveStatementBase<ModifierKind, ModifierStatement> {
+ public ModifierEffectiveStatementImpl(final StmtContext<ModifierKind, ModifierStatement, ?> ctx) {
+ super(ctx);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("argument", argument()).toString();
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.rfc7950;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+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.ModifierKind;
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
+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.meta.SomeModifiersUnresolvedException;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.stmt.StmtTestUtils;
+
+public class Bug6870Test {
+ private static final String FOO_NS = "foo";
+ private static final String FOO_REV = "1970-01-01";
+
+ @Test
+ public void valid11Test() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+ final SchemaContext schemaContext = StmtTestUtils.parseYangSource("/rfc7950/bug6870/foo.yang");
+ assertNotNull(schemaContext);
+
+ assertModifier(schemaContext, ModifierKind.INVERT_MATCH, ImmutableList.of("root", "my-leaf"));
+ assertModifier(schemaContext, null, ImmutableList.of("root", "my-leaf-2"));
+ }
+
+ private void assertModifier(final SchemaContext schemaContext, final ModifierKind expectedModifierKind,
+ final List<String> localNamePath) {
+ final SchemaNode findNode = findNode(schemaContext, localNamePath);
+ assertTrue(findNode instanceof LeafSchemaNode);
+ final LeafSchemaNode myLeaf = (LeafSchemaNode) findNode;
+
+ final TypeDefinition<? extends TypeDefinition<?>> type = myLeaf.getType();
+ assertTrue(type instanceof StringTypeDefinition);
+ final StringTypeDefinition stringType = (StringTypeDefinition) type;
+
+ final List<PatternConstraint> patternConstraints = stringType.getPatternConstraints();
+ assertEquals(1, patternConstraints.size());
+
+ final PatternConstraint patternConstraint = patternConstraints.iterator().next();
+ assertEquals(expectedModifierKind, patternConstraint.getModifier());
+ }
+
+ private static SchemaNode findNode(final SchemaContext context, final Iterable<String> localNamesPath) {
+ final Iterable<QName> qNames = Iterables.transform(localNamesPath,
+ localName -> QName.create(FOO_NS, FOO_REV, localName));
+ return SchemaContextUtil.findDataSchemaNode(context, SchemaPath.create(qNames, true));
+ }
+
+ @Test
+ public void invalid11Test() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+ try {
+ StmtTestUtils.parseYangSource("/rfc7950/bug6870/invalid11.yang");
+ fail("Test should fail due to invalid Yang 1.1");
+ } catch (final SomeModifiersUnresolvedException e) {
+ assertTrue(e.getCause().getMessage()
+ .startsWith("'Invert-match' is not valid argument of modifier statement"));
+ }
+ }
+
+ @Test
+ public void invalid10Test() throws ReactorException, SourceException, FileNotFoundException, URISyntaxException {
+ try {
+ StmtTestUtils.parseYangSource("/rfc7950/bug6870/invalid10.yang");
+ fail("Test should fail due to invalid Yang 1.0");
+ } catch (final SomeModifiersUnresolvedException e) {
+ assertTrue(e.getCause().getMessage().startsWith("modifier is not a YANG statement or use of extension"));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+module foo {
+ namespace "foo";
+ prefix foo;
+ yang-version 1.1;
+
+ container root {
+ leaf my-leaf {
+ type string {
+ pattern '[xX][mM][lL].*' {
+ modifier invert-match;
+ }
+ }
+ }
+ leaf my-leaf-2 {
+ type string {
+ pattern '[xX][mM][lL].*' {
+ description "no modifier";
+ }
+ }
+ }
+ }
+}
--- /dev/null
+module foo {
+ namespace "foo";
+ prefix foo;
+
+ container root {
+ leaf my-leaf {
+ type string {
+ pattern '[xX][mM][lL].*' {
+ modifier invert-match;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+module foo {
+ namespace "foo";
+ prefix foo;
+ yang-version 1.1;
+
+ container root {
+ leaf my-leaf {
+ type string {
+ pattern '[xX][mM][lL].*' {
+ modifier Invert-match;
+ }
+ }
+ }
+ }
+}