Make StatementSupport an abstract class 58/94658/5
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 19 Jan 2021 14:48:33 +0000 (15:48 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 19 Jan 2021 18:37:19 +0000 (19:37 +0100)
This interface contract is quite explicit and all implementations
rely on AbstractStatementSupport (except ForwardingStatementSupport).

Turn StatementSupport into an abstract class, absorbing
AbstractStatementSupport in process of doing so. This frees up a
place in which rfc7950.stmt.BaseStatementSupport can land.

JIRA: YANGTOOLS-1150
Change-Id: I99dd54249880ada1fc461a00f3c6b38ebf47f957
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/odlext-parser-support/src/main/java/org/opendaylight/yangtools/odlext/parser/AnyxmlStatementSupportOverride.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/BaseStatementSupport.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/extension/ModelDefinedStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java [deleted file]
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementSupport.java

index 7dc10a6a64e983863ebea2ba51ad70067fd960a0..c7096fd69204a5fb33c6656e8203f1c6379b9b8d 100644 (file)
@@ -14,7 +14,6 @@ import org.opendaylight.yangtools.odlext.model.api.AnyxmlSchemaLocationEffective
 import org.opendaylight.yangtools.odlext.model.api.AnyxmlSchemaLocationStatement;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AnyxmlStatement;
@@ -23,7 +22,6 @@ import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.anyxml.AnyxmlStatemen
 import org.opendaylight.yangtools.yang.parser.spi.SchemaTreeNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ForwardingStatementSupport;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 
@@ -32,24 +30,13 @@ public final class AnyxmlStatementSupportOverride
     private static final AnyxmlStatementSupportOverride INSTANCE = new AnyxmlStatementSupportOverride();
 
     private AnyxmlStatementSupportOverride() {
-
+        super(AnyxmlStatementSupport.getInstance());
     }
 
     public static AnyxmlStatementSupportOverride getInstance() {
         return INSTANCE;
     }
 
-    @Override
-    protected StatementSupport<QName, AnyxmlStatement, AnyxmlEffectiveStatement> delegate() {
-        return AnyxmlStatementSupport.getInstance();
-    }
-
-    @Override
-    public Class<? extends EffectiveStatement<?, ?>> getEffectiveRepresentationClass() {
-        // FIXME: this is not entirely accurate?
-        return delegate().getEffectiveRepresentationClass();
-    }
-
     @Override
     public AnyxmlEffectiveStatement createEffective(final Current<QName, AnyxmlStatement> stmt,
             final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
index 964cf3b6ce490b772d8b7650ff86c6a833ff858c..28c8dae37f90598667cb70d2f08387ece0ef9296 100644 (file)
@@ -21,12 +21,12 @@ import org.eclipse.jdt.annotation.Nullable;
 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.meta.StatementDefinition;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 
 /**
- * Implementation-internal base class for {@link AbstractStatementSupport} implementations.
+ * Implementation-internal base class for {@link StatementSupport} implementations.
  *
  * @param <A> Argument type
  * @param <D> Declared Statement representation
@@ -36,7 +36,8 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 //        we rely on  getEffectOfStatement() -- which is something reactor mechanics need to make work better.
 @Beta
 public abstract class BaseStatementSupport<A, D extends DeclaredStatement<A>,
-        E extends EffectiveStatement<A, D>> extends AbstractStatementSupport<A, D, E> {
+        E extends EffectiveStatement<A, D>> extends StatementSupport<A, D, E> {
+
     @Deprecated
     protected BaseStatementSupport(final StatementDefinition publicDefinition, final CopyPolicy copyPolicy) {
         super(publicDefinition, copyPolicy);
index 31ad29a9af02ff851e6698b6f626e128bb7ea552..02be149702b86cc5f7786a6b3060e0e3daac0260 100644 (file)
@@ -12,7 +12,6 @@ import java.util.stream.Stream;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 import org.opendaylight.yangtools.yang.model.api.stmt.UnrecognizedEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UnrecognizedStatement;
-import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
@@ -25,7 +24,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
  * @author Robert Varga
  */
 final class ModelDefinedStatementSupport
-        extends AbstractStatementSupport<String, UnrecognizedStatement, UnrecognizedEffectiveStatement> {
+        extends StatementSupport<String, UnrecognizedStatement, UnrecognizedEffectiveStatement> {
     private final UnrecognizedStatementSupport definition;
 
     ModelDefinedStatementSupport(final ModelDefinedStatementDefinition publicDefinition) {
diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java
deleted file mode 100644 (file)
index f8ddbf3..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (c) 2015 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.spi.meta;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.VerifyException;
-import java.util.Collection;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.concepts.Immutable;
-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.meta.StatementDefinition;
-import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
-
-/**
- * Class providing necessary support for processing a YANG statement. This class is intended to be subclassed
- * by developers who want to add semantic support for a statement to a parser reactor.
- *
- * @param <A> Argument type
- * @param <D> Declared Statement representation
- * @param <E> Effective Statement representation
- */
-public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
-        implements StatementDefinition, StatementFactory<A, D, E>, StatementSupport<A, D, E> {
-    /**
-     * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}
-     * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
-     *
-     * @param <A> Argument type
-     * @param <D> Declared Statement representation
-     */
-    public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
-        final @NonNull CopyPolicy copyPolicy;
-
-        StatementPolicy(final CopyPolicy copyPolicy) {
-            this.copyPolicy = requireNonNull(copyPolicy);
-        }
-
-        /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
-         *
-         * @param <A> Argument type
-         * @param <D> Declared Statement representation
-         * @return Context-independent policy
-         */
-        @SuppressWarnings("unchecked")
-        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
-            return (StatementPolicy<A, D>) AlwaysReuse.CONTEXT_INDEPENDENT;
-        }
-
-        /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
-         *
-         * @param <A> Argument type
-         * @param <D> Declared Statement representation
-         * @return Ignoring policy
-         */
-        @SuppressWarnings("unchecked")
-        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
-            return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
-        }
-
-        /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
-         *
-         * @param <A> Argument type
-         * @param <D> Declared Statement representation
-         * @return Rejecting statement policy
-         */
-        @SuppressWarnings("unchecked")
-        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
-            return (StatementPolicy<A, D>) AlwaysFail.REJECT;
-        }
-
-        /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
-         * {@link StatementEquality} for individual decisions.
-         *
-         * @param <A> Argument type
-         * @param <D> Declared Statement representation
-         * @param equality {@link StatementEquality} to apply to effective statements
-         * @return Rejecting statement policy
-         */
-        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> copyDeclared(
-                final @NonNull StatementEquality<A, D> equality) {
-            return new EqualSemantics<>(equality);
-        }
-
-        abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
-            @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
-
-        @Deprecated
-        @SuppressWarnings("unchecked")
-        static <A, D extends DeclaredStatement<A>> StatementPolicy<A, D> compat(final CopyPolicy copyPolicy) {
-            switch (copyPolicy) {
-                case CONTEXT_INDEPENDENT:
-                    return contextIndependent();
-                case DECLARED_COPY:
-                    return (StatementPolicy<A, D>) AlwaysCopy.DECLARED_COPY;
-                case IGNORE:
-                    return ignore();
-                case REJECT:
-                    return reject();
-                default:
-                    throw new IllegalStateException("Unsupported policy " + copyPolicy);
-            }
-        }
-
-        private static final class AlwaysCopy<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
-            @Deprecated
-            static final @NonNull AlwaysCopy<?, ?> DECLARED_COPY = new AlwaysCopy<>(CopyPolicy.DECLARED_COPY);
-
-            AlwaysCopy(final CopyPolicy copyPolicy) {
-                super(copyPolicy);
-            }
-
-            @Override
-            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
-                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
-                return false;
-            }
-        }
-
-        private static final class AlwaysReuse<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
-            static final @NonNull AlwaysReuse<?, ?> CONTEXT_INDEPENDENT =
-                new AlwaysReuse<>(CopyPolicy.CONTEXT_INDEPENDENT);
-
-            private AlwaysReuse(final CopyPolicy copyPolicy) {
-                super(copyPolicy);
-            }
-
-            @Override
-            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
-                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
-                return true;
-            }
-        }
-
-        private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
-            static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
-            static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
-
-            private AlwaysFail(final CopyPolicy copyPolicy) {
-                super(copyPolicy);
-            }
-
-            @Override
-            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
-                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
-                throw new VerifyException("This implementation should never be invoked");
-            }
-        }
-
-        private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
-            private final @NonNull StatementEquality<A, D> equality;
-
-            EqualSemantics(final @NonNull StatementEquality<A, D> equality) {
-                super(CopyPolicy.DECLARED_COPY);
-                this.equality = requireNonNull(equality);
-            }
-
-            @Override
-            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
-                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
-                return equality.canReuseCurrent(copy, current, substatements);
-            }
-        }
-    }
-
-    /**
-     * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
-     * policy.
-     *
-     * @param <A> Argument type
-     * @param <D> Declared Statement representation
-     */
-    @FunctionalInterface
-    public interface StatementEquality<A, D extends DeclaredStatement<A>> {
-        /**
-         * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
-         * specification of {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}.
-         *
-         * @param copy Copy of current effective context
-         * @param current Current effective context
-         * @param substatements Current effective substatements
-         * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
-         */
-        boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
-            @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
-    }
-
-    private final @NonNull StatementPolicy<A, D> policy;
-    private final @NonNull StatementDefinition type;
-    private final @NonNull CopyPolicy copyPolicy;
-
-    @Beta
-    protected AbstractStatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
-        this.type = requireNonNull(publicDefinition);
-        this.policy = requireNonNull(policy);
-        this.copyPolicy = policy.copyPolicy;
-        checkArgument(publicDefinition != this);
-    }
-
-    @Beta
-    @Deprecated
-    // FIXME: remove this constructor
-    protected AbstractStatementSupport(final StatementDefinition publicDefinition, final CopyPolicy copyPolicy) {
-        this(publicDefinition, StatementPolicy.compat(copyPolicy));
-    }
-
-    @Override
-    public final StatementDefinition getPublicView() {
-        return type;
-    }
-
-    @Override
-    public final CopyPolicy copyPolicy() {
-        return copyPolicy;
-    }
-
-    @Override
-    public final boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
-             final Collection<? extends EffectiveStatement<?, ?>> substatements) {
-        return policy.canReuseCurrent(copy, current, substatements);
-    }
-
-    @Override
-    public void onStatementAdded(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
-    }
-
-    /**
-     * {@inheritDoc}.
-     *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
-     */
-    @Override
-    public void onPreLinkageDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
-    }
-
-    /**
-     * {@inheritDoc}.
-     *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
-     */
-    @Override
-    public void onLinkageDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
-    }
-
-    /**
-     * {@inheritDoc}.
-     *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
-     */
-    @Override
-    public void onStatementDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        // NOOP for most implementations
-    }
-
-    /**
-     * {@inheritDoc}.
-     *
-     * <p>
-     * Subclasses of this class may override this method to perform actions on this event or register a modification
-     * action using {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
-     */
-    @Override
-    public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        final SubstatementValidator validator = getSubstatementValidator();
-        if (validator != null) {
-            validator.validate(stmt);
-        }
-    }
-
-    @Override
-    public boolean hasArgumentSpecificSupports() {
-        // Most of statement supports don't have any argument specific supports, so return 'false'.
-        return false;
-    }
-
-    @Override
-    public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
-        // Most of statement supports don't have any argument specific supports, so return null.
-        return null;
-    }
-
-    /**
-     * Returns corresponding substatement validator of a statement support.
-     *
-     * @return substatement validator or null, if substatement validator is not defined
-     */
-    protected abstract @Nullable SubstatementValidator getSubstatementValidator();
-}
index 0d15f1451aea98c63489027962bb242d655a0c3f..7597410e4119a58d75ccc0a54486dc932a4f1b68 100644 (file)
@@ -8,12 +8,9 @@
 package org.opendaylight.yangtools.yang.parser.spi.meta;
 
 import com.google.common.annotations.Beta;
