import com.google.common.base.VerifyException;
import java.util.Collection;
import java.util.Map;
+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.QName;
import org.opendaylight.yangtools.yang.common.YangVersion;
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.IdentifierNamespace;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.ConfigEffectiveStatement;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
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.SupportedFeaturesNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private @Nullable E 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
+ // of this flag -- eliminating the initial alignment shadow used by below gap-filler fields.
+ private boolean isSupportedToBuildEffective = true;
+
+ // Flag bit assignments
+ private static final int IS_SUPPORTED_BY_FEATURES = 0x01;
+ private static final int HAVE_SUPPORTED_BY_FEATURES = 0x02;
+ private static final int IS_IGNORE_IF_FEATURE = 0x04;
+ private static final int HAVE_IGNORE_IF_FEATURE = 0x08;
+ // Note: these four are related
+ private static final int IS_IGNORE_CONFIG = 0x10;
+ private static final int HAVE_IGNORE_CONFIG = 0x20;
+ private static final int IS_CONFIGURATION = 0x40;
+ private static final int HAVE_CONFIGURATION = 0x80;
+
+ // Have-and-set flag constants, also used as masks
+ private static final int SET_SUPPORTED_BY_FEATURES = HAVE_SUPPORTED_BY_FEATURES | IS_SUPPORTED_BY_FEATURES;
+ private static final int SET_CONFIGURATION = HAVE_CONFIGURATION | IS_CONFIGURATION;
+ // Note: implies SET_CONFIGURATION, allowing fewer bit operations to be performed
+ private static final int SET_IGNORE_CONFIG = HAVE_IGNORE_CONFIG | IS_IGNORE_CONFIG | SET_CONFIGURATION;
+ private static final int SET_IGNORE_IF_FEATURE = HAVE_IGNORE_IF_FEATURE | IS_IGNORE_IF_FEATURE;
+
+ // Flags for use with SubstatementContext. These are hiding in the alignment shadow created by above boolean and
+ // hence improve memory layout.
+ private byte flags;
+
+ // Flag for use with AbstractResumedStatement. This is hiding in the alignment shadow created by above boolean
+ // FIXME: move this out once we have JDK15+
+ private boolean fullyDefined;
+
+ ReactorStmtCtx() {
+ // Empty on purpose
+ }
+
+ ReactorStmtCtx(final ReactorStmtCtx<A, D, E> original) {
+ isSupportedToBuildEffective = original.isSupportedToBuildEffective;
+ fullyDefined = original.fullyDefined;
+ flags = original.flags;
+ }
+
//
//
// Common public interface contracts with simple mechanics. Please keep this in one logical block, so we do not end
abstract @NonNull E createEffective();
+ //
+ //
+ // Flags-based mechanics. These include public interfaces as well as all the crud we have lurking in our alignment
+ // shadow.
+ //
+ //
+
+ @Override
+ public final boolean isSupportedToBuildEffective() {
+ return isSupportedToBuildEffective;
+ }
+
+ @Override
+ public final void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) {
+ this.isSupportedToBuildEffective = isSupportedToBuildEffective;
+ }
+
+ @Override
+ public final boolean isSupportedByFeatures() {
+ final int fl = flags & SET_SUPPORTED_BY_FEATURES;
+ if (fl != 0) {
+ return fl == SET_SUPPORTED_BY_FEATURES;
+ }
+ if (isIgnoringIfFeatures()) {
+ flags |= SET_SUPPORTED_BY_FEATURES;
+ return true;
+ }
+
+ /*
+ * If parent is supported, we need to check if-features statements of this context.
+ */
+ 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);
+ if (supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures)) {
+ flags |= SET_SUPPORTED_BY_FEATURES;
+ return true;
+ }
+ }
+
+ // Either parent is not supported or this statement is not supported
+ flags |= HAVE_SUPPORTED_BY_FEATURES;
+ return false;
+ }
+
+ protected abstract boolean isParentSupportedByFeatures();
+
+ /**
+ * Config statements are not all that common which means we are performing a recursive search towards the root
+ * every time {@link #isConfiguration()} is invoked. This is quite expensive because it causes a linear search
+ * for the (usually non-existent) config statement.
+ *
+ * <p>
+ * This method maintains a resolution cache, so once we have returned a result, we will keep on returning the same
+ * result without performing any lookups, solely to support {@link SubstatementContext#isConfiguration()}.
+ *
+ * <p>
+ * Note: use of this method implies that {@link #isIgnoringConfig()} is realized with
+ * {@link #isIgnoringConfig(StatementContextBase)}.
+ */
+ final boolean isConfiguration(final StatementContextBase<?, ?, ?> parent) {
+ final int fl = flags & SET_CONFIGURATION;
+ if (fl != 0) {
+ return fl == SET_CONFIGURATION;
+ }
+ if (isIgnoringConfig(parent)) {
+ // Note: SET_CONFIGURATION has been stored in flags
+ return true;
+ }
+
+ final boolean isConfig;
+ final Optional<Boolean> optConfig = findSubstatementArgument(ConfigEffectiveStatement.class);
+ if (optConfig.isPresent()) {
+ isConfig = optConfig.orElseThrow();
+ if (isConfig) {
+ // Validity check: if parent is config=false this cannot be a config=true
+ InferenceException.throwIf(!parent.isConfiguration(), sourceReference(),
+ "Parent node has config=false, this node must not be specifed as config=true");
+ }
+ } else {
+ // If "config" statement is not specified, the default is the same as the parent's "config" value.
+ isConfig = parent.isConfiguration();
+ }
+
+ // Resolved, make sure we cache this return
+ flags |= isConfig ? SET_CONFIGURATION : HAVE_CONFIGURATION;
+ return isConfig;
+ }
+
+ protected abstract boolean isIgnoringConfig();
+
+ /**
+ * This method 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. Exists only to support
+ * {@link SubstatementContext#isIgnoringConfig()}.
+ *
+ * <p>
+ * Note: use of this method implies that {@link #isConfiguration()} is realized with
+ * {@link #isConfiguration(StatementContextBase)}.
+ */
+ final boolean isIgnoringConfig(final StatementContextBase<?, ?, ?> parent) {
+ final int fl = flags & SET_IGNORE_CONFIG;
+ if (fl != 0) {
+ return fl == SET_IGNORE_CONFIG;
+ }
+ if (definition().support().isIgnoringConfig() || parent.isIgnoringConfig()) {
+ flags |= SET_IGNORE_CONFIG;
+ return true;
+ }
+
+ flags |= HAVE_IGNORE_CONFIG;
+ return false;
+ }
+
+ protected abstract boolean isIgnoringIfFeatures();
+
+ /**
+ * This method 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. Exists only to support
+ * {@link SubstatementContext#isIgnoringIfFeatures()}.
+ */
+ final boolean isIgnoringIfFeatures(final StatementContextBase<?, ?, ?> parent) {
+ final int fl = flags & SET_IGNORE_IF_FEATURE;
+ if (fl != 0) {
+ return fl == SET_IGNORE_IF_FEATURE;
+ }
+ if (definition().support().isIgnoringIfFeatures() || parent.isIgnoringIfFeatures()) {
+ flags |= SET_IGNORE_IF_FEATURE;
+ return true;
+ }
+
+ flags |= HAVE_IGNORE_IF_FEATURE;
+ return false;
+ }
+
+ // These two exists only due to memory optimization, should live in AbstractResumedStatement
+ final boolean fullyDefined() {
+ return fullyDefined;
+ }
+
+ final void setFullyDefined() {
+ fullyDefined = true;
+ }
+
//
//
// Reference counting mechanics start. Please keep these methods in one block for clarity. Note this does not
import java.util.List;
import java.util.Map.Entry;
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.model.api.meta.IdentifierNamespace;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ConfigEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
import org.opendaylight.yangtools.yang.parser.spi.meta.ImplicitParentAwareStatementSupport;
-import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
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.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener;
import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.PredicateValueAddedListener;
import org.slf4j.Logger;
private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
- // Flag bit assignments
- private static final int IS_SUPPORTED_BY_FEATURES = 0x01;
- private static final int HAVE_SUPPORTED_BY_FEATURES = 0x02;
- private static final int IS_IGNORE_IF_FEATURE = 0x04;
- private static final int HAVE_IGNORE_IF_FEATURE = 0x08;
- // Note: these four are related
- private static final int IS_IGNORE_CONFIG = 0x10;
- private static final int HAVE_IGNORE_CONFIG = 0x20;
- private static final int IS_CONFIGURATION = 0x40;
- private static final int HAVE_CONFIGURATION = 0x80;
-
- // Have-and-set flag constants, also used as masks
- private static final int SET_SUPPORTED_BY_FEATURES = HAVE_SUPPORTED_BY_FEATURES | IS_SUPPORTED_BY_FEATURES;
- private static final int SET_CONFIGURATION = HAVE_CONFIGURATION | IS_CONFIGURATION;
- // Note: implies SET_CONFIGURATION, allowing fewer bit operations to be performed
- private static final int SET_IGNORE_CONFIG = HAVE_IGNORE_CONFIG | IS_IGNORE_CONFIG | SET_CONFIGURATION;
- private static final int SET_IGNORE_IF_FEATURE = HAVE_IGNORE_IF_FEATURE | IS_IGNORE_IF_FEATURE;
-
private final CopyHistory copyHistory;
// Note: this field can strictly be derived in InferredStatementContext, but it forms the basis of many of our
// operations, hence we want to keep it close by.
private @Nullable ModelProcessingPhase completedPhase;
- // 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
- // of this flag -- eliminating the initial alignment shadow used by below gap-filler fields.
- private boolean isSupportedToBuildEffective = true;
-
- // Flag for use with AbstractResumedStatement. This is hiding in the alignment shadow created by above boolean
- private boolean fullyDefined;
-
- // Flags for use with SubstatementContext. These are hiding in the alignment shadow created by above boolean and
- // hence improve memory layout.
- private byte flags;
-
// 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.
private volatile SchemaPath schemaPath;
// Copy constructor used by subclasses to implement reparent()
StatementContextBase(final StatementContextBase<A, D, E> original) {
+ super(original);
this.copyHistory = original.copyHistory;
this.definition = original.definition;
-
- this.isSupportedToBuildEffective = original.isSupportedToBuildEffective;
- this.fullyDefined = original.fullyDefined;
this.completedPhase = original.completedPhase;
- this.flags = original.flags;
}
StatementContextBase(final StatementDefinitionContext<A, D, E> def) {
effectOfStatement.addAll(ctxs);
}
- @Override
- public boolean isSupportedByFeatures() {
- final int fl = flags & SET_SUPPORTED_BY_FEATURES;
- if (fl != 0) {
- return fl == SET_SUPPORTED_BY_FEATURES;
- }
- if (isIgnoringIfFeatures()) {
- flags |= SET_SUPPORTED_BY_FEATURES;
- return true;
- }
-
- /*
- * If parent is supported, we need to check if-features statements of this context.
- */
- 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);
- if (supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures)) {
- flags |= SET_SUPPORTED_BY_FEATURES;
- return true;
- }
- }
-
- // Either parent is not supported or this statement is not supported
- flags |= HAVE_SUPPORTED_BY_FEATURES;
- return false;
- }
-
- protected abstract boolean isParentSupportedByFeatures();
-
- @Override
- public boolean isSupportedToBuildEffective() {
- return isSupportedToBuildEffective;
- }
-
- @Override
- public void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) {
- this.isSupportedToBuildEffective = isSupportedToBuildEffective;
- }
-
@Override
public CopyHistory getCopyHistory() {
return copyHistory;
return effective.isEmpty() ? new ArrayList<>(toAdd) : effective;
}
- // These two exists only due to memory optimization, should live in AbstractResumedStatement
- final boolean fullyDefined() {
- return fullyDefined;
- }
-
- final void setFullyDefined() {
- fullyDefined = true;
- }
-
// Exposed for ReplicaStatementContext
@Override
E createEffective() {
*/
abstract boolean hasEmptySubstatements();
- /**
- * Config statements are not all that common which means we are performing a recursive search towards the root
- * every time {@link #isConfiguration()} is invoked. This is quite expensive because it causes a linear search
- * for the (usually non-existent) config statement.
- *
- * <p>
- * This method maintains a resolution cache, so once we have returned a result, we will keep on returning the same
- * result without performing any lookups, solely to support {@link SubstatementContext#isConfiguration()}.
- *
- * <p>
- * Note: use of this method implies that {@link #isIgnoringConfig()} is realized with
- * {@link #isIgnoringConfig(StatementContextBase)}.
- */
- final boolean isConfiguration(final StatementContextBase<?, ?, ?> parent) {
- final int fl = flags & SET_CONFIGURATION;
- if (fl != 0) {
- return fl == SET_CONFIGURATION;
- }
- if (isIgnoringConfig(parent)) {
- // Note: SET_CONFIGURATION has been stored in flags
- return true;
- }
-
- final boolean isConfig;
- final Optional<Boolean> optConfig = findSubstatementArgument(ConfigEffectiveStatement.class);
- if (optConfig.isPresent()) {
- isConfig = optConfig.orElseThrow();
- if (isConfig) {
- // Validity check: if parent is config=false this cannot be a config=true
- InferenceException.throwIf(!parent.isConfiguration(), sourceReference(),
- "Parent node has config=false, this node must not be specifed as config=true");
- }
- } else {
- // If "config" statement is not specified, the default is the same as the parent's "config" value.
- isConfig = parent.isConfiguration();
- }
-
- // Resolved, make sure we cache this return
- flags |= isConfig ? SET_CONFIGURATION : HAVE_CONFIGURATION;
- return isConfig;
- }
-
- protected abstract boolean isIgnoringConfig();
-
- /**
- * This method 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. Exists only to support
- * {@link SubstatementContext#isIgnoringConfig()}.
- *
- * <p>
- * Note: use of this method implies that {@link #isConfiguration()} is realized with
- * {@link #isConfiguration(StatementContextBase)}.
- */
- final boolean isIgnoringConfig(final StatementContextBase<?, ?, ?> parent) {
- final int fl = flags & SET_IGNORE_CONFIG;
- if (fl != 0) {
- return fl == SET_IGNORE_CONFIG;
- }
- if (definition.support().isIgnoringConfig() || parent.isIgnoringConfig()) {
- flags |= SET_IGNORE_CONFIG;
- return true;
- }
-
- flags |= HAVE_IGNORE_CONFIG;
- return false;
- }
-
- protected abstract boolean isIgnoringIfFeatures();
-
- /**
- * This method 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. Exists only to support
- * {@link SubstatementContext#isIgnoringIfFeatures()}.
- */
- final boolean isIgnoringIfFeatures(final StatementContextBase<?, ?, ?> parent) {
- final int fl = flags & SET_IGNORE_IF_FEATURE;
- if (fl != 0) {
- return fl == SET_IGNORE_IF_FEATURE;
- }
- if (definition.support().isIgnoringIfFeatures() || parent.isIgnoringIfFeatures()) {
- flags |= SET_IGNORE_IF_FEATURE;
- return true;
- }
-
- flags |= HAVE_IGNORE_IF_FEATURE;
- return false;
- }
-
abstract @NonNull Optional<SchemaPath> schemaPath();
// Exists only to support {SubstatementContext,InferredStatementContext}.schemaPath()