X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=parser%2Fyang-parser-reactor%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fstmt%2Freactor%2FReactorStmtCtx.java;h=a00b5446e56db4d2fbfd566267cc50fec0fd18af;hb=a964a780e67e0f094f275a35c20a9079cb902a47;hp=66ad765afa84bc53301a1906773b6417186f2f21;hpb=0a8bdd5f4997e5f01decde68ddef7ac2c315e0f4;p=yangtools.git diff --git a/parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java b/parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java index 66ad765afa..a00b5446e5 100644 --- a/parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java +++ b/parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ReactorStmtCtx.java @@ -17,12 +17,13 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Stream; 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; @@ -33,7 +34,9 @@ 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; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.parser.spi.ParserNamespaces; 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; @@ -41,12 +44,11 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry; import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace; +import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; 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 +120,7 @@ abstract class ReactorStmtCtx, 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 +162,6 @@ abstract class ReactorStmtCtx, 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 +192,10 @@ abstract class ReactorStmtCtx, E extends Effec public abstract RootStatementContext getRoot(); @Override - public abstract Collection> mutableDeclaredSubstatements(); + public abstract Collection> mutableDeclaredSubstatements(); @Override - public final @NonNull Registry getBehaviourRegistry() { + public final Registry getBehaviourRegistry() { return getRoot().getBehaviourRegistryImpl(); } @@ -239,13 +236,8 @@ abstract class ReactorStmtCtx, E extends Effec @Override public final QName moduleName() { - final RootStatementContext root = getRoot(); - return QName.create(StmtContextUtils.getRootModuleQName(root), root.getRawArgument()); - } - - @Override - public final EffectiveStatement original() { - return getOriginalCtx().map(StmtContext::buildEffective).orElse(null); + final var root = getRoot(); + return QName.create(StmtContextUtils.getModuleQName(root), root.getRawArgument()); } // @@ -258,17 +250,22 @@ abstract class ReactorStmtCtx, E extends Effec @Override public final > @NonNull Optional findSubstatementArgument( final @NonNull Class 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> 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. > @NonNull Optional findSubstatementArgumentImpl( final @NonNull Class type) { @@ -297,22 +294,17 @@ abstract class ReactorStmtCtx, 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() { final int current = refcount; - switch (current) { - case REFCOUNT_DEFUNCT: - return "DEFUNCT"; - case REFCOUNT_SWEEPING: - return "SWEEPING"; - case REFCOUNT_SWEPT: - return "SWEPT"; - default: - return String.valueOf(refcount); - } + return switch (current) { + case REFCOUNT_DEFUNCT -> "DEFUNCT"; + case REFCOUNT_SWEEPING -> "SWEEPING"; + case REFCOUNT_SWEPT -> "SWEPT"; + default -> String.valueOf(refcount); + }; } /** @@ -329,25 +321,22 @@ abstract class ReactorStmtCtx, E extends Effec // @Override - public final > V namespaceItem(final Class<@NonNull N> type, - final T key) { + public final V namespaceItem(final ParserNamespace type, final T key) { return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key); } @Override - public final > Map namespace(final Class<@NonNull N> type) { + public final Map namespace(final ParserNamespace type) { return getNamespace(type); } @Override - public final > - Map localNamespacePortion(final Class<@NonNull N> type) { + public final Map localNamespacePortion(final ParserNamespace type) { return getLocalNamespace(type); } @Override - protected > void onNamespaceElementAdded(final Class type, final K key, - final V value) { + protected void onNamespaceElementAdded(final ParserNamespace type, final K key, final V value) { // definition().onNamespaceElementAdded(this, type, key, value); } @@ -368,9 +357,11 @@ abstract class ReactorStmtCtx, E extends Effec QNameModule targetModule); @Override - public final ReactorStmtCtx replicaAsChildOf(final Mutable parent) { + public final ReplicaStatementContext 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 replicaAsChildOf(@NonNull StatementContextBase parent); @@ -383,17 +374,11 @@ abstract class ReactorStmtCtx, 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 +391,43 @@ abstract class ReactorStmtCtx, E extends Effec abstract @NonNull E createEffective(); + /** + * Routing of the request to build an effective statement from {@link InferredStatementContext} towards the original + * definition site. This is needed to pick the correct instantiation method: for declared statements we will + * eventually land in {@link AbstractResumedStatement}, for underclared statements that will be + * {@link UndeclaredStmtCtx}. + * + * @param factory Statement factory + * @param ctx Inferred statement context, i.e. where the effective statement is instantiated + * @return Built effective stateue + */ + abstract @NonNull E createInferredEffective(@NonNull StatementFactory factory, + @NonNull InferredStatementContext ctx, Stream> declared, + Stream> effective); + + /** + * Attach an effective copy of this statement. This essentially acts as a map, where we make a few assumptions: + *
    + *
  • {@code copy} and {@code this} statement share {@link #getOriginalCtx()} if it exists
  • + *
  • {@code copy} did not modify any statements relative to {@code this}
  • + *
+ * + * @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 instances; + if (local instanceof EffectiveInstances) { + instances = (EffectiveInstances) 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 @@ -443,14 +465,15 @@ abstract class ReactorStmtCtx, E extends Effec // // + // Non-final form ImplicitStmtCtx @Override - public final boolean isSupportedToBuildEffective() { + public boolean isSupportedToBuildEffective() { return isSupportedToBuildEffective; } @Override - public final void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) { - this.isSupportedToBuildEffective = isSupportedToBuildEffective; + public final void setUnsupported() { + this.isSupportedToBuildEffective = false; } @Override @@ -469,8 +492,8 @@ abstract class ReactorStmtCtx, E extends Effec */ if (isParentSupportedByFeatures()) { // If the set of supported features has not been provided, all features are supported by default. - final Set supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class, - SupportedFeatures.SUPPORTED_FEATURES); + final Set supportedFeatures = getFromNamespace(ParserNamespaces.SUPPORTED_FEATURES, + Empty.value()); if (supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures)) { flags |= SET_SUPPORTED_BY_FEATURES; return true; @@ -614,63 +637,38 @@ abstract class ReactorStmtCtx, 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); + final Object argument = argument(); + if (argument instanceof QName qname) { + return qname.getModule(); } - if (argument instanceof String) { - return parentPath.createChild(interpretAsQName((String) argument)); + if (argument instanceof String str) { + // FIXME: This may yield illegal argument exceptions + return StmtContextUtils.qnameFromArgument(getOriginalCtx().orElse(this), str).getModule(); } - if (argument instanceof SchemaNodeIdentifier + if (argument instanceof SchemaNodeIdentifier sni && (producesDeclared(AugmentStatement.class) || producesDeclared(RefineStatement.class) || producesDeclared(DeviationStatement.class))) { - - return parentPath.createChild(((SchemaNodeIdentifier) argument).getNodeIdentifiers()); + return sni.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 +821,10 @@ abstract class ReactorStmtCtx, 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 +848,9 @@ abstract class ReactorStmtCtx, 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(); } } }