-import com.google.common.collect.ForwardingObject;
-import java.util.Collection;
 import java.util.stream.Stream;
 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.meta.StatementDefinition;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 
@@ -29,76 +26,73 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
  */
 @Beta
 public abstract class ForwardingStatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
-    extends ForwardingObject implements StatementSupport<A, D, E> {
+        extends StatementSupport<A, D, E> {
+    private final StatementSupport<A, D, E> delegate;
 
-    @Override
-    protected abstract StatementSupport<A, D, E> delegate();
+    protected ForwardingStatementSupport(final StatementSupport<A, D, E> delegate) {
+        super(delegate.getPublicView(), delegate.copyPolicy());
+        this.delegate = delegate;
+    }
 
     @Override
     public D createDeclared(final StmtContext<A, D, ?> ctx) {
-        return delegate().createDeclared(ctx);
+        return delegate.createDeclared(ctx);
     }
 
     @Override
     public E createEffective(final Current<A, D> stmt,
             final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
             final Stream<? extends StmtContext<?, ?, ?>> effectiveSubstatements) {
-        return delegate().createEffective(stmt, declaredSubstatements, effectiveSubstatements);
-    }
-
-    @Override
-    public StatementDefinition getPublicView() {
-        return delegate().getPublicView();
+        return delegate.createEffective(stmt, declaredSubstatements, effectiveSubstatements);
     }
 
     @Override
     public A parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
-        return delegate().parseArgumentValue(ctx, value);
+        return delegate.parseArgumentValue(ctx, value);
     }
 
     @Override
     public void onStatementAdded(final Mutable<A, D, E> stmt) {
-        delegate().onStatementAdded(stmt);
+        delegate.onStatementAdded(stmt);
     }
 
     @Override
     public void onPreLinkageDeclared(final Mutable<A, D, E> stmt) {
-        delegate().onPreLinkageDeclared(stmt);
+        delegate.onPreLinkageDeclared(stmt);
     }
 
     @Override
     public void onLinkageDeclared(final Mutable<A, D, E> stmt) {
-        delegate().onLinkageDeclared(stmt);
+        delegate.onLinkageDeclared(stmt);
     }
 
     @Override
     public void onStatementDefinitionDeclared(final Mutable<A, D, E> stmt) {
-        delegate().onStatementDefinitionDeclared(stmt);
+        delegate.onStatementDefinitionDeclared(stmt);
     }
 
     @Override
     public void onFullDefinitionDeclared(final Mutable<A, D, E> stmt) {
-        delegate().onFullDefinitionDeclared(stmt);
+        delegate.onFullDefinitionDeclared(stmt);
     }
 
     @Override
     public boolean hasArgumentSpecificSupports() {
-        return delegate().hasArgumentSpecificSupports();
+        return delegate.hasArgumentSpecificSupports();
     }
 
     @Override
     public StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
-        return delegate().getSupportSpecificForArgument(argument);
+        return delegate.getSupportSpecificForArgument(argument);
     }
 
     @Override
