Centralize substatement validators
[yangtools.git] / yang / yang-parser-spi / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / StatementSupport.java
index 0db0df1a9e8a4691d054af3170a4187a75da7e95..0db910ffaf15505e09b0fbd35900aad05b493ca3 100644 (file)
@@ -32,6 +32,7 @@ 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
@@ -54,7 +55,7 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
         }
 
         /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
+         * Return a {@link StatementPolicy} for {@link CopyPolicy#CONTEXT_INDEPENDENT}.
          *
          * @param <A> Argument type
          * @param <D> Declared Statement representation
@@ -62,11 +63,23 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
          */
         @SuppressWarnings("unchecked")
         public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> contextIndependent() {
-            return (StatementPolicy<A, D>) AlwaysReuse.CONTEXT_INDEPENDENT;
+            return (StatementPolicy<A, D>) EqualSemantics.CONTEXT_INDEPENDENT;
         }
 
         /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
+         * Return a {@link StatementPolicy} for {@link CopyPolicy#EXACT_REPLICA}.
+         *
+         * @param <A> Argument type
+         * @param <D> Declared Statement representation
+         * @return Exact-replica policy
+         */
+        @SuppressWarnings("unchecked")
+        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> exactReplica() {
+            return (StatementPolicy<A, D>) EqualSemantics.EXACT_REPLICA;
+        }
+
+        /**
+         * Return a {@link StatementPolicy} for {@link CopyPolicy#IGNORE}.
          *
          * @param <A> Argument type
          * @param <D> Declared Statement representation
@@ -78,7 +91,7 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
         }
 
         /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
+         * Return a {@link StatementPolicy} for {@link CopyPolicy#REJECT}.
          *
          * @param <A> Argument type
          * @param <D> Declared Statement representation
@@ -90,68 +103,33 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
         }
 
         /**
-         * Return an {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, deferring to a
+         * Return a {@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
+         * @return Equality-based 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
+        /**
+         * Return a {@link StatementPolicy} for {@link CopyPolicy#DECLARED_COPY}, always performing a copy operation.
+         *
+         * @param <A> Argument type
+         * @param <D> Declared Statement representation
+         * @return Rejecting statement policy
+         */
         @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);
-            }
+        public static final <A, D extends DeclaredStatement<A>> @NonNull StatementPolicy<A, D> alwaysCopyDeclared() {
+            return (StatementPolicy<A, D>) EqualSemantics.ALWAYS_COPY;
         }
 
-        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;
-            }
-        }
+        abstract boolean canReuseCurrent(@NonNull Current<A, D> copy, @NonNull Current<A, D> current,
+            @NonNull Collection<? extends EffectiveStatement<?, ?>> substatements);
 
         private static final class AlwaysFail<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
             static final @NonNull AlwaysFail<?, ?> IGNORE = new AlwaysFail<>(CopyPolicy.IGNORE);
@@ -169,13 +147,24 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
         }
 
         private static final class EqualSemantics<A, D extends DeclaredStatement<A>> extends StatementPolicy<A, D> {
+            static final @NonNull EqualSemantics<?, ?> ALWAYS_COPY =
+                new EqualSemantics<>((copy, stmt, substatements) -> false);
+            static final @NonNull EqualSemantics<?, ?> CONTEXT_INDEPENDENT =
+                new EqualSemantics<>(CopyPolicy.CONTEXT_INDEPENDENT, (copy, stmt, substatements) -> true);
+            static final @NonNull EqualSemantics<?, ?> EXACT_REPLICA =
+                new EqualSemantics<>(CopyPolicy.EXACT_REPLICA, (copy, stmt, substatements) -> true);
+
             private final @NonNull StatementEquality<A, D> equality;
 
-            EqualSemantics(final @NonNull StatementEquality<A, D> equality) {
-                super(CopyPolicy.DECLARED_COPY);
+            private EqualSemantics(final CopyPolicy copyPolicy, final StatementEquality<A, D> equality) {
+                super(copyPolicy);
                 this.equality = requireNonNull(equality);
             }
 
+            EqualSemantics(final StatementEquality<A, D> equality) {
+                this(CopyPolicy.DECLARED_COPY, equality);
+            }
+
             @Override
             boolean canReuseCurrent(final Current<A, D> copy, final Current<A, D> current,
                     final Collection<? extends EffectiveStatement<?, ?>> substatements) {
@@ -210,6 +199,14 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
     private final @NonNull StatementDefinition def;
     private final @NonNull CopyPolicy copyPolicy;
 
+    @Beta
+    protected StatementSupport(final StatementSupport<A, D, E> delegate) {
+        checkArgument(delegate != this);
+        this.def = delegate.def;
+        this.policy = delegate.policy;
+        this.copyPolicy = delegate.copyPolicy;
+    }
+
     @Beta
     protected StatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy) {
         checkArgument(publicDefinition != this);
@@ -218,13 +215,6 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
         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.
      *
@@ -335,7 +325,7 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
      *
      * <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.
      * @throws SourceException when an inconsistency is detected.
@@ -350,7 +340,7 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
      *
      * <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. Argument and statement parent is accessible.
      * @throws SourceException when an inconsistency is detected.
@@ -365,13 +355,13 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
      *
      * <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. Argument and statement parent is accessible.
      * @throws SourceException when an inconsistency is detected.
      */
-    public void onFullDefinitionDeclared(final StmtContext.Mutable<A, D, E> stmt) {
-        final SubstatementValidator validator = getSubstatementValidator();
+    public void onFullDefinitionDeclared(final Mutable<A, D, E> stmt) {
+        final SubstatementValidator validator = substatementValidator();
         if (validator != null) {
             validator.validate(stmt);
         }
@@ -382,11 +372,12 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
      *
      * @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();
+    protected abstract @Nullable SubstatementValidator substatementValidator();
 
     /**
      * Returns true if this support has argument specific supports.
+     *
+     * @return true if this support has argument specific supports.
      */
     public boolean hasArgumentSpecificSupports() {
         // Most of statement supports don't have any argument specific supports, so return 'false'.
@@ -416,18 +407,6 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
         return rawArgument;
     }
 
-    /**
-     * 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
-     */
-    public Optional<StatementSupport<?, ?, ?>> getUnknownStatementDefinitionOf(final StatementDefinition yangStmtDef) {
-        return Optional.empty();
-    }
-
     /**
      * Returns true if this statement support and all its substatements ignore if-feature statements (e.g. yang-data
      * extension defined in <a href="https://tools.ietf.org/html/rfc8040#section-8">RFC 8040</a>). Default
@@ -497,6 +476,13 @@ public abstract class StatementSupport<A, D extends DeclaredStatement<A>, E exte
          */
         // TODO: does this mean source must have transitioned to ModelProcessingPhase.EFFECTIVE_MODEL?
         CONTEXT_INDEPENDENT,
+        /**
+         * Reuse the source statement context in the new place completely. This policy is more stringent than
+         * {@link #CONTEXT_INDEPENDENT} in that the statement is dependent on circumstances of its original definition
+         * and any copy operation must replicate it exactly as is. This implies ignoring the usual policy of its
+         * substatements. A typical example of such a statement is {@code type}.
+         */
+        EXACT_REPLICA,
         /**
          * Create a copy sharing declared instance, but otherwise having a separate disconnected lifecycle.
          */