122fad30133d8ff3e80629d3800661a0b882aeda
[yangtools.git] / yang / yang-parser-impl / 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 com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableMap;
12 import com.google.common.io.ByteSource;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.EnumMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Optional;
21 import java.util.Set;
22 import javax.annotation.Nonnull;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.common.QNameModule;
25 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
26 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
27 import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
28 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
29 import org.opendaylight.yangtools.yang.parser.rfc6020.repo.YangStatementStreamSource;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
33 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
34 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
35 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public final class CrossSourceStatementReactor {
40     private static final Logger LOG = LoggerFactory.getLogger(CrossSourceStatementReactor.class);
41
42     private final Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology;
43     private final Map<ValidationBundleType, Collection<?>> supportedValidation;
44
45     CrossSourceStatementReactor(final Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology,
46             final Map<ValidationBundleType, Collection<?>> supportedValidation) {
47         this.supportedTerminology = ImmutableMap.copyOf(supportedTerminology);
48         this.supportedValidation = ImmutableMap.copyOf(supportedValidation);
49     }
50
51     /**
52      * Create a new {@link Builder}.
53      *
54      * @return A new builder.
55      */
56     public static Builder builder() {
57         return new Builder();
58     }
59
60     /**
61      * Start a new reactor build using the default statement parser mode with all features and deviations enabled.
62      *
63      * @return A new {@link BuildAction}.
64      */
65     public BuildAction newBuild() {
66         return newBuild(StatementParserMode.DEFAULT_MODE);
67     }
68
69     /**
70      * Start a new reactor build using the default statement parser mode and enabling only the specified features
71      * and all deviations.
72      *
73      * @param supportedFeatures The set of supported features in the final SchemaContext
74      * @return A new {@link BuildAction}.
75      *
76      * @deprecated Use {@link #newBuild()} and then call setSupportedFeatures() on the created BuildAction instead.
77      */
78     @Deprecated
79     public BuildAction newBuild(final Set<QName> supportedFeatures) {
80         final BuildAction buildAction = newBuild();
81         if (supportedFeatures != null) {
82             buildAction.setSupportedFeatures(supportedFeatures);
83         }
84
85         return buildAction;
86     }
87
88     /**
89      * Start a new reactor build using the default statement parser mode and enabling only the specified features
90      * and all deviations.
91      *
92      * @param supportedFeatures The set of supported features in the final SchemaContext, if present.
93      * @return A new {@link BuildAction}.
94      *
95      * @deprecated Use {@link #newBuild()} and then call setSupportedFeatures() on the created BuildAction instead.
96      */
97     @Deprecated
98     public BuildAction newBuild(final Optional<Set<QName>> supportedFeatures) {
99         final BuildAction buildAction = newBuild();
100         if (supportedFeatures.isPresent()) {
101             buildAction.setSupportedFeatures(supportedFeatures.get());
102         }
103
104         return buildAction;
105     }
106
107     /**
108      * Start a new reactor build using the specified statement parser mode and enabling all features and deviations.
109      *
110      * @param statementParserMode Parser mode to use
111      * @return A new {@link BuildAction}.
112      * @throws NullPointerException if statementParserMode is null
113      */
114     public BuildAction newBuild(final StatementParserMode statementParserMode) {
115         return new BuildAction(statementParserMode);
116     }
117
118     /**
119      * Start a new reactor build using the specified statement parser mode and enabling only the specified features
120      * and all deviations.
121      *
122      * @param statementParserMode Parser mode to use
123      * @param supportedFeatures The set of supported features in the final SchemaContext
124      * @return A new {@link BuildAction}.
125      * @throws NullPointerException if statementParserMode is null
126      *
127      * @deprecated Use {@link #newBuild(StatementParserMode)} and then call setSupportedFeatures()
128      * on the created BuildAction instead.
129      */
130     @Deprecated
131     public BuildAction newBuild(final StatementParserMode statementParserMode,
132             final Set<QName> supportedFeatures) {
133         final BuildAction buildAction = new BuildAction(statementParserMode);
134         if (supportedFeatures != null) {
135             buildAction.setSupportedFeatures(supportedFeatures);
136         }
137
138         return buildAction;
139     }
140
141     /**
142      * Start a new reactor build using the specified statement parser mode and enabling only the specified features
143      * and all deviations.
144      *
145      * @param statementParserMode Parser mode to use
146      * @param supportedFeatures The set of supported features in the final SchemaContext, or absent if all features
147      *                          encountered should be supported.
148      * @return A new {@link BuildAction}.
149      * @throws NullPointerException if statementParserMode is null
150      *
151      * @deprecated Use {@link #newBuild(StatementParserMode)} and then call setSupportedFeatures()
152      * on the created BuildAction instead.
153      */
154     @Deprecated
155     public BuildAction newBuild(final StatementParserMode statementParserMode,
156             final Optional<Set<QName>> supportedFeatures) {
157         final BuildAction buildAction = new BuildAction(statementParserMode);
158         if (supportedFeatures.isPresent()) {
159             buildAction.setSupportedFeatures(supportedFeatures.get());
160         }
161
162         return buildAction;
163     }
164
165     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor> {
166         private final Map<ValidationBundleType, Collection<?>> validationBundles =
167                 new EnumMap<>(ValidationBundleType.class);
168         private final Map<ModelProcessingPhase, StatementSupportBundle> bundles =
169                 new EnumMap<>(ModelProcessingPhase.class);
170
171         public Builder setBundle(final ModelProcessingPhase phase, final StatementSupportBundle bundle) {
172             bundles.put(phase, bundle);
173             return this;
174         }
175
176         public Builder setValidationBundle(final ValidationBundleType type, final Collection<?> validationBundle) {
177             validationBundles.put(type, validationBundle);
178             return this;
179         }
180
181         @Override
182         public CrossSourceStatementReactor build() {
183             return new CrossSourceStatementReactor(bundles, validationBundles);
184         }
185     }
186
187     public class BuildAction {
188         private final BuildGlobalContext context;
189         private boolean supportedFeaturesSet = false;
190         private boolean modulesDeviatedByModulesSet = false;
191
192         BuildAction(@Nonnull final StatementParserMode statementParserMode) {
193             this.context = new BuildGlobalContext(supportedTerminology,supportedValidation,
194                     Preconditions.checkNotNull(statementParserMode));
195         }
196
197         /**
198          * Add main source. All main sources are present in resulting
199          * SchemaContext.
200          *
201          * @param source
202          *            which should be added into main sources
203          */
204         public void addSource(final StatementStreamSource source) {
205             context.addSource(source);
206         }
207
208         /**
209          * Add main sources. All main sources are present in resulting
210          * SchemaContext.
211          *
212          * @param sources
213          *            which should be added into main sources
214          */
215         public void addSources(final StatementStreamSource... sources) {
216             addSources(Arrays.asList(sources));
217         }
218
219         public void addSources(final Collection<? extends StatementStreamSource> sources) {
220             for (final StatementStreamSource source : sources) {
221                 context.addSource(source);
222             }
223         }
224
225         /**
226          * Add library sources. Only library sources required by main sources
227          * are present in resulting SchemaContext. Any other library sources are
228          * ignored and this also applies to error reporting.
229          *
230          * Library sources are not supported in semantic version mode currently.
231          *
232          * @param libSources
233          *            yang sources which should be added into library sources
234          */
235         public void addLibSources(final StatementStreamSource... libSources) {
236             addLibSources(Arrays.asList(libSources));
237         }
238
239         public void addLibSources(final Collection<StatementStreamSource> libSources) {
240             for (final StatementStreamSource libSource : libSources) {
241                 context.addLibSource(libSource);
242             }
243         }
244
245         /**
246          * Set supported features based on which all if-feature statements in the
247          * parsed YANG modules will be resolved.
248          *
249          * @param supportedFeatures
250          *            Set of supported features in the final SchemaContext.
251          *            If the set is empty, no features encountered will be supported.
252          */
253         public void setSupportedFeatures(@Nonnull final Set<QName> supportedFeatures) {
254             Preconditions.checkState(!supportedFeaturesSet, "Supported features should be set only once.");
255             context.setSupportedFeatures(Preconditions.checkNotNull(supportedFeatures));
256             supportedFeaturesSet = true;
257         }
258
259         /**
260          * Set YANG modules which can be deviated by specified modules during the parsing process.
261          * Map key (QNameModule) denotes a module which can be deviated by the modules in the Map value.
262          *
263          * @param modulesDeviatedByModules
264          *            Map of YANG modules (Map key) which can be deviated by specified modules (Map value) in the final
265          *            SchemaContext. If the map is empty, no deviations encountered will be supported.
266          */
267         public void setModulesWithSupportedDeviations(
268                 @Nonnull final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules) {
269             Preconditions.checkState(!modulesDeviatedByModulesSet,
270                     "Modules with supported deviations should be set only once.");
271             context.setModulesDeviatedByModules(Preconditions.checkNotNull(modulesDeviatedByModules));
272             modulesDeviatedByModulesSet = true;
273         }
274
275         /**
276          * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException
277          * @throws ReactorException
278          */
279         public EffectiveModelContext build() throws ReactorException {
280             return context.build();
281         }
282
283         public EffectiveSchemaContext buildEffective() throws ReactorException {
284             return context.buildEffective();
285         }
286
287         /**
288          * @deprecated Use {@link #addSources(Collection)} and {@link #buildEffective()} instead.
289          */
290         @Deprecated
291         public SchemaContext buildEffective(final Collection<ByteSource> yangByteSources) throws ReactorException,
292                 IOException {
293             for (final ByteSource source : yangByteSources) {
294                 if (source instanceof YangTextSchemaSource) {
295                     try {
296                         addSource(YangStatementStreamSource.create((YangTextSchemaSource) source));
297                     } catch (YangSyntaxErrorException e) {
298                         throw new IOException("Source " + source + " failed to parse", e);
299                     }
300                 } else {
301                     addSource(new YangStatementSourceImpl(source.openStream()));
302                 }
303             }
304
305             return buildEffective();
306         }
307
308         /**
309          * @deprecated Use {@link #addSources(Collection)} and {@link #buildEffective()} instead.
310          */
311         @Deprecated
312         public SchemaContext buildEffective(final List<InputStream> yangInputStreams) throws ReactorException {
313             for (final InputStream yangInputStream : yangInputStreams) {
314                 addSource(new YangStatementSourceImpl(yangInputStream));
315             }
316
317             return buildEffective();
318         }
319     }
320 }