-    public CopyPolicy copyPolicy() {
-        return delegate().copyPolicy();
+    protected SubstatementValidator getSubstatementValidator() {
+        return delegate.getSubstatementValidator();
     }
 
     @Override
-    public boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
-            final Collection<? extends EffectiveStatement<?, ?>> substatements) {
-        return delegate().canReuseCurrent(copy, current, substatements);
+    public String toString() {
+        return delegate.toString();
     }
 }
index 05e5f47f4c8e0348ca9e72c50049eead268e3614..0db0df1a9e8a4691d054af3170a4187a75da7e95 100644 (file)
@@ -7,16 +7,24 @@
  */
 package org.opendaylight.yangtools.yang.parser.spi.meta;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
+import com.google.common.base.VerifyException;
+import java.util.Collection;
 import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.meta.ArgumentDefinition;
 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.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
 /**
@@ -24,14 +32,199 @@ import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
  *
  * <p>
  * This interface is intended to be implemented by developers, which want to introduce support of statement to parser.
- * Consider subclassing {@link AbstractStatementSupport} for easier implementation of this interface.
  *
  * @param <A> Argument type
  * @param <D> Declared Statement representation
  * @param <E> Effective Statement representation
  */
-public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
-        extends StatementDefinition, StatementFactory<A, D, E> {
+public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
+        implements StatementDefinition, StatementFactory<A, D, E> {
+    /**
+     * A baseline class for implementing the {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}
+     * contract in a manner which is consistent with a statement's {@link CopyPolicy}.
+     *
+     * @param <A> Argument type
+     * @param <D> Declared Statement representation
+     */
+    public abstract static class StatementPolicy<A, D extends DeclaredStatement<A>> implements Immutable {
+        final @NonNull CopyPolicy copyPolicy;
+
+        StatementPolicy(final CopyPolicy copyPolicy) {
+            this.copyPolicy = requireNonNull(copyPolicy);
+        }
+
+        /**
+         * Return an {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
+         *
+         * @param <A> Argument type
+         * @param <D> Declared Statement representation
+         * @return Context-independent policy
+         */
+        @SuppressWarnings("unchecked")
+        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
+            return (StatementPolicy<A, D>) AlwaysReuse.CONTEXT_INDEPENDENT;
+        }
+
+        /**
+         * Return an {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
+         *
+         * @param <A> Argument type
+         * @param <D> Declared Statement representation
+         * @return Ignoring policy
+         */
+        @SuppressWarnings("unchecked")
+        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> ignore() {
+            return (StatementPolicy<A, D>) AlwaysFail.IGNORE;
+        }
+
+        /**
+         * Return an {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
+         *
+         * @param <A> Argument type
+         * @param <D> Declared Statement representation
+         * @return Rejecting statement policy
+         */
+        @SuppressWarnings("unchecked")
+        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> reject() {
+            return (StatementPolicy<A, D>) AlwaysFail.REJECT;
+        }
+
+        /**
+         * Return an {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
+         * {@link StatementEquality} for individual decisions.
+         *
+         * @param <A> Argument type
+         * @param <D> Declared Statement representation
+         * @param equality {@link StatementEquality} to apply to effective statements
+         * @return Rejecting statement policy
+         */
+        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> copyDeclared(
+                final @NonNull StatementEquality<A, D> equality) {
+            return new EqualSemantics<>(equality);
+        }
+
+        abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
+            @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
+
+        @Deprecated
+        @SuppressWarnings("unchecked")
+        static <A, D extends DeclaredStatement<A>> StatementPolicy<A, D> compat(final CopyPolicy copyPolicy) {
+            switch (copyPolicy) {
+                case CONTEXT_INDEPENDENT:
+                    return contextIndependent();
+                case DECLARED_COPY:
+                    return (StatementPolicy<A, D>) AlwaysCopy.DECLARED_COPY;
+                case IGNORE:
+                    return ignore();
+                case REJECT:
+                    return reject();
+                default:
+                    throw new IllegalStateException("Unsupported policy " + copyPolicy);
+            }
+        }
+
+        private static final class AlwaysCopy<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+            @Deprecated
+            static final @NonNull AlwaysCopy<?, ?> DECLARED_COPY = new AlwaysCopy<>(CopyPolicy.DECLARED_COPY);
+
+            AlwaysCopy(final CopyPolicy copyPolicy) {
+                super(copyPolicy);
+            }
+
+            @Override
+            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+                return false;
+            }
+        }
+
+        private static final class AlwaysReuse<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+            static final @NonNull AlwaysReuse<?, ?> CONTEXT_INDEPENDENT =
+                new AlwaysReuse<>(CopyPolicy.CONTEXT_INDEPENDENT);
+
+            private AlwaysReuse(final CopyPolicy copyPolicy) {
+                super(copyPolicy);
+            }
+
+            @Override
+            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+                return true;
+            }
+        }
+
+        private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+            static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
+            static final @NonNull AlwaysFail<?, ?> REJECT = new AlwaysFail<>(CopyPolicy.REJECT);
+
+            private AlwaysFail(final CopyPolicy copyPolicy) {
+                super(copyPolicy);
+            }
+
+            @Override
+            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+                throw new VerifyException("This implementation should never be invoked");
+            }
+        }
+
+        private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+            private final @NonNull StatementEquality<A, D> equality;
+
+            EqualSemantics(final @NonNull StatementEquality<A, D> equality) {
+                super(CopyPolicy.DECLARED_COPY);
+                this.equality = requireNonNull(equality);
+            }
+
+            @Override
+            boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+                    final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+                return equality.canReuseCurrent(copy, current, substatements);
+            }
+        }
+    }
+
+    /**
+     * Abstract base class for comparators associated with statements with a {@link CopyPolicy#DECLARED_COPY} copy
+     * policy.
+     *
+     * @param <A> Argument type
+     * @param <D> Declared Statement representation
+     */
+    @FunctionalInterface
+    public interface StatementEquality<A, D extends DeclaredStatement<A>> {
+        /**
+         * Determine whether {@code current} statement has the same semantics as the provided copy. See the contract
+         * specification of {@link StatementFactory#canReuseCurrent(Current, Current, Collection)}.
+         *
+         * @param copy Copy of current effective context
+         * @param current Current effective context
+         * @param substatements Current effective substatements
+         * @return True if {@code current} can be reused in place of {@code copy}, false if the copy needs to be used.
+         */
+        boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
+            @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
+    }
+
+    private final @NonNull StatementPolicy<A, D> policy;
+    private final @NonNull StatementDefinition def;
+    private final @NonNull CopyPolicy copyPolicy;
+
+    @Beta
+    protected StatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
+        checkArgument(publicDefinition != this);
+        this.def = requireNonNull(publicDefinition);
+        this.policy = requireNonNull(policy);
+        this.copyPolicy = policy.copyPolicy;
+    }
+
+    @Beta
+    @Deprecated
+    // FIXME: remove this constructor
+    protected StatementSupport(final StatementDefinition publicDefinition, final CopyPolicy copyPolicy) {
+        this(publicDefinition, StatementPolicy.compat(copyPolicy));
+    }
+
     /**
      * Returns public statement definition, which will be present in built statements.
      *
@@ -41,7 +234,52 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      *
      * @return public statement definition, which will be present in built statements.
      */
