Remove AugmentationSchemaNode.getOriginalDefinition()
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ReactorStmtCtx.java
index 66ad765afa84bc53301a1906773b6417186f2f21..e0507835b9e28a0f3003f17d59b26e24bbf6df9d 100644 (file)
@@ -19,10 +19,10 @@ import java.util.Optional;
 import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangVersion;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 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.meta.StatementDefinition;
@@ -34,6 +34,7 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStatementState;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
@@ -46,7 +47,6 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -118,7 +118,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
      * {@link #buildEffective()} instance. If this context is reused, it can be inflated to {@link EffectiveInstances}
      * and also act as a common instance reuse site.
      */
-    private @Nullable E effectiveInstance;
+    private @Nullable Object effectiveInstance;
 
     // Master flag controlling whether this context can yield an effective statement
     // FIXME: investigate the mechanics that are being supported by this, as it would be beneficial if we can get rid
@@ -160,11 +160,6 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     // FIXME: move this out once we have JDK15+
     private boolean boolFlag;
 
-    // SchemaPath cache for use with SubstatementContext and InferredStatementContext. This hurts RootStatementContext
-    // a bit in terms of size -- but those are only a few and SchemaPath is on its way out anyway.
-    // FIXME: this should become 'QName'
-    private SchemaPath schemaPath;
-
     ReactorStmtCtx() {
         // Empty on purpose
     }
@@ -195,10 +190,10 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     public abstract RootStatementContext<?, ?, ?> getRoot();
 
     @Override
-    public abstract Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
+    public abstract Collection<? extends @NonNull StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
 
     @Override
-    public final @NonNull Registry getBehaviourRegistry() {
+    public final Registry getBehaviourRegistry() {
         return getRoot().getBehaviourRegistryImpl();
     }
 
@@ -243,11 +238,6 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         return QName.create(StmtContextUtils.getRootModuleQName(root), root.getRawArgument());
     }
 
-    @Override
-    public final EffectiveStatement<?, ?> original() {
-        return getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
-    }
-
     //
     // In the next two methods we are looking for an effective statement. If we already have an effective instance,
     // defer to it's implementation of the equivalent search. Otherwise we search our substatement contexts.
@@ -258,17 +248,22 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     @Override
     public final <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgument(
             final @NonNull Class<Z> type) {
-        final E existing = effectiveInstance;
+        final E existing = effectiveInstance();
         return existing != null ? existing.findFirstEffectiveSubstatementArgument(type)
             : findSubstatementArgumentImpl(type);
     }
 
     @Override
     public final boolean hasSubstatement(final @NonNull Class<? extends EffectiveStatement<?, ?>> type) {
-        final E existing = effectiveInstance;
+        final E existing = effectiveInstance();
         return existing != null ? existing.findFirstEffectiveSubstatement(type).isPresent() : hasSubstatementImpl(type);
     }
 
+    private E effectiveInstance() {
+        final Object existing = effectiveInstance;
+        return existing != null ? EffectiveInstances.local(existing) : null;
+    }
+
     // Visible due to InferredStatementContext's override. At this point we do not have an effective instance available.
     <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgumentImpl(
             final @NonNull Class<Z> type) {
@@ -297,8 +292,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     }
 
     protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
-        return toStringHelper.add("definition", definition()).add("rawArgument", rawArgument())
-            .add("refCount", refString());
+        return toStringHelper.add("definition", definition()).add("argument", argument()).add("refCount", refString());
     }
 
     private String refString() {
@@ -368,9 +362,11 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         QNameModule targetModule);
 
     @Override
-    public final ReactorStmtCtx<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
+    public final ReplicaStatementContext<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
         checkArgument(parent instanceof StatementContextBase, "Unsupported parent %s", parent);
-        return replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
+        final var ret = replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
+        definition().onStatementAdded(ret);
+        return ret;
     }
 
     abstract @NonNull ReplicaStatementContext<A, D, E> replicaAsChildOf(@NonNull StatementContextBase<?, ?, ?> parent);
