BUG-5222: Reuse substatements across phases
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / RootStatementContext.java
index 8108cd810e6339ac946c7a534cc47538997dc6c6..7417165d8691d9e0f2280a38c6f44f72f2e01844 100644 (file)
@@ -7,73 +7,83 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
+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 java.util.ArrayList;
 import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
+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.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.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.source.SourceException;
+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
+ * Root statement class for a YANG source. All statements defined in that YANG source are mapped underneath an instance
+ * of this class, hence recursive lookups from them cross this class.
  */
 public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> extends
         StatementContextBase<A, D, E> {
 
+    public static final YangVersion DEFAULT_VERSION = YangVersion.VERSION_1;
+
     private final SourceSpecificContext sourceContext;
     private final A argument;
 
-    RootStatementContext(ContextBuilder<A, D, E> builder, SourceSpecificContext sourceContext) throws SourceException {
-        super(builder);
-        this.sourceContext = sourceContext;
-        this.argument = builder.getDefinition().parseArgumentValue(this, builder.getRawArgument());
+    private YangVersion version;
+
+    /**
+     * References to RootStatementContext of submodules which are included in this source.
+     */
+    private Collection<RootStatementContext<?, ?, ?>> includedContexts = ImmutableList.of();
+
+    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 = def.parseArgumentValue(this, rawArgument);
+    }
+
+    RootStatementContext(final SourceSpecificContext sourceContext, final StatementDefinitionContext<A, D, E> def,
+        final StatementSourceReference ref, final String rawArgument, final YangVersion version) {
+        this(sourceContext, def, ref, rawArgument);
+        this.setRootVersion(version);
     }
 
-    RootStatementContext(RootStatementContext<A, D, E> original, QNameModule newQNameModule, TypeOfCopy typeOfCopy)
-            throws SourceException {
+    RootStatementContext(final RootStatementContext<A, D, E> original, final QNameModule newQNameModule,
+        final CopyType typeOfCopy) {
         super(original);
 
-        sourceContext = original.sourceContext;
+        sourceContext = Preconditions.checkNotNull(original.sourceContext);
         this.argument = original.argument;
 
-        copyDeclaredStmts(original, newQNameModule, typeOfCopy);
-
-        copyEffectiveStmts(original, newQNameModule, typeOfCopy);
+        final Collection<StatementContextBase<?, ?, ?>> declared = original.declaredSubstatements();
+        final Collection<StatementContextBase<?, ?, ?>> effective = original.effectiveSubstatements();
+        final Collection<StatementContextBase<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
 
-    }
-
-    /**
-     * copies declared statements from original to this' substatements
-     *
-     * @param typeOfCopy
-     *            determines whether copy is used by augmentation or uses
-     * @throws SourceException
-     */
-    private void copyDeclaredStmts(RootStatementContext<A, D, E> original, QNameModule newQNameModule,
-            TypeOfCopy typeOfCopy) throws SourceException {
-        Collection<? extends StmtContext<?, ?, ?>> originalDeclaredSubstatements = original.declaredSubstatements();
-        for (StmtContext<?, ?, ?> stmtContext : originalDeclaredSubstatements) {
-            this.addEffectiveSubstatement(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
+        for (final StatementContextBase<?, ?, ?> stmtContext : declared) {
+            if (StmtContextUtils.areFeaturesSupported(stmtContext)) {
+                buffer.add(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
+            }
         }
-    }
-
-    /**
-     * copies effective statements from original to this' substatements
-     *
-     * @param typeOfCopy
-     *            determines whether copy is used by augmentation or uses
-     * @throws SourceException
-     */
-    private void copyEffectiveStmts(RootStatementContext<A, D, E> original, QNameModule newQNameModule,
-            TypeOfCopy typeOfCopy) throws SourceException {
-        Collection<? extends StmtContext<?, ?, ?>> originalEffectiveSubstatements = original.effectiveSubstatements();
-        for (StmtContext<?, ?, ?> stmtContext : originalEffectiveSubstatements) {
-            this.addEffectiveSubstatement(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
+        for (final StmtContext<?, ?, ?> stmtContext : effective) {
+            buffer.add(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
         }
+
+        addEffectiveSubstatements(buffer);
     }
 
     /**
@@ -92,17 +102,19 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
         return sourceContext;
     }
 
-    /**
-     * @return registry of source context
-     */
     @Override
     public Registry getBehaviourRegistry() {
         return sourceContext;
     }
 
+    @Override
+    public StorageNodeType getStorageNodeType() {
+        return StorageNodeType.ROOT_STATEMENT_LOCAL;
+    }
     /**
      * @return this as its own root
      */
+    @Nonnull
     @Override
     public RootStatementContext<?, ?, ?> getRoot() {
         return this;
@@ -118,64 +130,116 @@ public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends E
     }
 
     /**
-     * @return copy of this considering {@link TypeOfCopy} (augment, uses)
+     * @return copy of this considering {@link CopyType} (augment, uses)
      *
-     * @throws SourceException
+     * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException instance of SourceException
      */
     @Override
-    public StatementContextBase<?, ?, ?> createCopy(StatementContextBase<?, ?, ?> newParent, TypeOfCopy typeOfCopy)
-            throws SourceException {
+    public StatementContextBase<?, ?, ?> createCopy(final StatementContextBase<?, ?, ?> newParent,
+            final CopyType typeOfCopy) {
         return createCopy(null, newParent, typeOfCopy);
     }
 
     /**
-     * @return copy of this considering {@link TypeOfCopy} (augment, uses)
+     * @return copy of this considering {@link CopyType} (augment, uses)
      *
-     * @throws SourceException
+     * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException instance of SourceException
      */
     @Override
-    public StatementContextBase<A, D, E> createCopy(QNameModule newQNameModule,
-            StatementContextBase<?, ?, ?> newParent, TypeOfCopy typeOfCopy) throws SourceException {
-        RootStatementContext<A, D, E> copy = new RootStatementContext<>(this, newQNameModule, typeOfCopy);
+    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.addAllToCopyHistory(this.getCopyHistory());
-        copy.addToCopyHistory(typeOfCopy);
+        copy.appendCopyHistory(typeOfCopy, this.getCopyHistory());
 
-        if(this.getOriginalCtx() != null) {
+        if (this.getOriginalCtx() != null) {
             copy.setOriginalCtx(this.getOriginalCtx());
         } else {
             copy.setOriginalCtx(this);
         }
-
+        definition().onStatementAdded(copy);
         return copy;
     }
 
-    /**
-     * @return this' argument as it is the only from root (this)
-     */
+    @Nonnull
     @Override
-    public List<Object> getArgumentsFromRoot() {
-        List<Object> argumentList = new LinkedList<>();
-        argumentList.add(argument);
-        return argumentList;
+    public Optional<SchemaPath> getSchemaPath() {
+        return Optional.of(SchemaPath.ROOT);
     }
 
     /**
-     * @return this as it is the only\context from root (this)
+     * @return true
      */
     @Override
-    public List<StmtContext<?, ?, ?>> getStmtContextsFromRoot() {
-        List<StmtContext<?, ?, ?>> stmtContextsList = new LinkedList<>();
-        stmtContextsList.add(this);
-        return stmtContextsList;
+    public boolean isRootContext() {
+        return true;
     }
 
-    /**
-     * @return true
-     */
     @Override
-    public boolean isRootContext() {
+    public boolean isConfiguration() {
         return true;
     }
 
+    @Override
+    public boolean isEnabledSemanticVersioning() {
+        return sourceContext.isEnabledSemanticVersioning();
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(final Class<N> type, final K key,
+            final V value) {
+        if (IncludedModuleContext.class.isAssignableFrom(type)) {
+            if (includedContexts.isEmpty()) {
+                includedContexts = new ArrayList<>(1);
+            }
+            Verify.verify(value instanceof RootStatementContext);
+            includedContexts.add((RootStatementContext<?, ?, ?>) value);
+        }
+        super.addToLocalStorage(type, key, value);
+    }
+
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
+        final V potentialLocal = super.getFromLocalStorage(type, key);
+        if (potentialLocal != null) {
+            return potentialLocal;
+        }
+        for (final NamespaceStorageNode includedSource : includedContexts) {
+            final V potential = includedSource.getFromLocalStorage(type, key);
+            if (potential != null) {
+                return potential;
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    @Override
+    public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
+        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);
+            if (potential != null) {
+                return potential;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public YangVersion getRootVersion() {
+        return version == null ? DEFAULT_VERSION : version;
+    }
+
+    @Override
+    public void setRootVersion(final YangVersion version) {
+        Preconditions.checkArgument(sourceContext.getSupportedVersions().contains(version),
+                "Unsupported yang version %s in %s", version, getStatementSourceReference());
+        Preconditions.checkState(this.version == null, "Version of root %s has been already set to %s", argument,
+                this.version);
+        this.version = Preconditions.checkNotNull(version);
+    }
 }