-    @NonNull StatementDefinition getPublicView();
+    public final @NonNull StatementDefinition getPublicView() {
+        return def;
+    }
+
+    /**
+     * Return this statement's {@link CopyPolicy}. This is a static value, reflecting how this statement reacts to being
+     * replicated to a different context, without reflecting on behaviour of potential substatements, which would come
+     * into play in something like:
+     *
+     * <pre>
+     *   <code>
+     *     module foo {
+     *       namespace foo;
+     *       prefix foo;
+     *
+     *       extension note {
+     *         argument string {
+     *           type string {
+     *             length 1..max;
+     *           }
+     *         }
+     *         description "Can be used in description/reference statements to attach additional notes";
+     *       }
+     *
+     *       description "A nice module extending description statement semantics" {
+     *         foo:note "We can now attach description/reference a note.";
+     *         foo:note "Also another note";
+     *       }
+     *     }
+     *   </code>
+     * </pre>
+     *
+     * <p>
+     * In this scenario, it is the reactor's job to figure out what to do (like talking to substatements).
+     *
+     * @return This statement's copy policy
+     */
+    public final @NonNull CopyPolicy copyPolicy() {
+        return copyPolicy;
+    }
+
+    @Override
+    public final boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
+            final Collection<? extends EffectiveStatement<?, ?>> substatements) {
+        return policy.canReuseCurrent(copy, current, substatements);
+    }
 
     /**
      * Parses textual representation of argument in object representation.
@@ -51,16 +289,17 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * @return Parsed value
      * @throws SourceException when an inconsistency is detected.
      */
