Refactor AbstractEffectiveModule
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / submodule / SubmoduleEffectiveStatementImpl.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.submodule;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
12
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.collect.Iterables;
15 import java.util.HashSet;
16 import java.util.Map;
17 import java.util.Objects;
18 import java.util.Optional;
19 import java.util.Set;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.common.QNameModule;
22 import org.opendaylight.yangtools.yang.common.Revision;
23 import org.opendaylight.yangtools.yang.model.api.Module;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.BelongsToStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
29 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractEffectiveModule;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
34 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedSubmoduleNameToModuleCtx;
35 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
36 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
37
38 final class SubmoduleEffectiveStatementImpl extends AbstractEffectiveModule<SubmoduleStatement>
39         implements SubmoduleEffectiveStatement, MutableStatement {
40
41     private final QNameModule qnameModule;
42
43     private Set<StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>> submoduleContexts;
44     private ImmutableSet<Module> submodules;
45     private boolean sealed;
46
47     SubmoduleEffectiveStatementImpl(final StmtContext<String, SubmoduleStatement, SubmoduleEffectiveStatement> ctx) {
48         super(ctx, findSubmodulePrefix(ctx));
49
50         final String belongsToModuleName = firstAttributeOf(ctx.declaredSubstatements(), BelongsToStatement.class);
51         final QNameModule belongsToModuleQName = ctx.getFromNamespace(ModuleNameToModuleQName.class,
52                 belongsToModuleName);
53
54         final Optional<Revision> submoduleRevision = findFirstEffectiveSubstatementArgument(
55             RevisionEffectiveStatement.class);
56         this.qnameModule = QNameModule.create(belongsToModuleQName.getNamespace(), submoduleRevision).intern();
57
58         /*
59          * Because of possible circular chains of includes between submodules we can
60          * collect only submodule contexts here and then build them during
61          * sealing of this statement.
62          */
63         final Map<String, StmtContext<?, ?, ?>> includedSubmodulesMap = ctx.getAllFromCurrentStmtCtxNamespace(
64             IncludedSubmoduleNameToModuleCtx.class);
65         if (includedSubmodulesMap != null) {
66             final Set<StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>>
67                 submoduleContextsInit = new HashSet<>();
68             for (final StmtContext<?, ?, ?> submoduleCtx : includedSubmodulesMap.values()) {
69                 submoduleContextsInit.add(
70                     (StmtContext<?, SubmoduleStatement, EffectiveStatement<String, SubmoduleStatement>>)submoduleCtx);
71             }
72             submoduleContexts = ImmutableSet.copyOf(submoduleContextsInit);
73         } else {
74             submoduleContexts = ImmutableSet.of();
75         }
76
77         if (!submoduleContexts.isEmpty()) {
78             ((Mutable<?, ?, ?>) ctx).addMutableStmtToSeal(this);
79             sealed = false;
80         } else {
81             submodules = ImmutableSet.of();
82             sealed = true;
83         }
84     }
85
86     @Override
87     public QNameModule getQNameModule() {
88         return qnameModule;
89     }
90
91     @Override
92     public Set<Module> getSubmodules() {
93         checkState(sealed, "Attempt to get base submodules from unsealed submodule effective statement %s",
94             qnameModule);
95         return submodules;
96     }
97
98     @Override
99     public int hashCode() {
100         return Objects.hash(getName(), getYangVersion(), qnameModule);
101     }
102
103     @Override
104     public boolean equals(final Object obj) {
105         if (this == obj) {
106             return true;
107         }
108         if (!(obj instanceof SubmoduleEffectiveStatementImpl)) {
109             return false;
110         }
111         final SubmoduleEffectiveStatementImpl other = (SubmoduleEffectiveStatementImpl) obj;
112         return Objects.equals(getName(), other.getName()) && qnameModule.equals(other.qnameModule)
113                 && Objects.equals(getYangVersion(), other.getYangVersion());
114     }
115
116     @Override
117     public void seal() {
118         if (!sealed) {
119             submodules = ImmutableSet.copyOf(Iterables.transform(submoduleContexts,
120                 ctx -> (Module) ctx.buildEffective()));
121             submoduleContexts = ImmutableSet.of();
122             sealed = true;
123         }
124     }
125
126     private static @NonNull String findSubmodulePrefix(final StmtContext<String, ?, ?> ctx) {
127         final String name = ctx.getStatementArgument();
128         final StmtContext<?, ?, ?> belongsTo = SourceException.throwIfNull(
129                 StmtContextUtils.findFirstDeclaredSubstatement(ctx, BelongsToStatement.class),
130                 ctx.getStatementSourceReference(), "Unable to find belongs-to statement in submodule %s.", name);
131         return findPrefix(belongsTo, "submodule", name);
132     }
133 }