YANGTOOLS-812: Add SchemaContextFactory control of deviations 13/64413/22
authorPeter Kajsa <pkajsa@cisco.com>
Tue, 17 Oct 2017 16:52:05 +0000 (18:52 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 20 Nov 2017 12:40:57 +0000 (13:40 +0100)
This patch adds missing API and implementation for setting supported
deviations in SchemaContextFactory.

In order to avoid passing of numerous arguments into
createSchemaContext(..) method a concept of a
SchemaContextFactoryConfiguration has been introduced in this patch,
which encapsulates all options possible to set.

Change-Id: I8eef54d729b7bfed4cee41ee6758d969fc375dcf
Signed-off-by: Peter Kajsa <pkajsa@cisco.com>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
22 files changed:
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.java
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactoryConfiguration.java [new file with mode: 0644]
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaRepository.java
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/repo/util/SchemaSourceTransformerTest.java
yang/yang-parser-api/src/main/java/org/opendaylight/yangtools/yang/model/parser/api/YangParser.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaContextFactory.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepository.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/repo/YangTextSchemaContextResolver.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SchemaContextFactoryDeviationsTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/bar-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/bar.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/baz-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/baz.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/foo-invalid.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/bug9195/foobar.yang [new file with mode: 0644]
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java
yang/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CrossSourceStatementReactor.java
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/deviate/AbstractDeviateStatementSupport.java
yang/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/Bug8307Test.java
yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/ModulesDeviatedByModules.java

index 5fac8367e813967b4311501c7cb3703a56d44117..84300e492fa98e2278a2d19f3e867dbdbc4c6c4a 100644 (file)
@@ -32,10 +32,7 @@ public interface SchemaContextFactory {
      *         with an explanation why the creation of the schema context
      *         failed.
      */
-    default ListenableFuture<SchemaContext> createSchemaContext(
-            @Nonnull final Collection<SourceIdentifier> requiredSources) {
-        return createSchemaContext(requiredSources, StatementParserMode.DEFAULT_MODE);
-    }
+    ListenableFuture<SchemaContext> createSchemaContext(@Nonnull Collection<SourceIdentifier> requiredSources);
 
     /**
      * Create a new schema context containing specified sources, pulling in any
@@ -48,9 +45,11 @@ public interface SchemaContextFactory {
      * @return A checked future, which will produce a schema context, or fail
      *         with an explanation why the creation of the schema context
      *         failed.
+     * @deprecated Use SchemaContextFactoryConfiguration instead.
      */
-    default ListenableFuture<SchemaContext> createSchemaContext(
-            final Collection<SourceIdentifier> requiredSources, final StatementParserMode statementParserMode) {
+    @Deprecated
+    default ListenableFuture<SchemaContext> createSchemaContext(final Collection<SourceIdentifier> requiredSources,
+            final StatementParserMode statementParserMode) {
         return createSchemaContext(requiredSources, statementParserMode, null);
     }
 
@@ -61,12 +60,14 @@ public interface SchemaContextFactory {
      * @param requiredSources
      *            a collection of sources which are required to be present
      * @param supportedFeatures
-     *            set of supported features based on which all if-feature statements in the
-     *            parsed yang models are resolved
+     *            set of supported features based on which all if-feature
+     *            statements in the parsed yang models are resolved
      * @return A checked future, which will produce a schema context, or fail
      *         with an explanation why the creation of the schema context
      *         failed.
+     * @deprecated Use SchemaContextFactoryConfiguration instead.
      */
+    @Deprecated
     default ListenableFuture<SchemaContext> createSchemaContext(
             @Nonnull final Collection<SourceIdentifier> requiredSources, final Set<QName> supportedFeatures) {
         return createSchemaContext(requiredSources, StatementParserMode.DEFAULT_MODE, supportedFeatures);
@@ -81,12 +82,14 @@ public interface SchemaContextFactory {
      * @param statementParserMode
      *            mode of statement parser
      * @param supportedFeatures
-     *            set of supported features based on which all if-feature statements in the
-     *            parsed yang models are resolved
+     *            set of supported features based on which all if-feature
+     *            statements in the parsed yang models are resolved
      * @return A checked future, which will produce a schema context, or fail
      *         with an explanation why the creation of the schema context
      *         failed.
+     * @deprecated Use SchemaContextFactoryConfiguration instead.
      */
+    @Deprecated
     ListenableFuture<SchemaContext> createSchemaContext(Collection<SourceIdentifier> requiredSources,
             StatementParserMode statementParserMode, Set<QName> supportedFeatures);
 }
diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactoryConfiguration.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactoryConfiguration.java
new file mode 100644 (file)
index 0000000..99454d7
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.repo.api;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+
+/**
+ * SchemaContextFactory configuration class.
+ *
+ * <p>
+ * SchemaContextFactoryConfiguration supports currently the following options to
+ * be set:
+ * <ul>
+ * <li>schema source filter</li>
+ * <li>statement parser mode</li>
+ * <li>supported features</li>
+ * <li>supported deviations</li>
+ * </ul>
+ */
+@Beta
+public final class SchemaContextFactoryConfiguration implements Immutable {
+    private static final SchemaContextFactoryConfiguration DEFAULT_CONFIGURATION = new Builder().build();
+
+    private final SchemaSourceFilter filter;
+    private final StatementParserMode statementParserMode;
+    private final Set<QName> supportedFeatures;
+    private final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules;
+
+    private SchemaContextFactoryConfiguration(final SchemaSourceFilter filter,
+            final StatementParserMode statementParserMode, final Set<QName> supportedFeatures,
+            final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
+        this.filter = requireNonNull(filter);
+        this.statementParserMode = requireNonNull(statementParserMode);
+        this.supportedFeatures = supportedFeatures;
+        this.modulesDeviatedByModules = modulesDeviatedByModules;
+    }
+
+    public SchemaSourceFilter getSchemaSourceFilter() {
+        return filter;
+    }
+
+    public StatementParserMode getStatementParserMode() {
+        return statementParserMode;
+    }
+
+    public Optional<Set<QName>> getSupportedFeatures() {
+        return Optional.ofNullable(supportedFeatures);
+    }
+
+    public Optional<SetMultimap<QNameModule, QNameModule>> getModulesDeviatedByModules() {
+        return Optional.ofNullable(modulesDeviatedByModules);
+    }
+
+    public static SchemaContextFactoryConfiguration getDefault() {
+        return DEFAULT_CONFIGURATION;
+    }
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(filter, statementParserMode, supportedFeatures, modulesDeviatedByModules);
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SchemaContextFactoryConfiguration)) {
+            return false;
+        }
+        final SchemaContextFactoryConfiguration other = (SchemaContextFactoryConfiguration) obj;
+        return filter.equals(other.filter) && statementParserMode.equals(other.statementParserMode)
+                && Objects.equals(supportedFeatures, other.supportedFeatures)
+                && Objects.equals(modulesDeviatedByModules, other.modulesDeviatedByModules);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).omitNullValues().add("schemaSourceFilter", filter)
+                .add("statementParserMode", statementParserMode).add("supportedFeatures", supportedFeatures)
+                .add("modulesDeviatedByModules", modulesDeviatedByModules).toString();
+    }
+
+    public static class Builder
+            implements org.opendaylight.yangtools.concepts.Builder<SchemaContextFactoryConfiguration> {
+        private SchemaSourceFilter filter = SchemaSourceFilter.ALWAYS_ACCEPT;
+        private StatementParserMode statementParserMode = StatementParserMode.DEFAULT_MODE;
+        private SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules;
+        private Set<QName> supportedFeatures;
+
+        /**
+         * Set schema source filter which will filter available schema sources
+         * using the provided filter.
+         *
+         * @param filter
+         *            schema source filter which acts as the gating function
+         *            before a schema source is considered by the factory for
+         *            inclusion in the SchemaContext it produces.
+         * @return this builder
+         */
+        public Builder setFilter(@Nonnull final SchemaSourceFilter filter) {
+            this.filter = requireNonNull(filter);
+            return this;
+        }
+
+        /**
+         * Set yang statement parser mode.
+         *
+         * @param statementParserMode
+         *            mode of yang statement parser
+         * @return this builder
+         */
+        public Builder setStatementParserMode(@Nonnull final StatementParserMode statementParserMode) {
+            this.statementParserMode = requireNonNull(statementParserMode);
+            return this;
+        }
+
+        /**
+         * 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.
+         * @return this builder
+         */
+        public Builder setSupportedFeatures(final Set<QName> supportedFeatures) {
+            this.supportedFeatures = supportedFeatures != null ? ImmutableSet.copyOf(supportedFeatures) : null;
+            return this;
+        }
+
+        /**
+         * 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 values) in the final SchemaContext.
+         *            If the map is empty, no deviations encountered will be
+         *            supported. If the map is null, all deviations will be applied.
+         * @return this builder
+         */
+        public Builder setModulesDeviatedByModules(
+                final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
+            this.modulesDeviatedByModules = modulesDeviatedByModules != null
+                    ? ImmutableSetMultimap.copyOf(modulesDeviatedByModules) : null;
+            return this;
+        }
+
+        @Override
+        public SchemaContextFactoryConfiguration build() {
+            return new SchemaContextFactoryConfiguration(filter, statementParserMode, supportedFeatures,
+                    modulesDeviatedByModules);
+        }
+    }
+}
\ No newline at end of file
index cefd55868eeb84b392d66d284b3ca16dd217e897..c3936f40b09ee0465d8398223cde2576935b602b 100644 (file)
@@ -19,16 +19,30 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 @Beta
 public interface SchemaRepository {
     /**
-     * Instantiate a new {@link SchemaContextFactory}, which will filter available schema
-     * sources using the provided filter.
+     * Instantiate a new {@link SchemaContextFactory}, which will filter
+     * available schema sources using the provided filter.
      *
-     * @param filter Filter which acts as the gating function before a schema source is
-     *               considered by the factory for inclusion in the {@link SchemaContext}
-     *               it produces.
+     * @param filter
+     *            Filter which acts as the gating function before a schema
+     *            source is considered by the factory for inclusion in the
+     *            {@link SchemaContext} it produces.
      * @return A new schema context factory.
+     * @deprecated Use
+     *             {@link #createSchemaContextFactory(SchemaContextFactoryConfiguration)}
+     *             instead.
      */
+    @Deprecated
     SchemaContextFactory createSchemaContextFactory(@Nonnull SchemaSourceFilter filter);
 
+    /**
+     * Returns {@link SchemaContextFactory} with supplied configuration.
+     *
+     * @param config
+     *            configuration of schema context factory.
+     * @return schema context factory.
+     */
+    SchemaContextFactory createSchemaContextFactory(@Nonnull SchemaContextFactoryConfiguration config);
+
     <T extends SchemaSourceRepresentation> ListenableFuture<T> getSchemaSource(@Nonnull SourceIdentifier id,
             @Nonnull Class<T> represetation);
 }
index c404c0a437c9a8a5aa2f947034d904282e6b492e..71482cab8fc3c0a38a6d1fcad791fbb141f4651f 100644 (file)
@@ -20,6 +20,7 @@ import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
@@ -139,20 +140,31 @@ public class SchemaSourceTransformerTest {
     }
 
     private class Provider extends AbstractSchemaRepository {
-
+        @Deprecated
         @Override
         public SchemaContextFactory createSchemaContextFactory(@Nonnull final SchemaSourceFilter filter) {
             return null;
         }
 
+        @Override
+        public SchemaContextFactory createSchemaContextFactory(
+                @Nonnull final SchemaContextFactoryConfiguration config) {
+            return null;
+        }
+
     }
 
     private class Consumer extends AbstractSchemaRepository {
-
+        @Deprecated
         @Override
         public SchemaContextFactory createSchemaContextFactory(@Nonnull final SchemaSourceFilter filter) {
             return null;
         }
 
+        @Override
+        public SchemaContextFactory createSchemaContextFactory(
+                @Nonnull final SchemaContextFactoryConfiguration config) {
+            return null;
+        }
     }
 }