-    A parseArgumentValue(StmtContext<?, ?, ?> ctx, String value);
+    public abstract A parseArgumentValue(StmtContext<?, ?, ?> ctx, String value);
 
     /**
-     * Adapts the argument value to match a new module.
+     * Adapts the argument value to match a new module. Default implementation returns original value stored in context,
+     * which is appropriate for most implementations.
      *
      * @param ctx Context, which may be used to access source-specific namespaces required for parsing.
      * @param targetModule Target module, may not be null.
-     * @return Adapted argument value. The default implementation returns original value stored in context.
+     * @return Adapted argument value.
      */
-    default A adaptArgumentValue(final StmtContext<A, D, E> ctx, final QNameModule targetModule) {
+    public A adaptArgumentValue(final @NonNull StmtContext<A, D, E> ctx, final @NonNull QNameModule targetModule) {
         return ctx.argument();
     }
 
@@ -72,7 +311,9 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      *
      * @param stmt Context of added statement. No substatements are available.
      */
-    void onStatementAdded(StmtContext.Mutable<A, D, E> stmt);
+    public void onStatementAdded(final @NonNull Mutable<A, D, E> stmt) {
+        // NOOP for most implementations
+    }
 
     /**
      * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_PRE_LINKAGE} phase, only substatements
@@ -80,11 +321,13 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      *
      * <p>
      * Implementation may use method to perform actions on this event or register modification action using
-     * {@link StmtContext.Mutable#newInferenceAction(ModelProcessingPhase)}.
+     * {@link Mutable#newInferenceAction(ModelProcessingPhase)}.
      *
      * @param stmt Context of added statement.
      */
-    void onPreLinkageDeclared(StmtContext.Mutable<A, D, E> stmt);
+    public void onPreLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
+        // NOOP for most implementations
+    }
 
     /**
      * Invoked when statement is closed during {@link ModelProcessingPhase#SOURCE_LINKAGE} phase, only substatements
@@ -97,7 +340,9 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * @param stmt Context of added statement.
      * @throws SourceException when an inconsistency is detected.
      */
