Refactor AbstractEffectiveModule
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / submodule / SubmoduleEffectiveStatementImpl.java
index a53155396152912e26850fafc4013adfc400bae4..90edc788679f0b4922332fcf3193b458723d0b6f 100644 (file)
@@ -7,27 +7,45 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.submodule;
 
+import static com.google.common.base.Preconditions.checkState;
 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
 
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import java.util.HashSet;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveModule;
+import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement;
 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.IncludedSubmoduleNameToModuleCtx;
 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 
 final class SubmoduleEffectiveStatementImpl extends AbstractEffectiveModule<SubmoduleStatement>
-        implements SubmoduleEffectiveStatement {
+        implements SubmoduleEffectiveStatement, MutableStatement {
 
     private final QNameModule qnameModule;
 
+    private Set<StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>> submoduleContexts;
+    private ImmutableSet<Module> submodules;
+    private boolean sealed;
+
     SubmoduleEffectiveStatementImpl(final StmtContext<String, SubmoduleStatement, SubmoduleEffectiveStatement> ctx) {
-        super(ctx);
+        super(ctx, findSubmodulePrefix(ctx));
 
         final String belongsToModuleName = firstAttributeOf(ctx.declaredSubstatements(), BelongsToStatement.class);
         final QNameModule belongsToModuleQName = ctx.getFromNamespace(ModuleNameToModuleQName.class,
@@ -36,6 +54,33 @@ final class SubmoduleEffectiveStatementImpl extends AbstractEffectiveModule<Subm
         final Optional<Revision> submoduleRevision = findFirstEffectiveSubstatementArgument(
             RevisionEffectiveStatement.class);
         this.qnameModule = QNameModule.create(belongsToModuleQName.getNamespace(), submoduleRevision).intern();
+
+        /*
+         * Because of possible circular chains of includes between submodules we can
+         * collect only submodule contexts here and then build them during
+         * sealing of this statement.
+         */
+        final Map<String, StmtContext<?, ?, ?>> includedSubmodulesMap = ctx.getAllFromCurrentStmtCtxNamespace(
+            IncludedSubmoduleNameToModuleCtx.class);
+        if (includedSubmodulesMap != null) {
+            final Set<StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>>
+                submoduleContextsInit = new HashSet<>();
+            for (final StmtContext<?, ?, ?> submoduleCtx : includedSubmodulesMap.values()) {
+                submoduleContextsInit.add(
+                    (StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>)submoduleCtx);
+            }
+            submoduleContexts = ImmutableSet.copyOf(submoduleContextsInit);
+        } else {
+            submoduleContexts = ImmutableSet.of();
+        }
+
+        if (!submoduleContexts.isEmpty()) {
+            ((Mutable<?, ?, ?>) ctx).addMutableStmtToSeal(this);
+            sealed = false;
+        } else {
+            submodules = ImmutableSet.of();
+            sealed = true;
+        }
     }
 
     @Override
@@ -43,6 +88,13 @@ final class SubmoduleEffectiveStatementImpl extends AbstractEffectiveModule<Subm
         return qnameModule;
     }
 
+    @Override
+    public Set<Module> getSubmodules() {
+        checkState(sealed, "Attempt to get base submodules from unsealed submodule effective statement %s",
+            qnameModule);
+        return submodules;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(getName(), getYangVersion(), qnameModule);
@@ -60,4 +112,22 @@ final class SubmoduleEffectiveStatementImpl extends AbstractEffectiveModule<Subm
         return Objects.equals(getName(), other.getName()) && qnameModule.equals(other.qnameModule)
                 && Objects.equals(getYangVersion(), other.getYangVersion());
     }
+
+    @Override
+    public void seal() {
+        if (!sealed) {
+            submodules = ImmutableSet.copyOf(Iterables.transform(submoduleContexts,
+                ctx -> (Module) ctx.buildEffective()));
+            submoduleContexts = ImmutableSet.of();
+            sealed = true;
+        }
+    }
+
+    private static @NonNull String findSubmodulePrefix(final StmtContext<String, ?, ?> ctx) {
+        final String name = ctx.getStatementArgument();
+        final StmtContext<?, ?, ?> belongsTo = SourceException.throwIfNull(
+                StmtContextUtils.findFirstDeclaredSubstatement(ctx, BelongsToStatement.class),
+                ctx.getStatementSourceReference(), "Unable to find belongs-to statement in submodule %s.", name);
+        return findPrefix(belongsTo, "submodule", name);
+    }
 }