BUG-7052: reduce StatementContextBase proliferation even more
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementContextBase.java
index 0819d9c81721d27f85e8cf2a28b38227b7abfd86..423a0cabb9ff5936f3c29c0147915f29c31a737e 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableCollection;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMultimap;
@@ -22,7 +21,10 @@ import java.util.Collections;
 import java.util.EnumMap;
 import java.util.EventListener;
 import java.util.Iterator;
+import java.util.Optional;
+import java.util.Set;
 import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QName;
 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;
@@ -36,15 +38,19 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 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.SourceException;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
+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.ValueAddedListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
         extends NamespaceStorageSupport implements StmtContext.Mutable<A, D, E> {
-
     /**
-     * event listener when an item is added to model namespace
+     * event listener when an item is added to model namespace.
      */
     interface OnNamespaceItemAdded extends EventListener {
         /**
@@ -54,7 +60,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     /**
-     * event listener when a parsing {@link ModelProcessingPhase} is completed
+     * event listener when a parsing {@link ModelProcessingPhase} is completed.
      */
     interface OnPhaseFinished extends EventListener {
         /**
@@ -64,28 +70,30 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     /**
-     * interface for all mutations within an {@link ModelActionBuilder.InferenceAction}
+     * interface for all mutations within an {@link ModelActionBuilder.InferenceAction}.
      */
     interface ContextMutation {
 
         boolean isFinished();
     }
 
+    private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
+
     private final StatementDefinitionContext<A, D, E> definition;
     private final StatementSourceReference statementDeclSource;
     private final String rawArgument;
 
     private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
     private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
-    private Collection<StatementContextBase<?, ?, ?>> effective = ImmutableList.of();
-    private Collection<StatementContextBase<?, ?, ?>> effectOfStatement = ImmutableList.of();
+    private Collection<Mutable<?, ?, ?>> effective = ImmutableList.of();
+    private Collection<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
     private StatementMap substatements = StatementMap.empty();
 
-    private SupportedByFeatures supportedByFeatures = SupportedByFeatures.UNDEFINED;
+    private Boolean supportedByFeatures = null;
     private CopyHistory copyHistory = CopyHistory.original();
     private boolean isSupportedToBuildEffective = true;
     private ModelProcessingPhase completedPhase = null;
-    private StatementContextBase<?, ?, ?> originalCtx;
+    private StmtContext<?, ?, ?> originalCtx;
     private D declaredInstance;
     private E effectiveInstance;
     private int order = 0;
@@ -94,7 +102,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             final String rawArgument) {
         this.definition = Preconditions.checkNotNull(def);
         this.statementDeclSource = Preconditions.checkNotNull(ref);
-        this.rawArgument = rawArgument;
+        this.rawArgument = def.internArgument(rawArgument);
     }
 
     StatementContextBase(final StatementContextBase<A, D, E> original) {
@@ -107,12 +115,12 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     @Override
-    public Collection<StatementContextBase<?, ?, ?>> getEffectOfStatement() {
+    public Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
         return effectOfStatement;
     }
 
     @Override
-    public void addAsEffectOfStatement(final StatementContextBase<?, ?, ?> ctx) {
+    public void addAsEffectOfStatement(final StmtContext<?, ?, ?> ctx) {
         if (effectOfStatement.isEmpty()) {
             effectOfStatement = new ArrayList<>(1);
         }
@@ -120,7 +128,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     @Override
-    public void addAsEffectOfStatement(final Collection<StatementContextBase<?, ?, ?>> ctxs) {
+    public void addAsEffectOfStatement(final Collection<? extends StmtContext<?, ?, ?>> ctxs) {
         if (ctxs.isEmpty()) {
             return;
         }
@@ -132,13 +140,16 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     @Override
-    public SupportedByFeatures getSupportedByFeatures() {
-        return supportedByFeatures;
-    }
+    public boolean isSupportedByFeatures() {
+        if (supportedByFeatures == null) {
+            final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class,
+                SupportedFeatures.SUPPORTED_FEATURES);
+            // If the set of supported features has not been provided, all features are supported by default.
+            supportedByFeatures = supportedFeatures == null ? Boolean.TRUE
+                    : StmtContextUtils.checkFeatureSupport(this, supportedFeatures);
+        }
 
-    @Override
-    public void setSupportedByFeatures(final boolean isSupported) {
-        this.supportedByFeatures = isSupported ? SupportedByFeatures.SUPPORTED : SupportedByFeatures.NOT_SUPPORTED;
+        return supportedByFeatures.booleanValue();
     }
 
     @Override
@@ -162,12 +173,12 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     @Override
-    public StatementContextBase<?, ?, ?> getOriginalCtx() {
+    public StmtContext<?, ?, ?> getOriginalCtx() {
         return originalCtx;
     }
 
     @Override
-    public void setOriginalCtx(final StatementContextBase<?, ?, ?> originalCtx) {
+    public void setOriginalCtx(final StmtContext<?, ?, ?> originalCtx) {
         this.originalCtx = originalCtx;
     }
 
@@ -226,13 +237,24 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     @Nonnull
     @Override
-    public Collection<StatementContextBase<?, ?, ?>> declaredSubstatements() {
+    public Collection<? extends StmtContext<?, ?, ?>> declaredSubstatements() {
+        return substatements.values();
+    }
+
+    @Nonnull
+    @Override
+    public Collection<? extends Mutable<?, ?, ?>> mutableDeclaredSubstatements() {
         return substatements.values();
     }
 
+    @Override
+    public Collection<? extends StmtContext<?, ?, ?>> effectiveSubstatements() {
+        return mutableEffectiveSubstatements();
+    }
+
     @Nonnull
     @Override
-    public Collection<StatementContextBase<?, ?, ?>> effectiveSubstatements() {
+    public Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
         if (effective instanceof ImmutableCollection) {
             return effective;
         }
@@ -240,7 +262,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         return Collections.unmodifiableCollection(effective);
     }
 
-    public void removeStatementsFromEffectiveSubstatements(final Collection<StatementContextBase<?, ?, ?>> substatements) {
+    public void removeStatementsFromEffectiveSubstatements(final Collection<? extends StmtContext<?, ?, ?>> substatements) {
         if (!effective.isEmpty()) {
             effective.removeAll(substatements);
             shrinkEffective();
@@ -258,9 +280,9 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             return;
         }
 
-        final Iterator<StatementContextBase<?, ?, ?>> iterator = effective.iterator();
+        final Iterator<? extends StmtContext<?, ?, ?>> iterator = effective.iterator();
         while (iterator.hasNext()) {
-            final StatementContextBase<?, ?, ?> next = iterator.next();
+            final StmtContext<?, ?, ?> next = iterator.next();
             if (statementDef.equals(next.getPublicDefinition())) {
                 iterator.remove();
             }
@@ -290,9 +312,9 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             return;
         }
 
-        final Iterator<StatementContextBase<?, ?, ?>> iterator = effective.iterator();
+        final Iterator<Mutable<?, ?, ?>> iterator = effective.iterator();
         while (iterator.hasNext()) {
-            final StatementContextBase<?, ?, ?> next = iterator.next();
+            final Mutable<?, ?, ?> next = iterator.next();
             if (statementDef.equals(next.getPublicDefinition()) && statementArg.equals(next.rawStatementArgument())) {
                 iterator.remove();
             }
@@ -310,9 +332,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      * @throws NullPointerException
      *             if statement parameter is null
      */
-    public void addEffectiveSubstatement(final StatementContextBase<?, ?, ?> substatement) {
-        Preconditions.checkNotNull(substatement, "StatementContextBase effective substatement cannot be null at: %s",
-            getStatementSourceReference());
+    public void addEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
         beforeAddEffectiveStatement(1);
         effective.add(substatement);
     }
@@ -326,7 +346,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      * @throws NullPointerException
      *             if statement parameter is null
      */
-    public void addEffectiveSubstatements(final Collection<StatementContextBase<?, ?, ?>> substatements) {
+    public void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> substatements) {
         if (substatements.isEmpty()) {
             return;
         }
@@ -356,13 +376,20 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      * @param argument statement argument
      * @return A new substatement
      */
-    final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>> StatementContextBase<CA, CD, CE>
-            createSubstatement(final int offset, final StatementDefinitionContext<CA, CD, CE> def,
-                    final StatementSourceReference ref, final String argument) {
+    public final <CA, CD extends DeclaredStatement<CA>, CE extends EffectiveStatement<CA, CD>> StatementContextBase<CA, CD, CE> createSubstatement(
+            final int offset, final StatementDefinitionContext<CA, CD, CE> def, final StatementSourceReference ref,
+            final String argument) {
         final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
         Preconditions.checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
                 "Declared statement cannot be added in effective phase at: %s", getStatementSourceReference());
 
+        final Optional<StatementContextBase<?, ?, ?>> implicitStatement = definition.beforeSubStatementCreated(this,
+            offset, def, ref, argument);
+        if(implicitStatement.isPresent()) {
+            final StatementContextBase<?, ?, ?> presentImplicitStmt = implicitStatement.get();
+            return presentImplicitStmt.createSubstatement(offset, def, ref, argument);
+        }
+
         final StatementContextBase<CA, CD, CE> ret = new SubstatementContext<>(this, def, ref, argument);
         substatements = substatements.put(offset, ret);
         def.onStatementAdded(ret);
@@ -379,9 +406,6 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         return substatements.get(offset);
     }
 
-    /**
-     * builds {@link DeclaredStatement} for statement context
-     */
     @Override
     public D buildDeclared() {
         Preconditions.checkArgument(completedPhase == ModelProcessingPhase.FULL_DECLARATION
@@ -392,9 +416,6 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         return declaredInstance;
     }
 
-    /**
-     * builds {@link EffectiveStatement} for statement context
-     */
     @Override
     public E buildEffective() {
         if (effectiveInstance == null) {
@@ -404,7 +425,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     /**
-     * tries to execute current {@link ModelProcessingPhase} of source parsing
+     * tries to execute current {@link ModelProcessingPhase} of source parsing.
      *
      * @param phase
      *            to be executed (completed)
@@ -438,8 +459,10 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         for (final StatementContextBase<?, ?, ?> child : substatements.values()) {
             finished &= child.tryToCompletePhase(phase);
         }
-        for (final StatementContextBase<?, ?, ?> child : effective) {
-            finished &= child.tryToCompletePhase(phase);
+        for (final Mutable<?, ?, ?> child : effective) {
+            if (child instanceof StatementContextBase) {
+                finished &= ((StatementContextBase<?, ?, ?>) child).tryToCompletePhase(phase);
+            }
         }
 
         if (finished) {
@@ -450,7 +473,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     /**
-     * Occurs on end of {@link ModelProcessingPhase} of source parsing
+     * Occurs on end of {@link ModelProcessingPhase} of source parsing.
      *
      * @param phase
      *            that was to be completed (finished)
@@ -503,13 +526,9 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         definition().checkNamespaceAllowed(type);
     }
 
-    /**
-     * occurs when an item is added to model namespace
-     *
-     * @throws SourceException instance of SourceException
-     */
     @Override
-    protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key, final V value) {
+    protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key,
+            final V value) {
         // definition().onNamespaceElementAdded(this, type, key, value);
     }
 
@@ -517,27 +536,26 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             final OnNamespaceItemAdded listener) throws SourceException {
         final Object potential = getFromNamespace(type, key);
         if (potential != null) {
+            LOG.trace("Listener on {} key {} satisfied immediately", type, key);
             listener.namespaceItemAdded(this, type, key, potential);
             return;
         }
+
         final NamespaceBehaviour<K, V, N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
-        if (behaviour instanceof NamespaceBehaviourWithListeners) {
-            final NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K, V, N>) behaviour;
-            casted.addValueListener(new ValueAddedListener<K>(this, key) {
-                @Override
-                void onValueAdded(final Object key, final Object value) {
-                    try {
-                        listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
-                    } catch (final SourceException e) {
-                        throw Throwables.propagate(e);
-                    }
-                }
-            });
-        }
+        Preconditions.checkArgument(behaviour instanceof NamespaceBehaviourWithListeners,
+            "Namespace {} does not support listeners", type);
+
+        final NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K, V, N>) behaviour;
+        casted.addValueListener(new ValueAddedListener<K>(this, key) {
+            @Override
+            void onValueAdded(final Object key, final Object value) {
+                listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
+            }
+        });
     }
 
     /**
-     * @see StatementSupport#getPublicView()
+     * See {@link StatementSupport#getPublicView()}.
      */
     @Nonnull
     @Override
@@ -603,19 +621,9 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         phaseMutation.put(phase, mutation);
     }
 
-    /**
-     * adds statement to namespace map with the key
-     *
-     * @param namespace
-     *            {@link StatementNamespace} child that determines namespace to be added to
-     * @param key
-     *            of type according to namespace class specification
-     * @param stmt
-     *            to be added to namespace map
-     */
     @Override
-    public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<N> namespace, final KT key,
-            final StmtContext<?, ?, ?> stmt) {
+    public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<N> namespace,
+            final KT key,final StmtContext<?, ?, ?> stmt) {
         addContextToNamespace(namespace, key, stmt);
     }