-    void onLinkageDeclared(StmtContext.Mutable<A, D, E> stmt);
+    public void onLinkageDeclared(final @NonNull Mutable<A, D, E> stmt) {
+        // NOOP for most implementations
+    }
 
     /**
      * Invoked when statement is closed during {@link ModelProcessingPhase#STATEMENT_DEFINITION} phase,
@@ -110,7 +355,9 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * @param stmt Context of added statement. Argument and statement parent is accessible.
      * @throws SourceException when an inconsistency is detected.
      */
-    void onStatementDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt);
+    public void onStatementDefinitionDeclared(final Mutable<A, D, E> stmt) {
+        // NOOP for most implementations
+    }
 
     /**
      * Invoked when statement is closed during {@link ModelProcessingPhase#FULL_DECLARATION} phase,
@@ -123,12 +370,28 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * @param stmt Context of added statement. Argument and statement parent is accessible.
      * @throws SourceException when an inconsistency is detected.
      */
-    void onFullDefinitionDeclared(StmtContext.Mutable<A, D, E> stmt);
+    public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
+        final SubstatementValidator validator = getSubstatementValidator();
+        if (validator != null) {
+            validator.validate(stmt);
+        }
+    }
+
+    /**
+     * Returns corresponding substatement validator of a statement support.
+     *
+     * @return substatement validator or null, if substatement validator is not defined
+     */
+    // FIXME: rename to 'substatementValidator' and perhaps let it be passed in?
+    protected abstract @Nullable SubstatementValidator getSubstatementValidator();
 
     /**
      * Returns true if this support has argument specific supports.
      */
