Bump odlparent dependency to 2.0.0
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / CrossSourceStatementReactor.java
index 8ce59f70e5667a1f5f1ebea767d1307a353c5b06..87dfcecb8188f22c06b69e086469c53af5a173ea 100644 (file)
  */
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.io.ByteSource;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Predicate;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.repo.api.IfFeaturePredicates;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
 import org.opendaylight.yangtools.yang.model.repo.api.StatementParserMode;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.parser.rfc6020.repo.YangStatementStreamSource;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
-import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.EffectiveSchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class CrossSourceStatementReactor {
+public final class CrossSourceStatementReactor {
+    private static final Logger LOG = LoggerFactory.getLogger(CrossSourceStatementReactor.class);
 
     private final Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology;
     private final Map<ValidationBundleType, Collection<?>> supportedValidation;
 
-    CrossSourceStatementReactor(final Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology) {
-        this.supportedTerminology = ImmutableMap.copyOf(supportedTerminology);
-        this.supportedValidation = ImmutableMap.of();
-    }
-
     CrossSourceStatementReactor(final Map<ModelProcessingPhase, StatementSupportBundle> supportedTerminology,
             final Map<ValidationBundleType, Collection<?>> supportedValidation) {
         this.supportedTerminology = ImmutableMap.copyOf(supportedTerminology);
         this.supportedValidation = ImmutableMap.copyOf(supportedValidation);
     }
 
+    /**
+     * Create a new {@link Builder}.
+     *
+     * @return A new builder.
+     */
     public static Builder builder() {
         return new Builder();
     }
 
-    public final BuildAction newBuild() {
-        return newBuild(StatementParserMode.DEFAULT_MODE, IfFeaturePredicates.ALL_FEATURES);
+    /**
+     * Start a new reactor build using the default statement parser mode with all features and deviations enabled.
+     *
+     * @return A new {@link BuildAction}.
+     */
+    public BuildAction newBuild() {
+        return newBuild(StatementParserMode.DEFAULT_MODE);
     }
 
-    public final BuildAction newBuild(final Predicate<QName> isFeatureSupported) {
-        return new BuildAction(StatementParserMode.DEFAULT_MODE, isFeatureSupported);
+    /**
+     * Start a new reactor build using the default statement parser mode and enabling only the specified features
+     * and all deviations.
+     *
+     * @param supportedFeatures The set of supported features in the final SchemaContext
+     * @return A new {@link BuildAction}.
+     *
+     * @deprecated Use {@link #newBuild()} and then call setSupportedFeatures() on the created BuildAction instead.
+     */
+    @Deprecated
+    public BuildAction newBuild(final Set<QName> supportedFeatures) {
+        final BuildAction buildAction = newBuild();
+        if (supportedFeatures != null) {
+            buildAction.setSupportedFeatures(supportedFeatures);
+        }
+
+        return buildAction;
     }
 
-    public final BuildAction newBuild(final StatementParserMode statementParserMode) {
-        return new BuildAction(statementParserMode, IfFeaturePredicates.ALL_FEATURES);
+    /**
+     * Start a new reactor build using the default statement parser mode and enabling only the specified features
+     * and all deviations.
+     *
+     * @param supportedFeatures The set of supported features in the final SchemaContext, if present.
+     * @return A new {@link BuildAction}.
+     *
+     * @deprecated Use {@link #newBuild()} and then call setSupportedFeatures() on the created BuildAction instead.
+     */
+    @Deprecated
+    public BuildAction newBuild(final Optional<Set<QName>> supportedFeatures) {
+        final BuildAction buildAction = newBuild();
+        if (supportedFeatures.isPresent()) {
+            buildAction.setSupportedFeatures(supportedFeatures.get());
+        }
+
+        return buildAction;
     }
 
-    public final BuildAction newBuild(final StatementParserMode statementParserMode,
-            final Predicate<QName> isFeatureSupported) {
-        return new BuildAction(statementParserMode, isFeatureSupported);
+    /**
+     * Start a new reactor build using the specified statement parser mode and enabling all features and deviations.
+     *
+     * @param statementParserMode Parser mode to use
+     * @return A new {@link BuildAction}.
+     * @throws NullPointerException if statementParserMode is null
+     */
+    public BuildAction newBuild(final StatementParserMode statementParserMode) {
+        return new BuildAction(statementParserMode);
     }
 
-    public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor> {
+    /**
+     * Start a new reactor build using the specified statement parser mode and enabling only the specified features
+     * and all deviations.
+     *
+     * @param statementParserMode Parser mode to use
+     * @param supportedFeatures The set of supported features in the final SchemaContext
+     * @return A new {@link BuildAction}.
+     * @throws NullPointerException if statementParserMode is null
+     *
+     * @deprecated Use {@link #newBuild(StatementParserMode)} and then call setSupportedFeatures()
+     * on the created BuildAction instead.
+     */
+    @Deprecated
+    public BuildAction newBuild(final StatementParserMode statementParserMode,
+            final Set<QName> supportedFeatures) {
+        final BuildAction buildAction = new BuildAction(statementParserMode);
+        if (supportedFeatures != null) {
+            buildAction.setSupportedFeatures(supportedFeatures);
+        }
 
-        final Map<ModelProcessingPhase, StatementSupportBundle> bundles = new EnumMap<>(ModelProcessingPhase.class);
-        final Map<ValidationBundleType, Collection<?>> validationBundles = new EnumMap<>(ValidationBundleType.class);
+        return buildAction;
+    }
+
+    /**
+     * Start a new reactor build using the specified statement parser mode and enabling only the specified features
+     * and all deviations.
+     *
+     * @param statementParserMode Parser mode to use
+     * @param supportedFeatures The set of supported features in the final SchemaContext, or absent if all features
+     *                          encountered should be supported.
+     * @return A new {@link BuildAction}.
+     * @throws NullPointerException if statementParserMode is null
+     *
+     * @deprecated Use {@link #newBuild(StatementParserMode)} and then call setSupportedFeatures()
+     * on the created BuildAction instead.
+     */
+    @Deprecated
+    public BuildAction newBuild(final StatementParserMode statementParserMode,
+            final Optional<Set<QName>> supportedFeatures) {
+        final BuildAction buildAction = new BuildAction(statementParserMode);
+        if (supportedFeatures.isPresent()) {
+            buildAction.setSupportedFeatures(supportedFeatures.get());
+        }
+
+        return buildAction;
+    }
+
+    public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor> {
+        private final Map<ValidationBundleType, Collection<?>> validationBundles =
+                new EnumMap<>(ValidationBundleType.class);
+        private final Map<ModelProcessingPhase, StatementSupportBundle> bundles =
+                new EnumMap<>(ModelProcessingPhase.class);
 
         public Builder setBundle(final ModelProcessingPhase phase, final StatementSupportBundle bundle) {
             bundles.put(phase, bundle);
@@ -88,34 +186,88 @@ public class CrossSourceStatementReactor {
 
     public class BuildAction {
         private final BuildGlobalContext context;
+        private boolean supportedFeaturesSet = false;
+        private boolean modulesDeviatedByModulesSet = false;
 
-        public BuildAction() {
-            this(StatementParserMode.DEFAULT_MODE, IfFeaturePredicates.ALL_FEATURES);
-        }
-
-        public BuildAction(final StatementParserMode statementParserMode) {
-            this(statementParserMode, IfFeaturePredicates.ALL_FEATURES);
-        }
-
-        public BuildAction(final Predicate<QName> isFeatureSupported) {
-            this(StatementParserMode.DEFAULT_MODE, isFeatureSupported);
-        }
-
-        public BuildAction(final StatementParserMode statementParserMode, final Predicate<QName> isFeatureSupported) {
-            this.context = new BuildGlobalContext(supportedTerminology, supportedValidation, statementParserMode,
-                    isFeatureSupported);
+        BuildAction(@Nonnull final StatementParserMode statementParserMode) {
+            this.context = new BuildGlobalContext(supportedTerminology,supportedValidation,
+                    Preconditions.checkNotNull(statementParserMode));
         }
 
+        /**
+         * Add main source. All main sources are present in resulting
+         * SchemaContext.
+         *
+         * @param source
+         *            which should be added into main sources
+         */
         public void addSource(final StatementStreamSource source) {
             context.addSource(source);
         }
 
+        /**
+         * Add main sources. All main sources are present in resulting
+         * SchemaContext.
+         *
+         * @param sources
+         *            which should be added into main sources
+         */
         public void addSources(final StatementStreamSource... sources) {
+            addSources(Arrays.asList(sources));
+        }
+
+        public void addSources(final Collection<? extends StatementStreamSource> sources) {
             for (final StatementStreamSource source : sources) {
                 context.addSource(source);
             }
         }
 
+        /**
+         * Add library sources. Only library sources required by main sources
+         * are present in resulting SchemaContext. Any other library sources are
+         * ignored and this also applies to error reporting.
+         *
+         * Library sources are not supported in semantic version mode currently.
+         *
+         * @param libSources
+         *            yang sources which should be added into library sources
+         */
+        public void addLibSources(final StatementStreamSource... libSources) {
+            for (final StatementStreamSource libSource : libSources) {
+                context.addLibSource(libSource);
+            }
+        }
+
+        /**
+         * Set supported features based on which all if-feature statements in the
+         * parsed YANG modules will be resolved.
+         *
+         * @param supportedFeatures
+         *            Set of supported features in the final SchemaContext.
+         *            If the set is empty, no features encountered will be supported.
+         */
+        public void setSupportedFeatures(@Nonnull final Set<QName> supportedFeatures) {
+            Preconditions.checkState(!supportedFeaturesSet, "Supported features should be set only once.");
+            context.setSupportedFeatures(Preconditions.checkNotNull(supportedFeatures));
+            supportedFeaturesSet = true;
+        }
+
+        /**
+         * Set YANG modules which can be deviated by specified modules during the parsing process.
+         * Map key (QNameModule) denotes a module which can be deviated by the modules in the Map value.
+         *
+         * @param modulesDeviatedByModules
+         *            Map of YANG modules (Map key) which can be deviated by specified modules (Map value) in the final
+         *            SchemaContext. If the map is empty, no deviations encountered will be supported.
+         */
+        public void setModulesWithSupportedDeviations(
+                @Nonnull final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules) {
+            Preconditions.checkState(!modulesDeviatedByModulesSet,
+                    "Modules with supported deviations should be set only once.");
+            context.setModulesDeviatedByModules(Preconditions.checkNotNull(modulesDeviatedByModules));
+            modulesDeviatedByModulesSet = true;
+        }
+
         /**
          * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException
          * @throws ReactorException
@@ -128,15 +280,31 @@ public class CrossSourceStatementReactor {
             return context.buildEffective();
         }
 
+        /**
+         * @deprecated Use {@link #addSources(Collection)} and {@link #buildEffective()} instead.
+         */
+        @Deprecated
         public SchemaContext buildEffective(final Collection<ByteSource> yangByteSources) throws ReactorException,
                 IOException {
-            for (final ByteSource yangByteSource : yangByteSources) {
-                addSource(new YangStatementSourceImpl(yangByteSource.openStream()));
+            for (final ByteSource source : yangByteSources) {
+                if (source instanceof YangTextSchemaSource) {
+                    try {
+                        addSource(YangStatementStreamSource.create((YangTextSchemaSource) source));
+                    } catch (YangSyntaxErrorException e) {
+                        throw new IOException("Source " + source + " failed to parse", e);
+                    }
+                } else {
+                    addSource(new YangStatementSourceImpl(source.openStream()));
+                }
             }
 
             return buildEffective();
         }
 
+        /**
+         * @deprecated Use {@link #addSources(Collection)} and {@link #buildEffective()} instead.
+         */
+        @Deprecated
         public SchemaContext buildEffective(final List<InputStream> yangInputStreams) throws ReactorException {
             for (final InputStream yangInputStream : yangInputStreams) {
                 addSource(new YangStatementSourceImpl(yangInputStream));