Refactor argument adaptation
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / SubstatementContext.java
index 2710f0802ad025bb3fc26f1f233b8f40487acc7a..002b9bc50cd32cb4e4391646a003b80f6086fe5e 100644 (file)
@@ -7,14 +7,15 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
 import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Optional;
 import java.util.Set;
 import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.util.OptionalBoolean;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangVersion;
@@ -28,7 +29,6 @@ import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ConfigStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.KeyStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
@@ -39,14 +39,12 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
-import org.opendaylight.yangtools.yang.parser.spi.meta.QNameCacheNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.source.AugmentToChoiceNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,10 +63,22 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
      * This field maintains a resolution cache, so once we have returned a result, we will keep on returning the same
      * result without performing any lookups.
      */
-    private boolean haveConfiguration;
-    private boolean configuration;
-    private boolean wasCheckedIfInYangDataExtensionBody;
-    private boolean isInYangDataExtensionBody;
+    // BooleanField value
+    private byte configuration;
+
+    /**
+     * This field maintains a resolution cache for ignore config, so once we have returned a result, we will
+     * keep on returning the same result without performing any lookups.
+     */
+    // BooleanField value
+    private byte ignoreConfig;
+
+    /**
+     * This field maintains a resolution cache for ignore if-feature, so once we have returned a result, we will
+     * keep on returning the same result without performing any lookups.
+     */
+    // BooleanField value
+    private byte ignoreIfFeature;
 
     private volatile SchemaPath schemaPath;
 
@@ -79,27 +89,11 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
         this.argument = def.parseArgumentValue(this, rawStatementArgument());
     }
 
-    @SuppressWarnings("unchecked")
-    SubstatementContext(final SubstatementContext<A, D, E> original, final QNameModule newQNameModule,
-            final StatementContextBase<?, ?, ?> newParent, final CopyType typeOfCopy) {
-        super(original);
-        this.parent = newParent;
-
-        if (newQNameModule != null) {
-            final A originalArg = original.argument;
-            if (originalArg instanceof QName) {
-                final QName originalQName = (QName) originalArg;
-                this.argument = (A) getFromNamespace(QNameCacheNamespace.class,
-                        QName.create(newQNameModule, originalQName.getLocalName()));
-            } else if (StmtContextUtils.producesDeclared(original, KeyStatement.class)) {
-                this.argument = (A) StmtContextUtils.replaceModuleQNameForKey(
-                        (StmtContext<Collection<SchemaNodeIdentifier>, KeyStatement, ?>) original, newQNameModule);
-            } else {
-                this.argument = original.argument;
-            }
-        } else {
-            this.argument = original.argument;
-        }
+    SubstatementContext(final StatementContextBase<A, D, E> original, final StatementContextBase<?, ?, ?> parent,
+            final A argument, final CopyType copyType) {
+        super(original, copyType);
+        this.parent = Preconditions.checkNotNull(parent);
+        this.argument = argument;
     }
 
     @Override
@@ -133,27 +127,14 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
         return argument;
     }
 