-    boolean hasArgumentSpecificSupports();
+    public boolean hasArgumentSpecificSupports() {
+        // Most of statement supports don't have any argument specific supports, so return 'false'.
+        return false;
+    }
 
     /**
      * If this support has argument specific supports, the method returns support specific for given argument
@@ -137,61 +400,31 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * @param argument argument of statement
      * @return statement support specific for supplied argument or null
      */
-    @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(String argument);
-
-    /**
-     * Return this statement's {@link CopyPolicy}. This is a static value, reflecting how this statement reacts to being
-     * replicated to a different context, without reflecting on behaviour of potential substatements, which would come
-     * into play in something like:
-     *
-     * <pre>
-     *   <code>
-     *     module foo {
-     *       namespace foo;
-     *       prefix foo;
-     *
-     *       extension note {
-     *         argument string {
-     *           type string {
-     *             length 1..max;
-     *           }
-     *         }
-     *         description "Can be used in description/reference statements to attach additional notes";
-     *       }
-     *
-     *       description "A nice module extending description statement semantics" {
-     *         foo:note "We can now attach description/reference a note.";
-     *         foo:note "Also another note";
-     *       }
-     *     }
-     *   </code>
-     * </pre>
-     *
-     * <p>
-     * In this scenario, it is the reactor's job to figure out what to do (like talking to substatements).
-     *
-     * @return This statement's copy policy
-     */
-    @NonNull CopyPolicy copyPolicy();
+    public @Nullable StatementSupport<?, ?, ?> getSupportSpecificForArgument(final String argument) {
+        // Most of statement supports don't have any argument specific supports, so return null.
+        return null;
+    }
 
     /**
-     * Given a raw string representation of an argument, try to use a shared representation.
+     * Given a raw string representation of an argument, try to use a shared representation. Default implementation
+     * does nothing.
      *
      * @param rawArgument Argument string
      * @return A potentially-shard instance
      */
