dca20a74aa3161e2dc4de49d928bd368e0fbeada
[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
107          *            which should be added into main sources
108          * @return This build action, for fluent use.
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
119          *            which should be added into main sources
120          * @return This build action, for fluent use.
121          */
122         public @NonNull BuildAction addSources(final StatementStreamSource... sources) {
123             addSources(Arrays.asList(sources));
124             return this;
125         }
126
127         public @NonNull BuildAction addSources(final @NonNull Collection<? extends StatementStreamSource> sources) {
128             for (final StatementStreamSource source : sources) {
129                 context.addSource(requireNonNull(source));
130             }
131             return this;
132         }
133
134         /**
135          * Add library sources. Only library sources required by main sources are present in resulting SchemaContext.
136          * Any other library sources are ignored and this also applies to error reporting.
137          *
138          * <p>
139          * Library sources are not supported in semantic version mode currently.
140          *
141          * @param libSources yang sources which should be added into library sources
142          * @return This build action, for fluent use.
143          */
144         public @NonNull BuildAction addLibSources(final StatementStreamSource... libSources) {
145             addLibSources(Arrays.asList(libSources));
146             return this;
147         }
148
149         public @NonNull BuildAction addLibSources(final Collection<StatementStreamSource> libSources) {
150             for (final StatementStreamSource libSource : libSources) {
151                 context.addLibSource(libSource);
152             }
153             return this;
154         }
155
156         /**
157          * Set supported features based on which all if-feature statements in the
158          * parsed YANG modules will be resolved.
159          *
160          * @param supportedFeatures
161          *            Set of supported features in the final SchemaContext.
162          *            If the set is empty, no features encountered will be supported.
163          * @return This build action, for fluent use.
164          */
165         public @NonNull BuildAction setSupportedFeatures(final @NonNull Set<QName> supportedFeatures) {
166             checkState(!supportedFeaturesSet, "Supported features should be set only once.");
167             context.setSupportedFeatures(requireNonNull(supportedFeatures));
168             supportedFeaturesSet = true;
169             return this;
170         }
171
172         /**
173          * Set YANG modules which can be deviated by specified modules during the parsing process.
174          * Map key (QNameModule) denotes a module which can be deviated by the modules in the Map value.
175          *
176          * @param modulesDeviatedByModules
177          *            Map of YANG modules (Map key) which can be deviated by specified modules (Map value) in the final
178          *            SchemaContext. If the map is empty, no deviations encountered will be supported.
179          * @return This build action, for fluent use.
180          */
181         public @NonNull BuildAction setModulesWithSupportedDeviations(
182                 final @NonNull SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
183             checkState(!modulesDeviatedByModulesSet, "Modules with supported deviations should be set only once.");
184             context.setModulesDeviatedByModules(requireNonNull(modulesDeviatedByModules));
185             modulesDeviatedByModulesSet = true;
186             return this;
187         }
188
189         /**
190          * Build the effective model context.
191          */
192         public ReactorDeclaredModel build() throws ReactorException {
193             return context.build();
194         }
195
196         public EffectiveSchemaContext buildEffective() throws ReactorException {
197             return context.buildEffective();
198         }
199     }
200 }