Make CopyHistory implement CopyableNode
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStatementMixins.java
index 359ccac359ecef11c9a64e0930de5f30f7a614d5..3eb78f0488bd4a1d2a9dba1b1488f9ae7b061c3c 100644 (file)
@@ -7,16 +7,17 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt;
 
-import static com.google.common.base.Verify.verify;
-
 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;
@@ -24,20 +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.OperationDefinition;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+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;
@@ -47,13 +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
@@ -64,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);
         }
@@ -93,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;
         }
@@ -134,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);
         }
     }
@@ -147,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;
         }
@@ -189,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);
+            }
         }
     }
 
@@ -242,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}.
      *
@@ -282,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.
      *
@@ -303,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);
         }
     }
@@ -314,17 +368,12 @@ public final class EffectiveStatementMixins {
      * @param <D> Class representing declared version of this statement.
      */
     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
@@ -348,14 +397,8 @@ public final class EffectiveStatementMixins {
         }
 
         @Override
-        default boolean isConfiguration() {
-            return false;
-        }
-
-        @Override
-        default boolean isPresenceContainer() {
-            // FIXME: this should not really be here
-            return false;
+        default Optional<Boolean> effectiveConfig() {
+            return Optional.empty();
         }
 
         default String defaultToString() {
@@ -373,12 +416,7 @@ public final class EffectiveStatementMixins {
                     MandatoryMixin<QName, D>, MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D> {
         @Override
         default @NonNull QName argument() {
-            return getPath().getLastComponent();
-        }
-
-        @Override
-        default QName getQName() {
-            return argument();
+            return getQName();
         }
     }
 
@@ -391,32 +429,27 @@ public final class EffectiveStatementMixins {
             extends SchemaNodeMixin<QName, D>, OperationDefinition {
         @Override
         default @NonNull QName argument() {
-            return getPath().getLastComponent();
+            return getQName();
         }
 
         @Override
-        default QName getQName() {
-            return argument();
-        }
-
-        @Override
-        default Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
+        default Collection<? extends @NonNull TypeDefinition<?>> getTypeDefinitions() {
             return filterTypeDefinitions(this);
         }
 
         @Override
-        default Collection<? extends GroupingDefinition> getGroupings() {
+        default Collection<? extends @NonNull GroupingDefinition> getGroupings() {
             return filterEffectiveStatements(GroupingDefinition.class);
         }
 
         @Override
-        default ContainerSchemaNode getInput() {
-            return findAsContainer(this, InputEffectiveStatement.class);
+        default InputSchemaNode getInput() {
+            return findAsContainer(this, InputEffectiveStatement.class, InputSchemaNode.class);
         }
 
         @Override
-        default ContainerSchemaNode getOutput() {
-            return findAsContainer(this, OutputEffectiveStatement.class);
+        default OutputSchemaNode getOutput() {
+            return findAsContainer(this, OutputEffectiveStatement.class, OutputSchemaNode.class);
         }
     }
 
@@ -437,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;
@@ -453,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;
             }
 
@@ -538,16 +565,22 @@ public final class EffectiveStatementMixins {
     private EffectiveStatementMixins() {
     }
 
-    static ContainerSchemaNode findAsContainer(final EffectiveStatement<?, ?> stmt,
-            final Class<? extends EffectiveStatement<QName, ?>> type) {
-        final EffectiveStatement<?, ?> statement = stmt.findFirstEffectiveSubstatement(type).get();
-        verify(statement instanceof ContainerSchemaNode, "Child statement %s is not a ContainerSchemaNode",
-            statement);
-        return (ContainerSchemaNode) statement;
+    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 TypeDefinition<?>> filterTypeDefinitions(final Mixin<?, ?> stmt) {
+    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();
+    }
 }