-    default String internArgument(final String rawArgument) {
+    public String internArgument(final String rawArgument) {
         return rawArgument;
     }
 
     /**
-     * Returns unknown statement form of a regular YANG statement supplied as a parameter to the method.
+     * Returns unknown statement form of a regular YANG statement supplied as a parameter to the method. Default
+     * implementation does nothing.
      *
      * @param yangStmtDef statement definition of a regular YANG statement
      * @return Optional of unknown statement form of a regular YANG statement or empty() if it is not supported by this
      *         statement support
      */
-    default Optional<StatementSupport<?, ?, ?>> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) {
+    public Optional<StatementSupport<?, ?, ?>> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) {
         return Optional.empty();
     }
 
@@ -200,11 +433,10 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      * extension defined in <a href="https://tools.ietf.org/html/rfc8040#section-8">RFC 8040</a>). Default
      * implementation returns false.
      *
-     * @return true if this statement support ignores if-feature statements,
-     *         otherwise false.
+     * @return true if this statement support ignores if-feature statements, otherwise false.
      */
     @Beta
-    default boolean isIgnoringIfFeatures() {
+    public boolean isIgnoringIfFeatures() {
         return false;
     }
 
@@ -217,35 +449,37 @@ public interface StatementSupport<A, D extends DeclaredStatement<A>, E extends E
      *         otherwise false.
      */
     @Beta
-    default boolean isIgnoringConfig() {
+    public boolean isIgnoringConfig() {
         return false;
     }
 
     @Override
-    default QName getStatementName() {
-        return getPublicView().getStatementName();
+    public final QName getStatementName() {
+        return def.getStatementName();
     }
 
     @Override
-    default @NonNull Optional<ArgumentDefinition> getArgumentDefinition() {
-        return getPublicView().getArgumentDefinition();
+    public final Optional<ArgumentDefinition> getArgumentDefinition() {
+        return def.getArgumentDefinition();
     }
 
     @Override
-    default Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
-        return getPublicView().getDeclaredRepresentationClass();
+    // Non-final for compatible extensions
+    public Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
+        return def.getDeclaredRepresentationClass();
     }
 
     @Override
-    default Class<? extends EffectiveStatement<?,?>> getEffectiveRepresentationClass() {
-        return getPublicView().getEffectiveRepresentationClass();
+    // Non-final for compatible extensions
+    public Class<? extends EffectiveStatement<?,?>> getEffectiveRepresentationClass() {
+        return def.getEffectiveRepresentationClass();
     }
 
     /**
      * Statement context copy policy, indicating how should reactor handle statement copy operations. Every statement
      * copied by the reactor is subject to this policy.
      */
-    enum CopyPolicy {
+    public enum CopyPolicy {
         /**
          * Reuse the source statement context in the new place, as it cannot be affected by any further operations. This
          * implies that the semantics of the effective statement are not affected by any of its substatements. Each