Populate SubmoduleEffectiveModule with import namespaces
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / AbstractEffectiveModule.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;
9
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import com.google.common.base.MoreObjects;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.collect.ImmutableMap.Builder;
17 import com.google.common.collect.ImmutableSet;
18 import java.net.URI;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.LinkedHashSet;
22 import java.util.List;
23 import java.util.Optional;
24 import java.util.Set;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.opendaylight.yangtools.concepts.SemVer;
27 import org.opendaylight.yangtools.openconfig.model.api.OpenConfigVersionEffectiveStatement;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.common.Revision;
30 import org.opendaylight.yangtools.yang.common.YangVersion;
31 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.Deviation;
34 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
35 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
36 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
37 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.Module;
39 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
40 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
41 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
42 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
43 import org.opendaylight.yangtools.yang.model.api.UsesNode;
44 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
45 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
46 import org.opendaylight.yangtools.yang.model.api.stmt.ContactEffectiveStatement;
47 import org.opendaylight.yangtools.yang.model.api.stmt.ImportEffectiveStatement;
48 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
49 import org.opendaylight.yangtools.yang.model.api.stmt.OrganizationEffectiveStatement;
50 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixEffectiveStatement;
51 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
52 import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
53 import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionEffectiveStatement;
54 import org.opendaylight.yangtools.yang.model.api.stmt.compat.NotificationNodeContainerCompat;
55 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
56 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
57 import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx;
58 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
59
60 @Beta
61 public abstract class AbstractEffectiveModule<D extends DeclaredStatement<String>> extends
62         AbstractSchemaEffectiveDocumentedNode<String, D> implements Module,
63         NotificationNodeContainerCompat<String, D> {
64     private final String name;
65     private final String prefix;
66     private final YangVersion yangVersion;
67     private final String organization;
68     private final String contact;
69     private final ImmutableSet<ModuleImport> imports;
70     private final ImmutableSet<FeatureDefinition> features;
71     private final @NonNull ImmutableSet<NotificationDefinition> notifications;
72     private final ImmutableSet<AugmentationSchemaNode> augmentations;
73     private final ImmutableSet<RpcDefinition> rpcs;
74     private final ImmutableSet<Deviation> deviations;
75     private final ImmutableList<ExtensionDefinition> extensionNodes;
76     private final ImmutableSet<IdentitySchemaNode> identities;
77     private final ImmutableSet<GroupingDefinition> groupings;
78     private final ImmutableSet<UsesNode> uses;
79     private final ImmutableSet<TypeDefinition<?>> typeDefinitions;
80     private final ImmutableSet<DataSchemaNode> publicChildNodes;
81     private final SemVer semanticVersion;
82
83     protected AbstractEffectiveModule(
84             final @NonNull StmtContext<String, D, ? extends EffectiveStatement<String, ?>> ctx,
85             final @NonNull String prefix) {
86         super(ctx);
87
88         this.name = argument();
89         this.prefix = requireNonNull(prefix);
90         this.yangVersion = findFirstEffectiveSubstatementArgument(YangVersionEffectiveStatement.class)
91                 .orElse(YangVersion.VERSION_1);
92         this.semanticVersion = findFirstEffectiveSubstatementArgument(OpenConfigVersionEffectiveStatement.class)
93                 .orElse(null);
94         this.organization = findFirstEffectiveSubstatementArgument(OrganizationEffectiveStatement.class)
95                 .orElse(null);
96         this.contact = findFirstEffectiveSubstatementArgument(ContactEffectiveStatement.class)
97                 .orElse(null);
98
99         final Set<AugmentationSchemaNode> augmentationsInit = new LinkedHashSet<>();
100         final Set<ModuleImport> importsInit = new LinkedHashSet<>();
101         final Set<NotificationDefinition> notificationsInit = new LinkedHashSet<>();
102         final Set<RpcDefinition> rpcsInit = new LinkedHashSet<>();
103         final Set<Deviation> deviationsInit = new LinkedHashSet<>();
104         final Set<IdentitySchemaNode> identitiesInit = new LinkedHashSet<>();
105         final Set<FeatureDefinition> featuresInit = new LinkedHashSet<>();
106         final List<ExtensionDefinition> extensionNodesInit = new ArrayList<>();
107
108         final Set<GroupingDefinition> mutableGroupings = new LinkedHashSet<>();
109         final Set<UsesNode> mutableUses = new LinkedHashSet<>();
110         final Set<TypeDefinition<?>> mutableTypeDefinitions = new LinkedHashSet<>();
111         final Set<DataSchemaNode> mutablePublicChildNodes = new LinkedHashSet<>();
112
113         for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
114             if (effectiveStatement instanceof AugmentationSchemaNode) {
115                 augmentationsInit.add((AugmentationSchemaNode) effectiveStatement);
116             }
117             if (effectiveStatement instanceof ModuleImport) {
118                 importsInit.add((ModuleImport) effectiveStatement);
119             }
120             if (effectiveStatement instanceof NotificationDefinition) {
121                 notificationsInit.add((NotificationDefinition) effectiveStatement);
122             }
123             if (effectiveStatement instanceof RpcDefinition) {
124                 rpcsInit.add((RpcDefinition) effectiveStatement);
125             }
126             if (effectiveStatement instanceof Deviation) {
127                 deviationsInit.add((Deviation) effectiveStatement);
128             }
129             if (effectiveStatement instanceof IdentitySchemaNode) {
130                 identitiesInit.add((IdentitySchemaNode) effectiveStatement);
131             }
132             if (effectiveStatement instanceof FeatureDefinition) {
133                 featuresInit.add((FeatureDefinition) effectiveStatement);
134             }
135             if (effectiveStatement instanceof ExtensionDefinition) {
136                 extensionNodesInit.add((ExtensionDefinition) effectiveStatement);
137             }
138             if (effectiveStatement instanceof DataSchemaNode) {
139                 mutablePublicChildNodes.add((DataSchemaNode) effectiveStatement);
140             }
141             if (effectiveStatement instanceof UsesNode && !mutableUses.add((UsesNode) effectiveStatement)) {
142                 throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
143             }
144             if (effectiveStatement instanceof TypedefEffectiveStatement) {
145                 final TypeDefinition<?> type = ((TypedefEffectiveStatement) effectiveStatement).getTypeDefinition();
146                 if (!mutableTypeDefinitions.add(type)) {
147                     throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
148                 }
149             }
150             if (effectiveStatement instanceof GroupingDefinition
151                     && !mutableGroupings.add((GroupingDefinition) effectiveStatement)) {
152                 throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, effectiveStatement);
153             }
154         }
155
156         this.augmentations = ImmutableSet.copyOf(augmentationsInit);
157         this.imports = ImmutableSet.copyOf(importsInit);
158         this.notifications = ImmutableSet.copyOf(notificationsInit);
159         this.rpcs = ImmutableSet.copyOf(rpcsInit);
160         this.deviations = ImmutableSet.copyOf(deviationsInit);
161         this.identities = ImmutableSet.copyOf(identitiesInit);
162         this.features = ImmutableSet.copyOf(featuresInit);
163         this.extensionNodes = ImmutableList.copyOf(extensionNodesInit);
164
165         this.groupings = ImmutableSet.copyOf(mutableGroupings);
166         this.publicChildNodes = ImmutableSet.copyOf(mutablePublicChildNodes);
167         this.typeDefinitions = ImmutableSet.copyOf(mutableTypeDefinitions);
168         this.uses = ImmutableSet.copyOf(mutableUses);
169     }
170
171     @Override
172     public URI getNamespace() {
173         return getQNameModule().getNamespace();
174     }
175
176     @Override
177     public String getName() {
178         return name;
179     }
180
181     @Override
182     public Optional<Revision> getRevision() {
183         return getQNameModule().getRevision();
184     }
185
186     @Override
187     public String getPrefix() {
188         return prefix;
189     }
190
191     @Override
192     public YangVersion getYangVersion() {
193         return yangVersion;
194     }
195
196     @Override
197     public Optional<String> getOrganization() {
198         return Optional.ofNullable(organization);
199     }
200
201     @Override
202     public Optional<String> getContact() {
203         return Optional.ofNullable(contact);
204     }
205
206     @Override
207     public Collection<? extends ModuleImport> getImports() {
208         return imports;
209     }
210
211     @Override
212     public Collection<? extends FeatureDefinition> getFeatures() {
213         return features;
214     }
215
216     @Override
217     public Collection<? extends NotificationDefinition> getNotifications() {
218         return notifications;
219     }
220
221     @Override
222     public Collection<? extends AugmentationSchemaNode> getAugmentations() {
223         return augmentations;
224     }
225
226     @Override
227     public Collection<? extends RpcDefinition> getRpcs() {
228         return rpcs;
229     }
230
231     @Override
232     public Collection<? extends Deviation> getDeviations() {
233         return deviations;
234     }
235
236     @Override
237     public Collection<? extends ExtensionDefinition> getExtensionSchemaNodes() {
238         return extensionNodes;
239     }
240
241     @Override
242     public Collection<? extends IdentitySchemaNode> getIdentities() {
243         return identities;
244     }
245
246     @Override
247     public final Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
248         return typeDefinitions;
249     }
250
251     @Override
252     public final Collection<? extends DataSchemaNode> getChildNodes() {
253         return publicChildNodes;
254     }
255
256     @Override
257     public final Collection<? extends GroupingDefinition> getGroupings() {
258         return groupings;
259     }
260
261     @Override
262     @SuppressWarnings("checkstyle:hiddenField")
263     public final Optional<DataSchemaNode> findDataChildByName(final QName name) {
264         return findDataSchemaNode(name);
265     }
266
267     @Override
268     public Collection<? extends UsesNode> getUses() {
269         return uses;
270     }
271
272     @Override
273     public Optional<SemVer> getSemanticVersion() {
274         return Optional.ofNullable(semanticVersion);
275     }
276
277     @Override
278     public String toString() {
279         return MoreObjects.toStringHelper(this).omitNullValues()
280                 .add("name", name)
281                 .add("namespace", getNamespace())
282                 .add("revision", getRevision().orElse(null))
283                 .add("prefix", prefix)
284                 .add("yangVersion", yangVersion)
285                 .toString();
286     }
287
288     protected static final @NonNull String findPrefix(final @NonNull StmtContext<?, ?, ?> ctx,
289             final String type, final String name) {
290         return SourceException.throwIfNull(
291             StmtContextUtils.firstAttributeOf(ctx.declaredSubstatements(), PrefixStatement.class),
292             ctx.getStatementSourceReference(), "Unable to resolve prefix for %s %s.", type, name);
293     }
294
295     // Alright. this is quite ugly
296     protected final void appendPrefixes(final StmtContext<?, ?, ?> ctx,
297             final Builder<String, ModuleEffectiveStatement> builder) {
298         streamEffectiveSubstatements(ImportEffectiveStatement.class)
299             .map(imp -> imp.findFirstEffectiveSubstatementArgument(PrefixEffectiveStatement.class).get())
300             .forEach(pfx -> {
301                 final StmtContext<?, ?, ?> importedCtx =
302                         verifyNotNull(ctx.getFromNamespace(ImportPrefixToModuleCtx.class, pfx),
303                             "Failed to resolve prefix %s", pfx);
304                 builder.put(pfx, (ModuleEffectiveStatement) importedCtx.buildEffective());
305             });
306     }
307 }