@@ -383,17 +379,11 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     @Override
     public final E buildEffective() {
-        final E existing;
-        return (existing = effectiveInstance) != null ? existing : loadEffective();
+        final Object existing;
+        return (existing = effectiveInstance) != null ? EffectiveInstances.local(existing) : loadEffective();
     }
 
     private @NonNull E loadEffective() {
-        // Creating an effective statement does not strictly require a declared instance -- there are statements like
-        // 'input', which are implicitly defined.
-        // Our implementation design makes an invariant assumption that buildDeclared() has been called by the time
-        // we attempt to create effective statement:
-        declared();
-
         final E ret = createEffective();
         effectiveInstance = ret;
         // we have called createEffective(), substatements are no longer guarded by us. Let's see if we can clear up
@@ -406,6 +396,29 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     abstract @NonNull E createEffective();
 
+    /**
+     * Attach an effective copy of this statement. This essentially acts as a map, where we make a few assumptions:
+     * <ul>
+     *   <li>{@code copy} and {@code this} statement share {@link #getOriginalCtx()} if it exists</li>
+     *   <li>{@code copy} did not modify any statements relative to {@code this}</li>
+     * </ul>
+     *
+     * @param state effective statement state, acting as a lookup key
+     * @param stmt New copy to append
+     * @return {@code stmt} or a previously-created instances with the same {@code state}
+     */
+    @SuppressWarnings("unchecked")
+    final @NonNull E attachEffectiveCopy(final @NonNull EffectiveStatementState state, final @NonNull E stmt) {
+        final Object local = effectiveInstance;
+        final EffectiveInstances<E> instances;
+        if (local instanceof EffectiveInstances) {
+            instances = (EffectiveInstances<E>) local;
+        } else {
+            effectiveInstance = instances = new EffectiveInstances<>((E) local);
+        }
+        return instances.attachCopy(state, stmt);
+    }
+
     /**
      * Walk this statement's copy history and return the statement closest to original which has not had its effective
      * statements modified. This statement and returned substatement logically have the same set of substatements, hence
@@ -449,8 +462,8 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     }
 
     @Override
-    public final void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) {
-        this.isSupportedToBuildEffective = isSupportedToBuildEffective;
+    public final void setUnsupported() {
+        this.isSupportedToBuildEffective = false;
     }
 
     @Override
@@ -469,8 +482,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
          */
         if (isParentSupportedByFeatures()) {
             // If the set of supported features has not been provided, all features are supported by default.
-            final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class,
-                    SupportedFeatures.SUPPORTED_FEATURES);
+            final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class, Empty.value());
             if (supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures)) {
                 flags |= SET_SUPPORTED_BY_FEATURES;
                 return true;
@@ -614,63 +626,38 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     @Override
     public final QName argumentAsTypeQName() {
-        return interpretAsQName(getRawArgument());
+        // FIXME: This may yield illegal argument exceptions
+        return StmtContextUtils.qnameFromArgument(getOriginalCtx().orElse(this), getRawArgument());
     }
 
     @Override
     public final QNameModule effectiveNamespace() {
-        // FIXME: there has to be a better way to do this
-        return getSchemaPath().getLastComponent().getModule();
-    }
-
-    //
-    //
-    // Common SchemaPath cache. All of this is bound to be removed once YANGTOOLS-1066 is done.
-    //
-    //
-
-    // Exists only to support {SubstatementContext,InferredStatementContext}.schemaPath()
-    @Deprecated
-    final @Nullable SchemaPath substatementGetSchemaPath() {
-        if (schemaPath == null) {
-            schemaPath = createSchemaPath((StatementContextBase<?, ?, ?>) coerceParentContext());
-        }
-        return schemaPath;
-    }
-
-    // FIXME: 7.0.0: this method's logic needs to be moved to the respective StatementSupport classes
-    @Deprecated
-    private SchemaPath createSchemaPath(final StatementContextBase<?, ?, ?> parent) {
-        final SchemaPath parentPath = parent.getSchemaPath();
         if (StmtContextUtils.isUnknownStatement(this)) {
-            return parentPath.createChild(publicDefinition().getStatementName());
+            return publicDefinition().getStatementName().getModule();
+        }
+        if (producesDeclared(UsesStatement.class)) {
+            return coerceParent().effectiveNamespace();
         }
+
         final Object argument = argument();
         if (argument instanceof QName) {
-            final QName qname = (QName) argument;
-            if (producesDeclared(UsesStatement.class)) {
-                return parentPath;
-            }
-
-            return parentPath.createChild(qname);
+            return ((QName) argument).getModule();
         }
         if (argument instanceof String) {
-            return parentPath.createChild(interpretAsQName((String) argument));
+            // FIXME: This may yield illegal argument exceptions
+            return StmtContextUtils.qnameFromArgument(getOriginalCtx().orElse(this), (String) argument).getModule();
         }
         if (argument instanceof SchemaNodeIdentifier
                 && (producesDeclared(AugmentStatement.class) || producesDeclared(RefineStatement.class)
                         || producesDeclared(DeviationStatement.class))) {
-
-            return parentPath.createChild(((SchemaNodeIdentifier) argument).getNodeIdentifiers());
+            return ((SchemaNodeIdentifier) argument).lastNodeIdentifier().getModule();
         }
 
-        // FIXME: this does not look right, investigate more?
-        return parentPath;
+        return coerceParent().effectiveNamespace();
     }
 
-    private @NonNull QName interpretAsQName(final String argument) {
-        // FIXME: This may yield illegal argument exceptions
-        return StmtContextUtils.qnameFromArgument(getOriginalCtx().orElse(this), argument);
+    private ReactorStmtCtx<?, ?, ?> coerceParent() {
+        return (ReactorStmtCtx<?, ?, ?>) coerceParentContext();
     }
 
     //
@@ -823,6 +810,10 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         }
 
         // Propagate towards parent if there is one
+        sweepParent();
+    }
+
+    private void sweepParent() {
         final ReactorStmtCtx<?, ?, ?> parent = getParentContext();
         if (parent != null) {
             parent.sweepOnChildDecrement();
@@ -846,12 +837,9 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
         // parent is potentially reclaimable
         if (noParentRef()) {
-            LOG.trace("Cleanup {} of parent {}", refcount, this);
+            LOG.trace("Cleanup {} of parent {}", refs, this);
             if (sweepState()) {
-                final ReactorStmtCtx<?, ?, ?> parent = getParentContext();
-                if (parent != null) {
-                    parent.sweepOnChildDecrement();
-                }
+                sweepParent();
             }
         }
     }