*/
package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.unique;
+import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
+import java.util.regex.Pattern;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
+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.stmt.SchemaNodeIdentifier;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Relative;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Descendant;
+import org.opendaylight.yangtools.yang.model.api.stmt.UniqueEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.UniqueStatement;
import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.ArgumentUtils;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStatementSupport;
+import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
public final class UniqueStatementSupport
- extends AbstractStatementSupport<Collection<SchemaNodeIdentifier.Relative>, UniqueStatement,
- EffectiveStatement<Collection<SchemaNodeIdentifier.Relative>, UniqueStatement>> {
- private static final Splitter SPACE_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
+ extends BaseStatementSupport<Set<Descendant>, UniqueStatement, UniqueEffectiveStatement> {
+ /**
+ * Support 'sep' ABNF rule in RFC7950 section 14. CRLF pattern is used to squash line-break from CRLF to LF form
+ * and then we use SEP_SPLITTER, which can operate on single characters.
+ */
+ private static final Pattern CRLF_PATTERN = Pattern.compile("\r\n", Pattern.LITERAL);
+ private static final Splitter SEP_SPLITTER = Splitter.on(CharMatcher.anyOf(" \t\n").precomputed())
+ .omitEmptyStrings();
+
private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(
YangStmtMapping.UNIQUE)
.build();
}
@Override
- public Collection<SchemaNodeIdentifier.Relative> parseArgumentValue(final StmtContext<?, ?, ?> ctx,
- final String value) {
- final Collection<Relative> uniqueConstraints = parseUniqueConstraintArgument(ctx, value);
+ public ImmutableSet<Descendant> parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
+ final ImmutableSet<Descendant> uniqueConstraints = parseUniqueConstraintArgument(ctx, value);
SourceException.throwIf(uniqueConstraints.isEmpty(), ctx.getStatementSourceReference(),
"Invalid argument value '%s' of unique statement. The value must contains at least "
+ "one descendant schema node identifier.", value);
}
@Override
- public UniqueStatement createDeclared(final StmtContext<Collection<Relative>, UniqueStatement, ?> ctx) {
- return new UniqueStatementImpl(ctx);
+ protected SubstatementValidator getSubstatementValidator() {
+ return SUBSTATEMENT_VALIDATOR;
}
@Override
- public EffectiveStatement<Collection<Relative>, UniqueStatement> createEffective(
- final StmtContext<Collection<Relative>, UniqueStatement,
- EffectiveStatement<Collection<Relative>, UniqueStatement>> ctx) {
- return new UniqueEffectiveStatementImpl(ctx);
+ protected UniqueStatement createDeclared(final StmtContext<Set<Descendant>, UniqueStatement, ?> ctx,
+ final ImmutableList<? extends DeclaredStatement<?>> substatements) {
+ return new RegularUniqueStatement(ctx.coerceRawStatementArgument(), ctx.coerceStatementArgument(),
+ substatements);
}
@Override
- protected SubstatementValidator getSubstatementValidator() {
- return SUBSTATEMENT_VALIDATOR;
+ protected UniqueStatement createEmptyDeclared(final StmtContext<Set<Descendant>, UniqueStatement, ?> ctx) {
+ return new EmptyUniqueStatement(ctx.coerceRawStatementArgument(), ctx.coerceStatementArgument());
}
- private static Collection<SchemaNodeIdentifier.Relative> parseUniqueConstraintArgument(
- final StmtContext<?, ?, ?> ctx, final String argumentValue) {
- final Set<SchemaNodeIdentifier.Relative> uniqueConstraintNodes = new HashSet<>();
- for (final String uniqueArgToken : SPACE_SPLITTER.split(argumentValue)) {
+ @Override
+ protected UniqueEffectiveStatement createEffective(final Current<Set<Descendant>, UniqueStatement> stmt,
+ final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+ return substatements.isEmpty() ? new EmptyUniqueEffectiveStatement(stmt.declared())
+ : new RegularUniqueEffectiveStatement(stmt.declared(), substatements);
+
+ }
+
+ private static ImmutableSet<Descendant> parseUniqueConstraintArgument(final StmtContext<?, ?, ?> ctx,
+ final String argumentValue) {
+ // deal with 'line-break' rule, which is either "\n" or "\r\n", but not "\r"
+ final String nocrlf = CRLF_PATTERN.matcher(argumentValue).replaceAll("\n");
+
+ final Set<Descendant> uniqueConstraintNodes = new HashSet<>();
+ for (final String uniqueArgToken : SEP_SPLITTER.split(nocrlf)) {
final SchemaNodeIdentifier nodeIdentifier = ArgumentUtils.nodeIdentifierFromPath(ctx, uniqueArgToken);
- SourceException.throwIf(nodeIdentifier.isAbsolute(), ctx.getStatementSourceReference(),
+ SourceException.throwIf(nodeIdentifier instanceof Absolute, ctx.getStatementSourceReference(),
"Unique statement argument '%s' contains schema node identifier '%s' "
+ "which is not in the descendant node identifier form.", argumentValue, uniqueArgToken);
- uniqueConstraintNodes.add((SchemaNodeIdentifier.Relative) nodeIdentifier);
+ uniqueConstraintNodes.add((Descendant) nodeIdentifier);
}
return ImmutableSet.copyOf(uniqueConstraintNodes);
}