BUG-6972: Do not allow root StmtContext to be copied
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / RootStatementContext.java
index 7c8b2d5877d44e16bba09744e3fbe44dd4568467..1246b9a8357f4838d8f5dae34465c64fbb1fcd9e 100644 (file)
@@ -11,24 +11,28 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Verify;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Map;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangVersion;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 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.IdentifierNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
+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.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.StmtContext;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedModuleContext;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 
 /**
  * Root statement class for a YANG source. All statements defined in that YANG source are mapped underneath an instance
@@ -43,45 +47,27 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
     private final A argument;
 
     private YangVersion version;
+    private Collection<ModuleIdentifier> requiredModules = ImmutableSet.of();
+    private ModuleIdentifier identifier;
 
     /**
      * References to RootStatementContext of submodules which are included in this source.
      */
     private Collection<RootStatementContext<?, ?, ?>> includedContexts = ImmutableList.of();
 
-    RootStatementContext(final ContextBuilder<A, D, E> builder, final SourceSpecificContext sourceContext) {
-        super(builder);
+    RootStatementContext(final SourceSpecificContext sourceContext, final StatementDefinitionContext<A, D, E> def,
+        final StatementSourceReference ref, final String rawArgument) {
+        super(def, ref, rawArgument);
         this.sourceContext = Preconditions.checkNotNull(sourceContext);
-        this.argument = builder.getDefinition().parseArgumentValue(this, builder.getRawArgument());
+        this.argument = def.parseArgumentValue(this, rawStatementArgument());
     }
 
-    RootStatementContext(final ContextBuilder<A, D, E> builder, final SourceSpecificContext sourceContext,
-            final YangVersion version) {
-        this(builder, sourceContext);
+    RootStatementContext(final SourceSpecificContext sourceContext, final StatementDefinitionContext<A, D, E> def,
+            final StatementSourceReference ref, final String rawArgument, final YangVersion version,
+            final ModuleIdentifier identifier) {
+        this(sourceContext, def, ref, rawArgument);
         this.setRootVersion(version);
-    }
-
-    RootStatementContext(final RootStatementContext<A, D, E> original, final QNameModule newQNameModule,
-        final CopyType typeOfCopy) {
-        super(original);
-
-        sourceContext = Preconditions.checkNotNull(original.sourceContext);
-        this.argument = original.argument;
-
-        final Collection<StatementContextBase<?, ?, ?>> declared = original.declaredSubstatements();
-        final Collection<StatementContextBase<?, ?, ?>> effective = original.effectiveSubstatements();
-        final Collection<StatementContextBase<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
-
-        for (final StatementContextBase<?, ?, ?> stmtContext : declared) {
-            if (StmtContextUtils.areFeaturesSupported(stmtContext)) {
-                buffer.add(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
-            }
-        }
-        for (final StmtContext<?, ?, ?> stmtContext : effective) {
-            buffer.add(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
-        }
-
-        addEffectiveSubstatements(buffer);
+        this.setRootIdentifier(identifier);
     }
 
     /**
@@ -100,9 +86,6 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
         return sourceContext;
     }
 
-    /**
-     * @return registry of source context
-     */
     @Override
     public Registry getBehaviourRegistry() {
         return sourceContext;
@@ -130,36 +113,16 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
         return argument;
     }
 
-    /**
-     * @return copy of this considering {@link CopyType} (augment, uses)
-     *
-     * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException instance of SourceException
-     */
     @Override
-    public StatementContextBase<?, ?, ?> createCopy(final StatementContextBase<?, ?, ?> newParent,
+    public StatementContextBase<A, D, E> createCopy(final StatementContextBase<?, ?, ?> newParent,
             final CopyType typeOfCopy) {
-        return createCopy(null, newParent, typeOfCopy);
+        throw new UnsupportedOperationException("Root context cannot be copied");
     }
 
-    /**
-     * @return copy of this considering {@link CopyType} (augment, uses)
-     *
-     * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException instance of SourceException
-     */
     @Override
     public StatementContextBase<A, D, E> createCopy(final QNameModule newQNameModule,
             final StatementContextBase<?, ?, ?> newParent, final CopyType typeOfCopy) {
-        final RootStatementContext<A, D, E> copy = new RootStatementContext<>(this, newQNameModule, typeOfCopy);
-
-        copy.appendCopyHistory(typeOfCopy, this.getCopyHistory());
-
-        if (this.getOriginalCtx() != null) {
-            copy.setOriginalCtx(this.getOriginalCtx());
-        } else {
-            copy.setOriginalCtx(this);
-        }
-        definition().onStatementAdded(copy);
-        return copy;
+        throw new UnsupportedOperationException("Root context cannot be copied");
     }
 
     @Nonnull
@@ -168,17 +131,14 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
         return Optional.of(SchemaPath.ROOT);
     }
 
-    /**
-     * @return true
-     */
     @Override
-    public boolean isRootContext() {
+    public boolean isConfiguration() {
         return true;
     }
 
     @Override
-    public boolean isConfiguration() {
-        return true;
+    public boolean isInYangDataExtensionBody() {
+        return false;
     }
 
     @Override
@@ -187,7 +147,7 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
     }
 
     @Override
-    public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(final Class<N> type, final K key,
+    public <K, V, N extends IdentifierNamespace<K, V>> V putToLocalStorage(final Class<N> type, final K key,
             final V value) {
         if (IncludedModuleContext.class.isAssignableFrom(type)) {
             if (includedContexts.isEmpty()) {
@@ -196,17 +156,33 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
             Verify.verify(value instanceof RootStatementContext);
             includedContexts.add((RootStatementContext<?, ?, ?>) value);
         }
-        super.addToLocalStorage(type, key, value);
+        return super.putToLocalStorage(type, key, value);
     }
 
+    @Nullable
     @Override
     public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
+        return getFromLocalStorage(type, key, new HashSet<>());
+    }
+
+    /*
+     * We need to track already checked RootStatementContexts due to possible
+     * circular chains of includes between submodules
+     */
+    @Nullable
+    private <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key,
+            final HashSet<RootStatementContext<?, ?, ?>> alreadyChecked) {
         final V potentialLocal = super.getFromLocalStorage(type, key);
         if (potentialLocal != null) {
             return potentialLocal;
         }
-        for (final NamespaceStorageNode includedSource : includedContexts) {
-            final V potential = includedSource.getFromLocalStorage(type, key);
+
+        alreadyChecked.add(this);
+        for (final RootStatementContext<?, ?, ?> includedSource : includedContexts) {
+            if (alreadyChecked.contains(includedSource)) {
+                continue;
+            }
+            final V potential = includedSource.getFromLocalStorage(type, key, alreadyChecked);
             if (potential != null) {
                 return potential;
             }
@@ -217,12 +193,27 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
     @Nullable
     @Override
     public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
+        return getAllFromLocalStorage(type, new HashSet<>());
+    }
+
+    /*
+     * We need to track already checked RootStatementContexts due to possible
+     * circular chains of includes between submodules
+     */
+    @Nullable
+    private <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type,
+            final HashSet<RootStatementContext<?, ?, ?>> alreadyChecked) {
         final Map<K, V> potentialLocal = super.getAllFromLocalStorage(type);
         if (potentialLocal != null) {
             return potentialLocal;
         }
-        for (final NamespaceStorageNode includedSource : includedContexts) {
-            final Map<K, V> potential = includedSource.getAllFromLocalStorage(type);
+
+        alreadyChecked.add(this);
+        for (final RootStatementContext<?, ?, ?> includedSource : includedContexts) {
+            if (alreadyChecked.contains(includedSource)) {
+                continue;
+            }
+            final Map<K, V> potential = includedSource.getAllFromLocalStorage(type, alreadyChecked);
             if (potential != null) {
                 return potential;
             }
@@ -243,4 +234,33 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
                 this.version);
         this.version = Preconditions.checkNotNull(version);
     }
+
+    @Override
+    public void addMutableStmtToSeal(final MutableStatement mutableStatement) {
+        sourceContext.addMutableStmtToSeal(mutableStatement);
+    }
+
+    @Override
+    public void addRequiredModule(final ModuleIdentifier dependency) {
+        Preconditions.checkState(sourceContext.getInProgressPhase() == ModelProcessingPhase.SOURCE_PRE_LINKAGE,
+                "Add required module is allowed only in ModelProcessingPhase.SOURCE_PRE_LINKAGE phase");
+        if (requiredModules.isEmpty()) {
+            requiredModules = new HashSet<>();
+        }
+        requiredModules.add(dependency);
+    }
+
+    Collection<ModuleIdentifier> getRequiredModules() {
+        return ImmutableSet.copyOf(requiredModules);
+    }
+
+    @Override
+    public void setRootIdentifier(final ModuleIdentifier identifier) {
+        Preconditions.checkNotNull(identifier);
+        this.identifier = identifier;
+    }
+
+    ModuleIdentifier getRootIdentifier() {
+        return identifier;
+    }
 }