index ab287e41b74347e0134e2ab728e6ac7e9ea35f82..ecd143798e6b09c62f7a403d695e4e3ee7dcd819 100644 (file)
@@ -8,10 +8,10 @@
 package org.opendaylight.yangtools.yang.model.parser.api;
 
 import com.google.common.annotations.Beta;
+import com.google.common.collect.SetMultimap;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.concurrent.NotThreadSafe;
@@ -131,7 +131,7 @@ public interface YangParser {
      *            SchemaContext. If the map is empty, no deviations encountered will be supported.
      */
     YangParser setModulesWithSupportedDeviations(
-            @Nonnull Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules);
+            @Nonnull SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules);
 
     /**
      * Build the declared view of a combined view of declared statements.
index 17741879d880da85e398ef17e325695e28c336ea..a101aa835fc9f9fcce4aa5953fb92c258ea44eab 100644 (file)
@@ -10,10 +10,10 @@ package org.opendaylight.yangtools.yang.parser.impl;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.SetMultimap;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import javax.xml.transform.TransformerException;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -78,7 +78,7 @@ final class YangParserImpl implements YangParser {
 
     @Override
     public YangParser setModulesWithSupportedDeviations(
-            final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules) {
+            final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
         buildAction.setModulesWithSupportedDeviations(modulesDeviatedByModules);
         return this;
     }
index 415d20aafb3e83ac0ec34f3b516ed41d43d6d832..2a9af3d1f81dda64cf5f71b0312c451871bc7839 100644 (file)
@@ -26,7 +26,6 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Optional;
 import java.util.Set;
 import javax.annotation.Nonnull;
 import org.antlr.v4.runtime.ParserRuleContext;
@@ -34,6 +33,8 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.Statement
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaResolutionException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
@@ -54,23 +55,38 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
             .weakValues().build();
     private final Cache<Collection<SourceIdentifier>, SchemaContext> semVerCache = CacheBuilder.newBuilder()
             .weakValues().build();
-    private final SharedSchemaRepository repository;
-    // FIXME: ignored right now
-    private final SchemaSourceFilter filter;
+    private final SchemaRepository repository;
+    private final SchemaContextFactoryConfiguration config;
 
     // FIXME SchemaRepository should be the type for repository parameter instead of SharedSchemaRepository
     //       (final implementation)
+    @Deprecated
     SharedSchemaContextFactory(final SharedSchemaRepository repository, final SchemaSourceFilter filter) {
         this.repository = Preconditions.checkNotNull(repository);
-        this.filter = Preconditions.checkNotNull(filter);
+        this.config = SchemaContextFactoryConfiguration.builder().setFilter(filter).build();
+    }
+
+    SharedSchemaContextFactory(final SchemaRepository repository, final SchemaContextFactoryConfiguration config) {
+        this.repository = Preconditions.checkNotNull(repository);
+        this.config = Preconditions.checkNotNull(config);
     }
 
     @Override
+    @Deprecated
     public ListenableFuture<SchemaContext> createSchemaContext(final Collection<SourceIdentifier> requiredSources,
             final StatementParserMode statementParserMode, final Set<QName> supportedFeatures) {
         return createSchemaContext(requiredSources,
-                statementParserMode == StatementParserMode.SEMVER_MODE ? this.semVerCache : this.revisionCache,
-                new AssembleSources(Optional.ofNullable(supportedFeatures), statementParserMode));
+                statementParserMode == StatementParserMode.SEMVER_MODE ? semVerCache : revisionCache,
+                new AssembleSources(SchemaContextFactoryConfiguration.builder()
+                        .setFilter(config.getSchemaSourceFilter()).setStatementParserMode(statementParserMode)
+                        .setSupportedFeatures(supportedFeatures).build()));
+    }
+
+    @Override
+    public ListenableFuture<SchemaContext> createSchemaContext(final Collection<SourceIdentifier> requiredSources) {
+        return createSchemaContext(requiredSources,
+                config.getStatementParserMode() == StatementParserMode.SEMVER_MODE ? semVerCache : revisionCache,
+                new AssembleSources(config));
     }
 
     private ListenableFuture<SchemaContext> createSchemaContext(final Collection<SourceIdentifier> requiredSources,
@@ -172,15 +188,12 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
 
     private static final class AssembleSources implements AsyncFunction<List<ASTSchemaSource>, SchemaContext> {
 
-        private final Optional<Set<QName>> supportedFeatures;
-        private final StatementParserMode statementParserMode;
+        private final SchemaContextFactoryConfiguration config;
         private final Function<ASTSchemaSource, SourceIdentifier> getIdentifier;
 
-        private AssembleSources(final Optional<Set<QName>> supportedFeatures,
-                final StatementParserMode statementParserMode) {
-            this.supportedFeatures = supportedFeatures;
-            this.statementParserMode = Preconditions.checkNotNull(statementParserMode);
-            switch (statementParserMode) {
+        private AssembleSources(@Nonnull final SchemaContextFactoryConfiguration config) {
+            this.config = config;
+            switch (config.getStatementParserMode()) {
                 case SEMVER_MODE:
                     this.getIdentifier = ASTSchemaSource::getSemVerIdentifier;
                     break;
@@ -198,7 +211,8 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
 
             LOG.debug("Resolving dependency reactor {}", deps);
 
-            final DependencyResolver res = this.statementParserMode == StatementParserMode.SEMVER_MODE
+            final StatementParserMode statementParserMode = config.getStatementParserMode();
+            final DependencyResolver res = statementParserMode == StatementParserMode.SEMVER_MODE
                     ? SemVerDependencyResolver.create(deps) : RevisionDependencyResolver.create(deps);
             if (!res.getUnresolvedSources().isEmpty()) {
                 LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(),
@@ -208,9 +222,8 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
             }
 
             final BuildAction reactor = DefaultReactors.defaultReactor().newBuild(statementParserMode);
-            if (supportedFeatures.isPresent()) {
-                reactor.setSupportedFeatures(supportedFeatures.get());
-            }
+            config.getSupportedFeatures().ifPresent(reactor::setSupportedFeatures);
+            config.getModulesDeviatedByModules().ifPresent(reactor::setModulesWithSupportedDeviations);
 
             for (final Entry<SourceIdentifier, ASTSchemaSource> e : srcs.entrySet()) {
                 final ASTSchemaSource ast = e.getValue();
index 3682b1014f212ff386f646d5e2c72ef2195b58c3..6e4bf20070968f3cc006153be3b2a1fec6dfcb99 100644 (file)
@@ -17,6 +17,7 @@ import org.kohsuke.MetaInfServices;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
@@ -31,13 +32,24 @@ import org.opendaylight.yangtools.yang.model.repo.util.AbstractSchemaRepository;
 @Beta
 @MetaInfServices(value = SchemaRepository.class)
 public final class SharedSchemaRepository extends AbstractSchemaRepository implements Identifiable<String> {
-    private final LoadingCache<SchemaSourceFilter, SchemaContextFactory> cache =
-            CacheBuilder.newBuilder().softValues().build(new CacheLoader<SchemaSourceFilter, SchemaContextFactory>() {
+    @Deprecated
+    private final LoadingCache<SchemaSourceFilter, SchemaContextFactory> cacheByFilter = CacheBuilder.newBuilder()
+            .softValues().build(new CacheLoader<SchemaSourceFilter, SchemaContextFactory>() {
                 @Override
                 public SchemaContextFactory load(@Nonnull final SchemaSourceFilter key) {
                     return new SharedSchemaContextFactory(SharedSchemaRepository.this, key);
                 }
             });
+
+    private final LoadingCache<SchemaContextFactoryConfiguration, SchemaContextFactory> cacheByConfig = CacheBuilder
+            .newBuilder().softValues()
+            .build(new CacheLoader<SchemaContextFactoryConfiguration, SchemaContextFactory>() {
+                @Override
+                public SchemaContextFactory load(@Nonnull final SchemaContextFactoryConfiguration key) {
+                    return new SharedSchemaContextFactory(SharedSchemaRepository.this, key);
+                }
+            });
+
     private final String id;
 
     public SharedSchemaRepository(final String id) {
@@ -50,8 +62,14 @@ public final class SharedSchemaRepository extends AbstractSchemaRepository imple
     }
 
     @Override
+    @Deprecated
     public SchemaContextFactory createSchemaContextFactory(@Nonnull final SchemaSourceFilter filter) {
-        return cache.getUnchecked(filter);
+        return cacheByFilter.getUnchecked(filter);
+    }
+
+    @Override
+    public SchemaContextFactory createSchemaContextFactory(@Nonnull final SchemaContextFactoryConfiguration config) {
+        return cacheByConfig.getUnchecked(config);
     }
 
     @Override
index 00075b935876010d296b1d68194f4dfc387f5629..eccacf5eed9873482509cc6f9bb1e53cfcdf9b25 100644 (file)
@@ -186,7 +186,7 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
     private static SourceIdentifier guessSourceIdentifier(final String fileName) {
         try {
             return YangTextSchemaSource.identifierFromFilename(fileName);
-        } catch (IllegalArgumentException e) {
+        } catch (final IllegalArgumentException e) {
             LOG.warn("Invalid file name format in '{}'", fileName, e);
             return RevisionSourceIdentifier.create(fileName);
         }
@@ -236,9 +236,9 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
                 try {
                     sc = Optional.of(f.get());
                     break;
-                } catch (InterruptedException e) {
+                } catch (final InterruptedException e) {
                     throw new RuntimeException("Interrupted while assembling schema context", e);
-                } catch (ExecutionException e) {
+                } catch (final ExecutionException e) {
                     LOG.info("Failed to fully assemble schema context for {}", sources, e);
                     final Throwable cause = e.getCause();
                     Verify.verify(cause instanceof SchemaResolutionException);
@@ -302,9 +302,9 @@ public final class YangTextSchemaContextResolver implements AutoCloseable, Schem
 
         try {
             return future.get();
-        } catch (InterruptedException e) {
+        } catch (final InterruptedException e) {
             throw new RuntimeException("Interrupted while waiting for SchemaContext assembly", e);
-        } catch (ExecutionException e) {
+        } catch (final ExecutionException e) {
             final Throwable cause = e.getCause();
             if (cause instanceof SchemaResolutionException) {
                 throw (SchemaResolutionException) cause;
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SchemaContextFactoryDeviationsTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SchemaContextFactoryDeviationsTest.java
new file mode 100644 (file)
index 0000000..61142c3
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.yangtools.yang.parser.repo;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.ExecutionException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactoryConfiguration;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.parser.rfc7950.repo.ASTSchemaSource;
+import org.opendaylight.yangtools.yang.parser.rfc7950.repo.TextToASTTransformer;
+import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
+
+public class SchemaContextFactoryDeviationsTest {
+    private static final String FOO = "/bug9195/foo.yang";
+    private static final String BAR = "/bug9195/bar.yang";
+    private static final String BAZ = "/bug9195/baz.yang";
+    private static final String FOOBAR = "/bug9195/foobar.yang";
+    private static final String BAR_INVALID = "/bug9195/bar-invalid.yang";
+    private static final String BAZ_INVALID = "/bug9195/baz-invalid.yang";
+    private static final URI FOO_NS = URI.create("foo-ns");
+    private static final URI BAR_NS = URI.create("bar-ns");
+    private static final URI BAZ_NS = URI.create("baz-ns");
+    private static Revision revision;
+    private static QNameModule foo;
+    private static QName myFooContA;
+    private static QName myFooContB;
+    private static QName myFooContC;
+    private static QNameModule bar;
+    private static QName myBarContA;
+    private static QName myBarContB;
+    private static QNameModule baz;
+
+    @BeforeClass
+    public static void setup() throws ParseException {
+        revision = Revision.of("2017-05-16");
+        foo = QNameModule.create(FOO_NS, revision);
+        myFooContA = QName.create(foo, "my-foo-cont-a");
+        myFooContB = QName.create(foo, "my-foo-cont-b");
+        myFooContC = QName.create(foo, "my-foo-cont-c");
+        bar = QNameModule.create(BAR_NS, revision);
+        myBarContA = QName.create(bar, "my-bar-cont-a");
+        myBarContB = QName.create(bar, "my-bar-cont-b");
+        baz = QNameModule.create(BAZ_NS, revision);
+    }
+
+    @Test
+    public void testDeviationsSupportedInSomeModules() throws Exception {
+        final SetMultimap<QNameModule, QNameModule> modulesWithSupportedDeviations =
+                ImmutableSetMultimap.<QNameModule, QNameModule>builder()
+                .put(foo, bar)
+                .put(foo, baz)
+                .put(bar, baz)
+                .build();
+
+        final ListenableFuture<SchemaContext> lf = createSchemaContext(modulesWithSupportedDeviations, FOO, BAR, BAZ,
+                FOOBAR);
+        assertTrue(lf.isDone());
+        final SchemaContext schemaContext = lf.get();
+        assertNotNull(schemaContext);
+
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContA)));
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContB)));
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContC)));
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myBarContA)));
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myBarContB)));
+    }
+
+    @Test
+    public void testDeviationsSupportedInAllModules() throws Exception {
+        final ListenableFuture<SchemaContext> lf = createSchemaContext(null, FOO, BAR, BAZ, FOOBAR);
+        assertTrue(lf.isDone());
+        final SchemaContext schemaContext = lf.get();
+        assertNotNull(schemaContext);
+
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContA)));
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContB)));
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContC)));
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myBarContA)));
+        assertNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myBarContB)));
+    }
+
+    @Test
+    public void testDeviationsSupportedInNoModule() throws Exception {
+        final ListenableFuture<SchemaContext> lf = createSchemaContext(ImmutableSetMultimap.of(), FOO, BAR, BAZ,
+            FOOBAR);
+        assertTrue(lf.isDone());
+        final SchemaContext schemaContext = lf.get();
+        assertNotNull(schemaContext);
+
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContA)));
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContB)));
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myFooContC)));
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myBarContA)));
+        assertNotNull(SchemaContextUtil.findDataSchemaNode(schemaContext, SchemaPath.create(true, myBarContB)));
+    }
+
+    @Test
+    public void shouldFailOnAttemptToDeviateTheSameModule2() throws Exception {
+        final ListenableFuture<SchemaContext> lf = createSchemaContext(null, BAR_INVALID, BAZ_INVALID);
+        assertTrue(lf.isDone());
+        try {
+            lf.get();
+            fail("Deviation that targets the same module as the one it is defined is forbidden.");
+        } catch (final ExecutionException ex) {
+            final Throwable cause = ex.getCause().getCause().getCause();
+            assertTrue(cause instanceof InferenceException);
+            assertTrue(cause.getMessage()
+                    .startsWith("Deviation must not target the same module as the one it is defined in"));
+        }
+    }
+
+    private static SettableSchemaProvider<ASTSchemaSource> getImmediateYangSourceProviderFromResource(
+            final String resourceName) throws Exception {
+        final YangTextSchemaSource yangSource = YangTextSchemaSource.forResource(resourceName);
+        return SettableSchemaProvider.createImmediate(TextToASTTransformer.transformText(yangSource),
+                ASTSchemaSource.class);
+    }
+
+    private static ListenableFuture<SchemaContext> createSchemaContext(
+            final SetMultimap<QNameModule, QNameModule> modulesWithSupportedDeviations, final String... resources)
+            throws Exception {
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository(
+                "shared-schema-repo-with-deviations-test");
+
+        final Collection<SourceIdentifier> requiredSources = new ArrayList<>();
+        for (final String resource : resources) {
+            final SettableSchemaProvider<ASTSchemaSource> yangSource = getImmediateYangSourceProviderFromResource(
+                    resource);
+            yangSource.register(sharedSchemaRepository);
+            yangSource.setResult();
+            requiredSources.add(yangSource.getId());
+        }
+
+        final SchemaContextFactoryConfiguration config = SchemaContextFactoryConfiguration.builder()
+                .setModulesDeviatedByModules(modulesWithSupportedDeviations).build();
+        final SchemaContextFactory fact = sharedSchemaRepository.createSchemaContextFactory(config);
+
+        return fact.createSchemaContext(ImmutableList.copyOf(requiredSources));
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/bar-invalid.yang b/yang/yang-parser-impl/src/test/resources/bug9195/bar-invalid.yang
new file mode 100644 (file)
index 0000000..d49ab16
--- /dev/null
@@ -0,0 +1,19 @@
+module bar {
+    namespace bar-ns;
+    prefix bar;
+
+    import baz {
+        prefix baz;
+        revision-date 2017-05-16;
+    }
+
+    revision 2017-05-16;
+
+    deviation "/baz:my-baz-cont/bar:my-aug-cont" {
+        deviate not-supported;
+    }
+
+    augment "/baz:my-baz-cont" {
+        container my-aug-cont {}
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/bar.yang b/yang/yang-parser-impl/src/test/resources/bug9195/bar.yang
new file mode 100644 (file)
index 0000000..46e15df
--- /dev/null
@@ -0,0 +1,19 @@
+module bar {
+    namespace bar-ns;
+    prefix bar-prefix;
+
+    import foo {
+        prefix foo;
+        revision-date 2017-05-16;
+    }
+
+    revision 2017-05-16;
+
+    deviation "/foo:my-foo-cont-a" {
+        deviate not-supported;
+    }
+
+    container my-bar-cont-a {}
+
+    container my-bar-cont-b {}
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/baz-invalid.yang b/yang/yang-parser-impl/src/test/resources/bug9195/baz-invalid.yang
new file mode 100644 (file)
index 0000000..39d1cfe
--- /dev/null
@@ -0,0 +1,8 @@
+module baz {
+    namespace baz-ns;
+    prefix baz;
+
+    revision 2017-05-16;
+
+    container my-baz-cont {}
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/baz.yang b/yang/yang-parser-impl/src/test/resources/bug9195/baz.yang
new file mode 100644 (file)
index 0000000..05df3ad
--- /dev/null
@@ -0,0 +1,26 @@
+module baz {
+    namespace baz-ns;
+    prefix baz-prefix;
+
+    import foo {
+        prefix foo;
+        revision-date 2017-05-16;
+    }
+
+    import bar {
+        prefix bar;
+        revision-date 2017-05-16;
+    }
+
+    revision 2017-05-16;
+
+    deviation "/foo:my-foo-cont-b" {
+        deviate not-supported;
+    }
+
+    deviation "/bar:my-bar-cont-a" {
+        deviate not-supported;
+    }
+
+    container my-baz-cont {}
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/foo-invalid.yang b/yang/yang-parser-impl/src/test/resources/bug9195/foo-invalid.yang
new file mode 100644 (file)
index 0000000..b1cad54
--- /dev/null
@@ -0,0 +1,12 @@
+module foo {
+    namespace foo-ns;
+    prefix foo;
+
+    revision 2017-05-16;
+
+    deviation "/my-foo-cont" {
+        deviate not-supported;
+    }
+
+    container my-foo-cont {}
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/foo.yang b/yang/yang-parser-impl/src/test/resources/bug9195/foo.yang
new file mode 100644 (file)
index 0000000..4027fee
--- /dev/null
@@ -0,0 +1,12 @@
+module foo {
+    namespace foo-ns;
+    prefix foo-prefix;
+
+    revision 2017-05-16;
+
+    container my-foo-cont-a {}
+
+    container my-foo-cont-b {}
+
+    container my-foo-cont-c {}
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/bug9195/foobar.yang b/yang/yang-parser-impl/src/test/resources/bug9195/foobar.yang
new file mode 100644 (file)
index 0000000..97d4478
--- /dev/null
@@ -0,0 +1,24 @@
+module foobar {
+    namespace foobar-ns;
+    prefix foobar-prefix;
+
+    import foo {
+        prefix foo;
+        revision-date 2017-05-16;
+    }
+
+    import bar {
+        prefix bar;
+        revision-date 2017-05-16;
+    }
+
+    revision 2017-05-16;
+
+    deviation "/foo:my-foo-cont-c" {
+        deviate not-supported;
+    }
+
+    deviation "/bar:my-bar-cont-b" {
+        deviate not-supported;
+    }
+}
\ No newline at end of file
index 2fd1b9462e2ba258adde16678ba03e5214620ecb..0bd6efdb76d4ad71a8293578dfe80324c4af48e3 100644 (file)
@@ -13,8 +13,9 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.base.Verify;
 import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
 import com.google.common.collect.Table;
 import com.google.common.collect.TreeBasedTable;
 import java.util.ArrayList;
@@ -134,9 +135,9 @@ class BuildGlobalContext extends NamespaceStorageSupport implements Registry {
                     ImmutableSet.copyOf(supportedFeatures));
     }
 
-    void setModulesDeviatedByModules(final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules) {
+    void setModulesDeviatedByModules(final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
         addToNs(ModulesDeviatedByModules.class, SupportedModules.SUPPORTED_MODULES,
-                    ImmutableMap.copyOf(modulesDeviatedByModules));
+                    ImmutableSetMultimap.copyOf(modulesDeviatedByModules));
     }
 
     @Override
index f22aed69ce96a9c981f1db74be457d450081c1c9..2adb14f665fdb7203b97c458728bccf2542bb722 100644 (file)
@@ -11,6 +11,7 @@ import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.SetMultimap;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumMap;
@@ -177,7 +178,7 @@ public final class CrossSourceStatementReactor {
          * @return This build action, for fluent use.
          */
         public BuildAction setModulesWithSupportedDeviations(
-                @Nonnull final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules) {
+                @Nonnull final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules) {
             checkState(!modulesDeviatedByModulesSet, "Modules with supported deviations should be set only once.");
             context.setModulesDeviatedByModules(requireNonNull(modulesDeviatedByModules));
             modulesDeviatedByModulesSet = true;
index 2c13541396c0959d0acc6ad2e539f58ceec86dfb..8cce0c2cb03a192bbc679e0c1a026b84c0b16358 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.deviate;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Objects;
@@ -204,7 +205,7 @@ abstract class AbstractDeviateStatementSupport extends AbstractStatementSupport<
     private static boolean isDeviationSupported(final Mutable<DeviateKind, DeviateStatement,
             EffectiveStatement<DeviateKind, DeviateStatement>> deviateStmtCtx,
             final SchemaNodeIdentifier deviationTarget) {
-        final Map<QNameModule, Set<QNameModule>> modulesDeviatedByModules = deviateStmtCtx.getFromNamespace(
+        final SetMultimap<QNameModule, QNameModule> modulesDeviatedByModules = deviateStmtCtx.getFromNamespace(
                 ModulesDeviatedByModules.class, SupportedModules.SUPPORTED_MODULES);
         if (modulesDeviatedByModules == null) {
             return true;
index a36bbe206ddc763da3dd4dfb04858ffdd5ae96bc..4b0e769d9ff30e5fa175efc502e594309e9dbd32 100644 (file)
@@ -13,11 +13,9 @@ import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.opendaylight.yangtools.yang.stmt.StmtTestUtils.sourceForResource;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.SetMultimap;
 import java.net.URI;
-import java.util.Map;
-import java.util.Set;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -72,8 +70,12 @@ public class Bug8307Test {
 
     @Test
     public void testDeviationsSupportedInSomeModules() throws Exception {
-        final Map<QNameModule, Set<QNameModule>> modulesWithSupportedDeviations = ImmutableMap.of(
-                foo, ImmutableSet.of(bar, baz), bar, ImmutableSet.of(baz));
+        final SetMultimap<QNameModule, QNameModule> modulesWithSupportedDeviations =
+                ImmutableSetMultimap.<QNameModule, QNameModule>builder()
+                .put(foo, bar)
+                .put(foo, baz)
+                .put(bar, baz)
+                .build();
 
         final SchemaContext schemaContext = RFC7950Reactors.defaultReactor().newBuild()
                 .addSources(FOO_MODULE, BAR_MODULE, BAZ_MODULE, FOOBAR_MODULE)
@@ -106,7 +108,7 @@ public class Bug8307Test {
     public void testDeviationsSupportedInNoModule() throws Exception {
         final SchemaContext schemaContext = RFC7950Reactors.defaultReactor().newBuild()
                 .addSources(FOO_MODULE, BAR_MODULE, BAZ_MODULE, FOOBAR_MODULE)
-                .setModulesWithSupportedDeviations(ImmutableMap.of())
+                .setModulesWithSupportedDeviations(ImmutableSetMultimap.of())
                 .buildEffective();
         assertNotNull(schemaContext);
 
index b4d16ac6eba22732e78e0d1979cf53ce9289db1c..60e03633964e50876ee96fa66d7f52c6183765a7 100644 (file)
@@ -9,8 +9,7 @@
 package org.opendaylight.yangtools.yang.parser.spi.source;
 
 import com.google.common.annotations.Beta;
-import java.util.Map;
-import java.util.Set;
+import com.google.common.collect.SetMultimap;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
@@ -22,8 +21,8 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
  */
 @Beta
 public interface ModulesDeviatedByModules
-        extends IdentifierNamespace<ModulesDeviatedByModules.SupportedModules, Map<QNameModule, Set<QNameModule>>> {
-    NamespaceBehaviour<SupportedModules, Map<QNameModule, Set<QNameModule>>, @NonNull ModulesDeviatedByModules>
+        extends IdentifierNamespace<ModulesDeviatedByModules.SupportedModules, SetMultimap<QNameModule, QNameModule>> {
+    NamespaceBehaviour<SupportedModules, SetMultimap<QNameModule, QNameModule>, @NonNull ModulesDeviatedByModules>
         BEHAVIOUR = NamespaceBehaviour.global(ModulesDeviatedByModules.class);
 
     enum SupportedModules {