Fire AbstractPrerequisite listeners as soon as they resolve
[yangtools.git] / yang / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / CrossSourceStatementReactor.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.stmt.reactor;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.SetMultimap;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.EnumMap;
18 import java.util.Map;
19 import java.util.Set;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.QNameModule;
23 import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
27 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
28 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
29
30 public final class CrossSourceStatementReactor {
31     private final ImmutableMap<ModelProcessingPhase, StatementSupportBundle> supportedTerminology;
32     private final ImmutableMap<ValidationBundleType, Collection<?>> supportedValidation;
33
34     CrossSourceStatementReactor(final Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology,
35             final Map<ValidationBundleType, Collection<?>> supportedValidation) {
36         this.supportedTerminology = ImmutableMap.copyOf(supportedTerminology);
37         this.supportedValidation = ImmutableMap.copyOf(supportedValidation);
38     }
39
40     /**
41      * Create a new {@link Builder}.
42      *
43      * @return A new builder.
44      */
45     public static @NonNull Builder builder() {
46         return new Builder();
47     }
48
49     /**
50      * Start a new reactor build using the default statement parser mode with all features and deviations enabled.
51      *
52      * @return A new {@link BuildAction}.
53      */
54     public @NonNull BuildAction newBuild() {
55         return newBuild(StatementParserMode.DEFAULT_MODE);
56     }
57
58     /**
59      * Start a new reactor build using the specified statement parser mode and enabling all features and deviations.
60      *
61      * @param statementParserMode Parser mode to use
62      * @return A new {@link BuildAction}.
63      * @throws NullPointerException if statementParserMode is null
64      */
65     public @NonNull BuildAction newBuild(final StatementParserMode statementParserMode) {
66         return new BuildAction(supportedTerminology, supportedValidation, requireNonNull(statementParserMode));
67     }
68
69     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor> {
70         private final Map<ValidationBundleType, Collection<?>> validationBundles =
71                 new EnumMap<>(ValidationBundleType.class);
72         private final Map<ModelProcessingPhase, StatementSupportBundle> bundles =
73                 new EnumMap<>(ModelProcessingPhase.class);
74
75         public @NonNull Builder setBundle(final ModelProcessingPhase phase, final StatementSupportBundle bundle) {
76             bundles.put(phase, bundle);
77             return this;
78         }
79
80         public @NonNull Builder setValidationBundle(final ValidationBundleType type,
81                 final Collection<?> validationBundle) {
82             validationBundles.put(type, validationBundle);
83             return this;
84         }
85
86         @Override
87         public CrossSourceStatementReactor build() {
88             return new CrossSourceStatementReactor(bundles, validationBundles);
89         }
90     }
91
92     public static class BuildAction {
93         private final BuildGlobalContext context;
94         private boolean supportedFeaturesSet = false;
95         private boolean modulesDeviatedByModulesSet = false;
96
97         BuildAction(final ImmutableMap<ModelProcessingPhase, StatementSupportBundle> supportedTerminology,
98                 final ImmutableMap<ValidationBundleType, Collection<?>> supportedValidation,
99                 final StatementParserMode statementParserMode) {
100             this.context = new BuildGlobalContext(supportedTerminology, supportedValidation, statementParserMode);
101         }
102
103         /**
104          * Add main source. All main sources are present in resulting SchemaContext.
105          *
106          * @param source which should be added into main sources
107          * @return This build action, for fluent use.
108          * @throws NullPointerException if @{code source} is null
109          */
110         public @NonNull BuildAction addSource(final StatementStreamSource source) {
111             context.addSource(source);
112             return this;
113         }
114
115         /**
116          * Add main sources. All main sources are present in resulting SchemaContext.
117          *
118          * @param sources which should be added into main sources
119          * @return This build action, for fluent use.
120          * @throws NullPointerException if @{code sources} is null or contains a null element
121          */
122         public @NonNull BuildAction addSources(final StatementStreamSource... sources) {
123             addSources(Arrays.asList(sources));
124             return this;
125         }
126
127         /**
128          * Add main sources. All main sources are present in resulting SchemaContext.
129          *
130          * @param sources which should be added into main sources
131          * @return This build action, for fluent use.
132          * @throws NullPointerException if @{code sources} is null or contains a null element
133          */
134         public @NonNull BuildAction addSources(final @NonNull Collection<? extends StatementStreamSource> sources) {
135             for (final StatementStreamSource source : sources) {
136                 context.addSource(requireNonNull(source));
137             }
138             return this;
139         }
140
141         /**
142          * Add a library source. Only library sources required by main sources are present in resulting SchemaContext.
143          * Any other library sources are ignored and this also applies to error reporting.
144          *
145          * <p>
146          * Library sources are not supported in semantic version mode currently.
147          *
148          * @param libSource source which should be added into library sources
149          * @return This build action, for fluent use.
150          * @throws NullPointerException if @{code libSource} is null
151          */
152         public @NonNull BuildAction addLibSource(final StatementStreamSource libSource) {
153             context.addLibSource(libSource);
154             return this;
155         }
156
157         /**
158          * Add library sources. Only library sources required by main sources are present in resulting SchemaContext.
159          * Any other library sources are ignored and this also applies to error reporting.
160          *
161          * <p>
162          * Library sources are not supported in semantic version mode currently.
163          *
164          * @param libSources sources which should be added into library sources
165          * @return This build action, for fluent use.
166          * @throws NullPointerException if @{code libSources} is null or contains a null element
167          */
168         public @NonNull BuildAction addLibSources(final StatementStreamSource... libSources) {
169             addLibSources(Arrays.asList(libSources));
170             return this;
171         }
172
173         /**
174          * Add library sources. Only library sources required by main sources are present in resulting SchemaContext.
175          * Any other library sources are ignored and this also applies to error reporting.
176          *
177          * <p>
178          * Library sources are not supported in semantic version mode currently.
179          *
180          * @param libSources sources which should be added into library sources
181          * @return This build action, for fluent use.
182          * @throws NullPointerException if @{code libSources} is null or contains a null element
183          */
184         public @NonNull BuildAction addLibSources(final Collection<StatementStreamSource> libSources) {
185             for (final StatementStreamSource libSource : libSources) {
186                 context.addLibSource(libSource);
187             }
188             return this;
189         }
190
191         /**
192          * Set supported features based on which all if-feature statements in the
193          * parsed YANG modules will be resolved.
194          *
195          * @param supportedFeatures
196          *            Set of supported features in the final SchemaContext.
197          *            If the set is empty, no features encountered will be supported.
198          * @return This build action, for fluent use.
199          */
200         public @NonNull BuildAction setSupportedFeatures(final @NonNull Set<QName> supportedFeatures) {
201             checkState(!supportedFeaturesSet, "Supported features should be set only once.");
202             context.setSupportedFeatures(requireNonNull(supportedFeatures));
203             supportedFeaturesSet = true;
204             return this;
205         }
206
207         /**
208          * Set YANG modules which can be deviated by specified modules during the parsing process.
209          * Map key (QNameModule) denotes a module which can be deviated by the modules in the Map value.
210          *
211          * @param modulesDeviatedByModules
212          *            Map of YANG modules (Map key) which can be deviated by specified modules (Map value) in the final
213          *            SchemaContext. If the map is empty, no deviations encountered will be supported.
214          * @return This build action, for fluent use.
215          */
216         public @NonNull BuildAction setModulesWithSupportedDeviations(
217                 final @NonNull SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
218             checkState(!modulesDeviatedByModulesSet, "Modules with supported deviations should be set only once.");
219             context.setModulesDeviatedByModules(requireNonNull(modulesDeviatedByModules));
220             modulesDeviatedByModulesSet = true;
221             return this;
222         }
223
224         /**
225          * Build the effective model context.
226          */
227         public ReactorDeclaredModel build() throws ReactorException {
228             return context.build();
229         }
230
231         public EffectiveSchemaContext buildEffective() throws ReactorException {
232             return context.buildEffective();
233         }
234     }
235 }