Make CopyHistory implement CopyableNode
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStatementMixins.java
index 07c88afea734d8b43d9669483410ba7e6c613033..3eb78f0488bd4a1d2a9dba1b1488f9ae7b061c3c 100644 (file)
@@ -9,12 +9,15 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import java.util.Collection;
 import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.Mutable;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
@@ -22,18 +25,22 @@ import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ConstraintMetaDefinition;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
 import org.opendaylight.yangtools.yang.model.api.CopyableNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.MandatoryAware;
 import org.opendaylight.yangtools.yang.model.api.MustConstraintAware;
 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.NotificationNodeContainer;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
+import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
@@ -43,11 +50,18 @@ import org.opendaylight.yangtools.yang.model.api.WhenConditionAware;
 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.DescriptionEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ErrorAppTagEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ErrorMessageEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ReferenceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.StatusEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
+import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMixins.EffectiveStatementWithFlags.FlagsBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
-import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
+import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression.QualifiedBound;
 
 /**
  * Mix-in interfaces providing services required by SchemaNode et al. These interfaces provide implementations, or
@@ -58,7 +72,7 @@ public final class EffectiveStatementMixins {
     // Marker interface requiring all mixins to be derived from EffectiveStatement.
     private interface Mixin<A, D extends DeclaredStatement<A>> extends EffectiveStatement<A, D> {
         @SuppressWarnings("unchecked")
-        default <T> Collection<? extends T> filterEffectiveStatements(final Class<T> type) {
+        default <T> @NonNull Collection<? extends @NonNull T> filterEffectiveStatements(final Class<T> type) {
             // Yeah, this is not nice, but saves one transformation
             return (Collection<? extends T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
         }
@@ -87,6 +101,7 @@ public final class EffectiveStatementMixins {
     public interface AddedByUsesMixin<A, D extends DeclaredStatement<A>>
             extends EffectiveStatementWithFlags<A, D>, AddedByUsesAware {
         @Override
+        @Deprecated
         default boolean isAddedByUses() {
             return (flags() & FlagsBuilder.ADDED_BY_USES) != 0;
         }
@@ -128,7 +143,7 @@ public final class EffectiveStatementMixins {
      */
     public interface MustConstraintMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, MustConstraintAware {
         @Override
-        default Collection<? extends MustDefinition> getMustConstraints() {
+        default Collection<? extends @NonNull MustDefinition> getMustConstraints() {
             return filterEffectiveStatements(MustDefinition.class);
         }
     }
@@ -141,6 +156,7 @@ public final class EffectiveStatementMixins {
      */
     public interface CopyableMixin<A, D extends DeclaredStatement<A>> extends AddedByUsesMixin<A, D>, CopyableNode {
         @Override
+        @Deprecated
         default boolean isAugmenting() {
             return (flags() & FlagsBuilder.AUGMENTING) != 0;
         }
@@ -155,9 +171,7 @@ public final class EffectiveStatementMixins {
     public interface DataNodeContainerMixin<A, D extends DeclaredStatement<A>> extends DataNodeContainer, Mixin<A, D> {
         @Override
         default Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
-            // TODO: the cast here is needed to work around Java 11 javac type inference issue
-            return Collections2.transform(filterEffectiveStatements(TypedefEffectiveStatement.class),
-                TypedefEffectiveStatement::getTypeDefinition);
+            return filterTypeDefinitions(this);
         }
 
         @Override
@@ -185,8 +199,18 @@ public final class EffectiveStatementMixins {
     public interface DataSchemaNodeMixin<A, D extends DeclaredStatement<A>>
             extends DataSchemaNode, CopyableMixin<A, D>, SchemaNodeMixin<A, D>, WhenConditionMixin<A, D> {
         @Override
-        default boolean isConfiguration() {
-            return (flags() & FlagsBuilder.CONFIGURATION) != 0;
+        default Optional<Boolean> effectiveConfig() {
+            final int fl = flags() & FlagsBuilder.MASK_CONFIG;
+            switch (fl) {
+                case FlagsBuilder.CONFIG_FALSE:
+                    return Optional.of(Boolean.FALSE);
+                case FlagsBuilder.CONFIG_TRUE:
+                    return Optional.of(Boolean.TRUE);
+                case FlagsBuilder.CONFIG_UNDEF:
+                    return Optional.empty();
+                default:
+                    throw new IllegalStateException("Unhandled effective config flags " + fl);
+            }
         }
     }
 
@@ -238,6 +262,25 @@ public final class EffectiveStatementMixins {
         }
     }
 
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link ConstraintMetaDefinition}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface ConstraintMetaDefinitionMixin<A, D extends DeclaredStatement<A>> extends DocumentedNodeMixin<A, D>,
+            ConstraintMetaDefinition {
+        @Override
+        default Optional<String> getErrorAppTag() {
+            return findFirstEffectiveSubstatementArgument(ErrorAppTagEffectiveStatement.class);
+        }
+
+        @Override
+        default Optional<String> getErrorMessage() {
+            return findFirstEffectiveSubstatementArgument(ErrorMessageEffectiveStatement.class);
+        }
+    }
+
     /**
      * Bridge between {@link EffectiveStatementWithFlags} and {@link MandatoryAware}.
      *
@@ -278,6 +321,21 @@ public final class EffectiveStatementMixins {
         }
     }
 
+    /**
+     * Bridge between {@link EffectiveStatementWithFlags} and {@link UnknownSchemaNode}.
+     *
+     * @param <A> Argument type ({@link Void} if statement does not have argument.)
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface UnknownSchemaNodeMixin<A, D extends DeclaredStatement<A>>
+            extends SchemaNodeMixin<A, D>, CopyableMixin<A, D>, UnknownSchemaNode {
+
+        @Override
+        default String getNodeParameter() {
+            return Strings.nullToEmpty(getDeclared().rawArgument());
+        }
+    }
+
     /**
      * Bridge between {@link EffectiveStatementWithFlags} and {@code ordered-by} statement.
      *
@@ -299,7 +357,7 @@ public final class EffectiveStatementMixins {
      */
     public interface WhenConditionMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, WhenConditionAware {
         @Override
-        default Optional<RevisionAwareXPath> getWhenCondition() {
+        default Optional<QualifiedBound> getWhenCondition() {
             return findFirstEffectiveSubstatementArgument(WhenEffectiveStatement.class);
         }
     }
@@ -309,19 +367,13 @@ public final class EffectiveStatementMixins {
      *
      * @param <D> Class representing declared version of this statement.
      */
-    @Beta
     public interface OperationContainerMixin<D extends DeclaredStatement<QName>>
-            extends ContainerSchemaNode, DocumentedNodeMixin.WithStatus<QName, D>, DataNodeContainerMixin<QName, D>,
+            extends ContainerLike, DocumentedNodeMixin.WithStatus<QName, D>, DataNodeContainerMixin<QName, D>,
                     MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D>, AugmentationTargetMixin<QName, D>,
-                    CopyableMixin<QName, D> {
+                    SchemaNodeMixin<QName, D>, CopyableMixin<QName, D> {
         @Override
         default @NonNull QName argument() {
-            return getPath().getLastComponent();
-        }
-
-        @Override
-        default QName getQName() {
-            return argument();
+            return getQName();
         }
 
         @Override
@@ -345,18 +397,59 @@ public final class EffectiveStatementMixins {
         }
 
         @Override
-        default boolean isConfiguration() {
-            return false;
+        default Optional<Boolean> effectiveConfig() {
+            return Optional.empty();
+        }
+
+        default String defaultToString() {
+            return MoreObjects.toStringHelper(this).add("path", getPath()).toString();
+        }
+    }
+
+    /**
+     * Helper bridge for {@code anydata} and {@code anyxml} opaque data.
+     *
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface OpaqueDataSchemaNodeMixin<D extends DeclaredStatement<QName>>
+            extends DerivableSchemaNode, DataSchemaNodeMixin<QName, D>, DocumentedNodeMixin.WithStatus<QName, D>,
+                    MandatoryMixin<QName, D>, MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D> {
+        @Override
+        default @NonNull QName argument() {
+            return getQName();
+        }
+    }
+
+    /**
+     * Helper bridge for {@code rpc} and {@code action} operations.
+     *
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface OperationDefinitionMixin<D extends DeclaredStatement<QName>>
+            extends SchemaNodeMixin<QName, D>, OperationDefinition {
+        @Override
+        default @NonNull QName argument() {
+            return getQName();
         }
 
         @Override
-        default boolean isPresenceContainer() {
-            // FIXME: this should not really be here
-            return false;
+        default Collection<? extends @NonNull TypeDefinition<?>> getTypeDefinitions() {
+            return filterTypeDefinitions(this);
         }
 
-        default String defaultToString() {
-            return MoreObjects.toStringHelper(this).add("path", getPath()).toString();
+        @Override
+        default Collection<? extends @NonNull GroupingDefinition> getGroupings() {
+            return filterEffectiveStatements(GroupingDefinition.class);
+        }
+
+        @Override
+        default InputSchemaNode getInput() {
+            return findAsContainer(this, InputEffectiveStatement.class, InputSchemaNode.class);
+        }
+
+        @Override
+        default OutputSchemaNode getOutput() {
+            return findAsContainer(this, OutputEffectiveStatement.class, OutputSchemaNode.class);
         }
     }
 
@@ -377,14 +470,13 @@ public final class EffectiveStatementMixins {
 
         @NonNullByDefault
         final class FlagsBuilder implements Mutable {
-            // We still have 24 flags remaining
+            // We still have 23 flags remaining
             static final int STATUS_CURRENT       = 0x0001;
             static final int STATUS_DEPRECATED    = 0x0002;
             static final int STATUS_OBSOLETE      = 0x0003;
             static final int MASK_STATUS          = 0x0003;
 
-            static final int CONFIGURATION        = 0x0004;
-            static final int MANDATORY            = 0x0008;
+            static final int MANDATORY            = 0x0004;
 
             static final int AUGMENTING           = 0x0010;
             static final int ADDED_BY_USES        = 0x0020;
@@ -393,32 +485,27 @@ public final class EffectiveStatementMixins {
             static final int USER_ORDERED         = 0x0040;
             static final int PRESENCE             = 0x0080;
 
+            static final int CONFIG_UNDEF         = 0x0100;
+            static final int CONFIG_FALSE         = 0x0200;
+            static final int CONFIG_TRUE          = 0x0300;
+            static final int MASK_CONFIG          = CONFIG_TRUE;
+
             private int flags;
 
-            public FlagsBuilder setConfiguration(final boolean config) {
-                if (config) {
-                    flags |= CONFIGURATION;
+            public FlagsBuilder setConfiguration(final @Nullable Boolean config) {
+                final int fl;
+                if (config != null) {
+                    fl = config ? CONFIG_TRUE : CONFIG_FALSE;
                 } else {
-                    flags &= ~CONFIGURATION;
+                    fl = CONFIG_UNDEF;
                 }
+                flags = flags & ~MASK_CONFIG | fl;
                 return this;
             }
 
             public FlagsBuilder setHistory(final CopyHistory history) {
-                int bits;
-                if (history.contains(CopyType.ADDED_BY_USES_AUGMENTATION)) {
-                    bits = AUGMENTING | ADDED_BY_USES;
-                } else {
-                    bits = 0;
-                    if (history.contains(CopyType.ADDED_BY_AUGMENTATION)) {
-                        bits |= AUGMENTING;
-                    }
-                    if (history.contains(CopyType.ADDED_BY_USES)) {
-                        bits |= ADDED_BY_USES;
-                    }
-                }
-
-                flags = flags & ~MASK_HISTORY | bits;
+                flags = flags & ~MASK_HISTORY
+                    | (history.isAugmenting() ? AUGMENTING : 0) | (history.isAddedByUses() ? ADDED_BY_USES : 0);
                 return this;
             }
 
@@ -450,7 +537,7 @@ public final class EffectiveStatementMixins {
                         bits = STATUS_DEPRECATED;
                         break;
                     case OBSOLETE:
-                        bits = STATUS_DEPRECATED;
+                        bits = STATUS_OBSOLETE;
                         break;
                     default:
                         throw new IllegalStateException("Unhandled status " + status);
@@ -474,4 +561,26 @@ public final class EffectiveStatementMixins {
             }
         }
     }
+
+    private EffectiveStatementMixins() {
+    }
+
+    static <T extends ContainerLike> T findAsContainer(final EffectiveStatement<?, ?> stmt,
+            final Class<? extends EffectiveStatement<QName, ?>> type, final Class<T> target) {
+        return target.cast(stmt.findFirstEffectiveSubstatement(type).get());
+    }
+
+    static Collection<? extends @NonNull TypeDefinition<?>> filterTypeDefinitions(final Mixin<?, ?> stmt) {
+        return Collections2.transform(stmt.filterEffectiveStatements(TypedefEffectiveStatement.class),
+            TypedefEffectiveStatement::getTypeDefinition);
+    }
+
+    public static int historyAndStatusFlags(final CopyHistory history,
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        return new FlagsBuilder()
+                .setHistory(history)
+                .setStatus(AbstractStatementSupport.findFirstArgument(substatements,
+                    StatusEffectiveStatement.class, Status.CURRENT))
+                .toFlags();
+    }
 }