Make CopyHistory implement CopyableNode
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStatementMixins.java
index b87da7e799ae67bccb3f28e124ae3160bbb26dc3..5e0331da7da8b0880b6688892d1e2324a8f0a558 100644 (file)
@@ -8,13 +8,13 @@
 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.List;
 import java.util.Optional;
-import java.util.Set;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.yangtools.concepts.Mutable;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -23,17 +23,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.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 +48,15 @@ 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.TypedefEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.WhenEffectiveStatement;
 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,19 +67,9 @@ 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<T> filterEffectiveStatements(final Class<T> type) {
+        default <T> @NonNull Collection<? extends T> filterEffectiveStatements(final Class<T> type) {
             // Yeah, this is not nice, but saves one transformation
-            return (Collection<T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
-        }
-
-        // FIXME: YANGTOOLS-1068: eliminate this once we can return collections
-        default <T> List<T> filterEffectiveStatementsList(final Class<T> type) {
-            return ImmutableList.copyOf(filterEffectiveStatements(type));
-        }
-
-        // FIXME: YANGTOOLS-1068: eliminate this once we can return collections
-        default <T> Set<T> filterEffectiveStatementsSet(final Class<T> type) {
-            return ImmutableSet.copyOf(filterEffectiveStatements(type));
+            return (Collection<? extends T>) Collections2.filter(effectiveSubstatements(), type::isInstance);
         }
     }
 
@@ -83,8 +82,8 @@ public final class EffectiveStatementMixins {
     public interface AugmentationTargetMixin<A, D extends DeclaredStatement<A>>
             extends Mixin<A, D>, AugmentationTarget {
         @Override
-        default Set<AugmentationSchemaNode> getAvailableAugmentations() {
-            return filterEffectiveStatementsSet(AugmentationSchemaNode.class);
+        default Collection<? extends AugmentationSchemaNode> getAvailableAugmentations() {
+            return filterEffectiveStatements(AugmentationSchemaNode.class);
         }
     }
 
@@ -111,8 +110,8 @@ public final class EffectiveStatementMixins {
     public interface ActionNodeContainerMixin<A, D extends DeclaredStatement<A>>
             extends Mixin<A, D>, ActionNodeContainer {
         @Override
-        default Set<ActionDefinition> getActions() {
-            return filterEffectiveStatementsSet(ActionDefinition.class);
+        default Collection<? extends ActionDefinition> getActions() {
+            return filterEffectiveStatements(ActionDefinition.class);
         }
     }
 
@@ -125,8 +124,8 @@ public final class EffectiveStatementMixins {
     public interface NotificationNodeContainerMixin<A, D extends DeclaredStatement<A>>
             extends Mixin<A, D>, NotificationNodeContainer {
         @Override
-        default Set<NotificationDefinition> getNotifications() {
-            return filterEffectiveStatementsSet(NotificationDefinition.class);
+        default Collection<? extends NotificationDefinition> getNotifications() {
+            return filterEffectiveStatements(NotificationDefinition.class);
         }
     }
 
@@ -138,7 +137,7 @@ public final class EffectiveStatementMixins {
      */
     public interface MustConstraintMixin<A, D extends DeclaredStatement<A>> extends Mixin<A, D>, MustConstraintAware {
         @Override
-        default Collection<MustDefinition> getMustConstraints() {
+        default Collection<? extends MustDefinition> getMustConstraints() {
             return filterEffectiveStatements(MustDefinition.class);
         }
     }
@@ -164,26 +163,23 @@ public final class EffectiveStatementMixins {
      */
     public interface DataNodeContainerMixin<A, D extends DeclaredStatement<A>> extends DataNodeContainer, Mixin<A, D> {
         @Override
-        default Set<TypeDefinition<?>> getTypeDefinitions() {
-            // TODO: the cast here is needed to work around Java 11 javac type inference issue
-            return (Set) effectiveSubstatements().stream().filter(TypedefEffectiveStatement.class::isInstance)
-                    .map(stmt -> ((TypedefEffectiveStatement) stmt).getTypeDefinition())
-                    .collect(ImmutableSet.toImmutableSet());
+        default Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
+            return filterTypeDefinitions(this);
         }
 
         @Override
-        default Collection<DataSchemaNode> getChildNodes() {
+        default Collection<? extends DataSchemaNode> getChildNodes() {
             return filterEffectiveStatements(DataSchemaNode.class);
         }
 
         @Override
-        default Set<GroupingDefinition> getGroupings() {
-            return filterEffectiveStatementsSet(GroupingDefinition.class);
+        default Collection<? extends GroupingDefinition> getGroupings() {
+            return filterEffectiveStatements(GroupingDefinition.class);
         }
 
         @Override
-        default Set<UsesNode> getUses() {
-            return filterEffectiveStatementsSet(UsesNode.class);
+        default Collection<? extends UsesNode> getUses() {
+            return filterEffectiveStatements(UsesNode.class);
         }
     }
 
@@ -244,8 +240,27 @@ public final class EffectiveStatementMixins {
         }
 
         @Override
-        default List<UnknownSchemaNode> getUnknownSchemaNodes() {
-            return filterEffectiveStatementsList(UnknownSchemaNode.class);
+        default Collection<? extends UnknownSchemaNode> getUnknownSchemaNodes() {
+            return filterEffectiveStatements(UnknownSchemaNode.class);
+        }
+    }
+
+    /**
+     * 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);
         }
     }
 
@@ -289,6 +304,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.
      *
@@ -310,11 +340,102 @@ 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);
         }
     }
 
+    /**
+     * Helper bridge for operation containers ({@code input} and {@code output}).
+     *
+     * @param <D> Class representing declared version of this statement.
+     */
+    public interface OperationContainerMixin<D extends DeclaredStatement<QName>>
+            extends ContainerLike, DocumentedNodeMixin.WithStatus<QName, D>, DataNodeContainerMixin<QName, D>,
+                    MustConstraintMixin<QName, D>, WhenConditionMixin<QName, D>, AugmentationTargetMixin<QName, D>,
+                    SchemaNodeMixin<QName, D>, CopyableMixin<QName, D> {
+        @Override
+        default @NonNull QName argument() {
+            return getQName();
+        }
+
+        @Override
+        default Optional<ActionDefinition> findAction(final QName qname) {
+            return Optional.empty();
+        }
+
+        @Override
+        default Optional<NotificationDefinition> findNotification(final QName qname) {
+            return Optional.empty();
+        }
+
+        @Override
+        default Collection<? extends ActionDefinition> getActions() {
+            return ImmutableSet.of();
+        }
+
+        @Override
+        default Collection<? extends NotificationDefinition> getNotifications() {
+            return ImmutableSet.of();
+        }
+
+        @Override
+        default boolean isConfiguration() {
+            return false;
+        }
+
+        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 Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
+            return filterTypeDefinitions(this);
+        }
+
+        @Override
+        default Collection<? extends 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);
+        }
+    }
+
     /**
      * Support interface for various mixins. Implementations are required to store 32bits worth of flags, which are
      * globally assigned to sub-interfaces -- thus providing storage for many low-cardinality properties.
@@ -360,20 +481,8 @@ public final class EffectiveStatementMixins {
             }
 
             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;
             }
 
@@ -405,7 +514,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);
@@ -429,4 +538,17 @@ public final class EffectiveStatementMixins {
             }
         }
     }
+
+    private EffectiveStatementMixins() {
+    }
+
+    static <T extends ContainerLike> T findAsContainer(final EffectiveStatement<?, ?> stmt,
+            final Class<? extends EffectiveStatement<QName, ?>> type, Class<T> target) {
+        return target.cast(stmt.findFirstEffectiveSubstatement(type).get());
+    }
+
+    static Collection<? extends TypeDefinition<?>> filterTypeDefinitions(final Mixin<?, ?> stmt) {
+        return Collections2.transform(stmt.filterEffectiveStatements(TypedefEffectiveStatement.class),
+            TypedefEffectiveStatement::getTypeDefinition);
+    }
 }