-    @Override
-    public StatementContextBase<A, D, E> createCopy(final StatementContextBase<?, ?, ?> newParent,
-            final CopyType typeOfCopy) {
-        return createCopy(null, newParent, typeOfCopy);
-    }
-
-    @Override
-    public StatementContextBase<A, D, E> createCopy(final QNameModule newQNameModule,
+    StatementContextBase<A, D, E> createCopy(final QNameModule newQNameModule,
             final StatementContextBase<?, ?, ?> newParent, final CopyType typeOfCopy) {
         Preconditions.checkState(getCompletedPhase() == ModelProcessingPhase.EFFECTIVE_MODEL,
                 "Attempted to copy statement %s which has completed phase %s", this, getCompletedPhase());
 
-        final SubstatementContext<A, D, E> copy = new SubstatementContext<>(this, newQNameModule, newParent, typeOfCopy);
-
-        copy.appendCopyHistory(typeOfCopy, this.getCopyHistory());
-
-        if (this.getOriginalCtx() != null) {
-            copy.setOriginalCtx(this.getOriginalCtx());
-        } else {
-            copy.setOriginalCtx(this);
-        }
+        final A argumentCopy = newQNameModule == null ? argument
+                : definition().adaptArgumentValue(this, newQNameModule);
+        final SubstatementContext<A, D, E> copy = new SubstatementContext<>(this, newParent, argumentCopy, typeOfCopy);
 
         definition().onStatementAdded(copy);
 
@@ -183,7 +164,7 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
     private void copySubstatement(final Mutable<?, ?, ?> stmtContext, final QNameModule newQNameModule,
             final CopyType typeOfCopy, final Collection<Mutable<?, ?, ?>> buffer) {
         if (needToCopyByUses(stmtContext)) {
-            final Mutable<?, ?, ?> copy = stmtContext.createCopy(newQNameModule, this, typeOfCopy);
+            final Mutable<?, ?, ?> copy = childCopyOf(stmtContext, typeOfCopy, newQNameModule);
             LOG.debug("Copying substatement {} for {} as", stmtContext, this, copy);
             buffer.add(copy);
         } else if (isReusedByUses(stmtContext)) {
@@ -233,13 +214,13 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
         Verify.verify(maybeParentPath.isPresent(), "Parent %s does not have a SchemaPath", parent);
         final SchemaPath parentPath = maybeParentPath.get();
 
-        if (Utils.isUnknownNode(this)) {
+        if (StmtContextUtils.isUnknownStatement(this)) {
             return parentPath.createChild(getPublicDefinition().getStatementName());
         }
         if (argument instanceof QName) {
             final QName qname = (QName) argument;
             if (StmtContextUtils.producesDeclared(this, UsesStatement.class)) {
-                return maybeParentPath.orNull();
+                return maybeParentPath.orElse(null);
             }
 
             final SchemaPath path;
@@ -254,21 +235,20 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
         }
         if (argument instanceof String) {
             // FIXME: This may yield illegal argument exceptions
-            final StmtContext<?, ?, ?> originalCtx = getOriginalCtx();
-            final QName qname = originalCtx != null ? Utils.qNameFromArgument(originalCtx, (String) argument) : Utils
-                    .qNameFromArgument(this, (String) argument);
+            final Optional<StmtContext<?, ?, ?>> originalCtx = getOriginalCtx();
+            final QName qname = StmtContextUtils.qnameFromArgument(originalCtx.orElse(this), (String) argument);
             return parentPath.createChild(qname);
         }
         if (argument instanceof SchemaNodeIdentifier
-                && (StmtContextUtils.producesDeclared(this, AugmentStatement.class) || StmtContextUtils
-                        .producesDeclared(this, RefineStatement.class) || StmtContextUtils
-                .producesDeclared(this, DeviationStatement.class))) {
+                && (StmtContextUtils.producesDeclared(this, AugmentStatement.class)
+                        || StmtContextUtils.producesDeclared(this, RefineStatement.class)
+                        || StmtContextUtils.producesDeclared(this, DeviationStatement.class))) {
 
             return parentPath.createChild(((SchemaNodeIdentifier) argument).getPathFromRoot());
         }
 
         // FIXME: this does not look right
-        return maybeParentPath.orNull();
+        return maybeParentPath.orElse(null);
     }
 
     @Nonnull
@@ -286,25 +266,17 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
 
         }
 
-        return Optional.fromNullable(local);
-    }
-
-    @Override
-    public boolean isRootContext() {
-        return false;
+        return Optional.ofNullable(local);
     }
 
     @Override
     public boolean isConfiguration() {
-        // if this statement is within a 'yang-data' extension body, config substatements are ignored as if
-        // they were not declared. As 'yang-data' is always a top-level node, all configs that are within it are
-        // automatically true
-        if (isInYangDataExtensionBody()) {
+        if (isIgnoringConfig()) {
             return true;
         }
 
-        if (haveConfiguration) {
-            return configuration;
+        if (OptionalBoolean.isPresent(configuration)) {
+            return OptionalBoolean.get(configuration);
         }
 
         final StmtContext<Boolean, ?, ?> configStatement = StmtContextUtils.findFirstSubstatement(this,
@@ -324,28 +296,10 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
         }
 
         // Resolved, make sure we cache this return
-        configuration = isConfig;
-        haveConfiguration = true;
+        configuration = OptionalBoolean.of(isConfig);
         return isConfig;
     }
 
-    @Override
-    public boolean isInYangDataExtensionBody() {
-        if (wasCheckedIfInYangDataExtensionBody) {
-            return isInYangDataExtensionBody;
-        }
-
-        final boolean parentIsInYangDataExtensionBody = parent.isInYangDataExtensionBody();
-        if (parentIsInYangDataExtensionBody) {
-            isInYangDataExtensionBody = parentIsInYangDataExtensionBody;
-        } else {
-            isInYangDataExtensionBody = StmtContextUtils.hasYangDataExtensionParent(this);
-        }
-
-        wasCheckedIfInYangDataExtensionBody = true;
-        return isInYangDataExtensionBody;
-    }
-
     @Override
     public boolean isEnabledSemanticVersioning() {
         return parent.isEnabledSemanticVersioning();
@@ -375,4 +329,33 @@ final class SubstatementContext<A, D extends DeclaredStatement<A>, E extends Eff
     public void setRootIdentifier(final ModuleIdentifier identifier) {
         getRoot().setRootIdentifier(identifier);
     }
+
+    @Override
+    protected boolean isIgnoringIfFeatures() {
+        if (OptionalBoolean.isPresent(ignoreIfFeature)) {
+            return OptionalBoolean.get(ignoreIfFeature);
+        }
+
+        final boolean ret = definition().isIgnoringIfFeatures() || parent.isIgnoringIfFeatures();
+        ignoreIfFeature = OptionalBoolean.of(ret);
+
+        return ret;
+    }
+
+    @Override
+    protected boolean isIgnoringConfig() {
+        if (OptionalBoolean.isPresent(ignoreConfig)) {
+            return OptionalBoolean.get(ignoreConfig);
+        }
+
+        final boolean ret = definition().isIgnoringConfig() || parent.isIgnoringConfig();
+        ignoreConfig = OptionalBoolean.of(ret);
+
+        return ret;
+    }
+
+    @Override
+    protected boolean isParentSupportedByFeatures() {
+        return parent.isSupportedByFeatures();
+    }
 }