Bug 4506: Honor if-feature during SchemaContext assembly 08/38108/12
authorIgor Foltin <ifoltin@cisco.com>
Fri, 13 May 2016 09:42:06 +0000 (11:42 +0200)
committerIgor Foltin <ifoltin@cisco.com>
Mon, 23 May 2016 09:16:07 +0000 (11:16 +0200)
If-feature statements in yang modules are now resolved
during SchemaContext assembly based on
a java.util.function.Predicate<QName> provided by user.

This functionality is also introduced into SchemaContextFactory

Change-Id: I2a74e36c9433a0b89c97c19407c988b538c236bc
Signed-off-by: Igor Foltin <ifoltin@cisco.com>
Signed-off-by: Robert Varga <rovarga@cisco.com>
Signed-off-by: Igor Foltin <ifoltin@cisco.com>
15 files changed:
yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/repo/api/SchemaContextFactory.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/spi/meta/StmtContextUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/SupportedFeaturesNamespace.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/BuildGlobalContext.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/CrossSourceStatementReactor.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/AugmentStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/UsesStatementImpl.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/effective/EffectiveStatementBase.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryWithFeaturesTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/IfFeatureResolutionTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/bar.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/shared-schema-repository/foobar.yang [new file with mode: 0644]

index 11782fe2acbc58820883fb70f900c624acc41cf5..9b338a742b601ac66db2bcd95e006ab7c9665322 100644 (file)
@@ -10,7 +10,9 @@ package org.opendaylight.yangtools.yang.model.repo.api;
 import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.CheckedFuture;
 import java.util.Collection;
+import java.util.function.Predicate;
 import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 /**
@@ -30,5 +32,23 @@ public interface SchemaContextFactory {
      *         fail with an explanation why the creation of the schema context
      *         failed.
      */
-    CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(@Nonnull Collection<SourceIdentifier> requiredSources);
+    default CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
+            @Nonnull Collection<SourceIdentifier> requiredSources) {
+        return createSchemaContext(requiredSources, t -> true);
+    }
+
+    /**
+     * Create a new schema context containing specified sources, pulling in
+     * any dependencies they may have.
+     *
+     * @param requiredSources a collection of sources which are required to
+     *                        be present
+     * @param isFeatureSupported a predicate 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.
+     */
+    CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
+            @Nonnull Collection<SourceIdentifier> requiredSources, Predicate<QName> isFeatureSupported);
 }
index ab146fcfc6d732196966f3697c36cee12aad0c3d..1594fd4212704836a7207008bfb619f9cafd67b6 100644 (file)
@@ -33,6 +33,7 @@ import org.antlr.v4.runtime.ParserRuleContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
 import org.opendaylight.yangtools.util.concurrent.ReflectiveExceptionMapper;
+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.SchemaResolutionException;
@@ -59,41 +60,6 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
         }
     };
     private final Cache<Collection<SourceIdentifier>, SchemaContext> cache = CacheBuilder.newBuilder().weakValues().build();
-
-    private final AsyncFunction<List<ASTSchemaSource>, SchemaContext> assembleSources = new AsyncFunction<List<ASTSchemaSource>, SchemaContext>() {
-        @Override
-        public ListenableFuture<SchemaContext> apply(final List<ASTSchemaSource> sources) throws SchemaResolutionException, SourceException, ReactorException {
-            final Map<SourceIdentifier, ASTSchemaSource> srcs =
-                    Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER);
-            final Map<SourceIdentifier, YangModelDependencyInfo> deps =
-                    Maps.transformValues(srcs, ASTSchemaSource.GET_DEPINFO);
-
-            LOG.debug("Resolving dependency reactor {}", deps);
-
-            final DependencyResolver res = DependencyResolver.create(deps);
-            if (!res.getUnresolvedSources().isEmpty()) {
-                LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
-                throw new SchemaResolutionException("Failed to resolve required models",
-                        res.getResolvedSources(), res.getUnsatisfiedImports());
-            }
-
-            final Map<SourceIdentifier, ParserRuleContext> asts = Maps.transformValues(srcs, ASTSchemaSource.GET_AST);
-            final CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
-
-            for (final Entry<SourceIdentifier, ParserRuleContext> e : asts.entrySet()) {
-                final ParserRuleContext parserRuleCtx = e.getValue();
-                Preconditions.checkArgument(parserRuleCtx instanceof StatementContext,
-                    "Unsupported context class %s for source %s", parserRuleCtx.getClass(), e.getKey());
-
-                reactor.addSource(new YangStatementSourceImpl(e.getKey(), (StatementContext) parserRuleCtx));
-            }
-
-            SchemaContext schemaContext = reactor.buildEffective();
-
-            return Futures.immediateCheckedFuture(schemaContext);
-        }
-    };
-
     private final SharedSchemaRepository repository;
     // FIXME: ignored right now
     private final SchemaSourceFilter filter;
@@ -105,7 +71,8 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
     }
 
     @Override
-    public CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(final Collection<SourceIdentifier> requiredSources) {
+    public CheckedFuture<SchemaContext, SchemaResolutionException> createSchemaContext(
+            final Collection<SourceIdentifier> requiredSources, java.util.function.Predicate<QName> isFeatureSupported) {
         // Make sources unique
         final List<SourceIdentifier> uniqueSourceIdentifiers = deDuplicateSources(requiredSources);
 
@@ -124,6 +91,7 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
         sf = Futures.transform(sf, new SourceIdMismatchDetector(uniqueSourceIdentifiers));
 
         // Assemble sources into a schema context
+        final AssembleSources assembleSources = new AssembleSources(isFeatureSupported);
         final ListenableFuture<SchemaContext> cf = Futures.transform(sf, assembleSources);
 
         // Populate cache when successful
@@ -194,4 +162,47 @@ final class SharedSchemaContextFactory implements SchemaContextFactory {
             return ImmutableList.copyOf(filtered.values());
         }
     }
+
+    private static final class AssembleSources implements AsyncFunction<List<ASTSchemaSource>, SchemaContext> {
+
+        private final java.util.function.Predicate<QName> isFeatureSupported;
+
+        private AssembleSources(final java.util.function.Predicate<QName> isFeatureSupported) {
+            this.isFeatureSupported = Preconditions.checkNotNull(isFeatureSupported);
+        }
+
+        @Override
+        public ListenableFuture<SchemaContext> apply(List<ASTSchemaSource> sources) throws SchemaResolutionException,
+                SourceException, ReactorException {
+            final Map<SourceIdentifier, ASTSchemaSource> srcs =
+                    Maps.uniqueIndex(sources, ASTSchemaSource.GET_IDENTIFIER);
+            final Map<SourceIdentifier, YangModelDependencyInfo> deps =
+                    Maps.transformValues(srcs, ASTSchemaSource.GET_DEPINFO);
+
+            LOG.debug("Resolving dependency reactor {}", deps);
+
+            final DependencyResolver res = DependencyResolver.create(deps);
+            if (!res.getUnresolvedSources().isEmpty()) {
+                LOG.debug("Omitting models {} due to unsatisfied imports {}", res.getUnresolvedSources(), res.getUnsatisfiedImports());
+                throw new SchemaResolutionException("Failed to resolve required models",
+                        res.getResolvedSources(), res.getUnsatisfiedImports());
+            }
+
+            final Map<SourceIdentifier, ParserRuleContext> asts = Maps.transformValues(srcs, ASTSchemaSource.GET_AST);
+            final CrossSourceStatementReactor.BuildAction reactor =
+                    YangInferencePipeline.RFC6020_REACTOR.newBuild(isFeatureSupported);
+
+            for (final Entry<SourceIdentifier, ParserRuleContext> e : asts.entrySet()) {
+                final ParserRuleContext parserRuleCtx = e.getValue();
+                Preconditions.checkArgument(parserRuleCtx instanceof StatementContext,
+                        "Unsupported context class %s for source %s", parserRuleCtx.getClass(), e.getKey());
+
+                reactor.addSource(new YangStatementSourceImpl(e.getKey(), (StatementContext) parserRuleCtx));
+            }
+
+            SchemaContext schemaContext = reactor.buildEffective();
+
+            return Futures.immediateCheckedFuture(schemaContext);
+        }
+    }
 }
index 05b7f67c333ceab95ede69325755457f7db658c5..fd15851a2fccbaf791d55eb168aef2bb48765e92 100644 (file)
@@ -12,13 +12,21 @@ import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Set;
+import java.util.function.Predicate;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.KeyStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
+import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase;
 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl;
 
 public final class StmtContextUtils {
@@ -223,4 +231,28 @@ public final class StmtContextUtils {
         // This makes sure we reuse the collection when a grouping is instantiated in the same module
         return replaced ? builder.build() : keyStmtCtx.getStatementArgument();
     }
+
+    public static boolean areFeaturesSupported(final StmtContext<?, ?, ?> stmtContext) {
+        Predicate<QName> isFeatureSupported = stmtContext.getFromNamespace(SupportedFeaturesNamespace.class,
+                SupportedFeatures.SUPPORTED_FEATURES);
+        Collection<StatementContextBase<?, ?, ?>> substatements = new ArrayList<>();
+        substatements.addAll(stmtContext.declaredSubstatements());
+        substatements.addAll(stmtContext.effectiveSubstatements());
+
+        boolean isSupported = false;
+        boolean containsIfFeature = false;
+        for (StatementContextBase<?, ?, ?> stmt: substatements) {
+            if (stmt.getPublicDefinition().equals(Rfc6020Mapping.IF_FEATURE)) {
+                containsIfFeature = true;
+                if (isFeatureSupported.test((QName) stmt.getStatementArgument())) {
+                    isSupported = true;
+                } else {
+                    isSupported = false;
+                    break;
+                }
+            }
+        }
+
+        return !containsIfFeature || isSupported;
+    }
 }
diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/SupportedFeaturesNamespace.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/spi/source/SupportedFeaturesNamespace.java
new file mode 100644 (file)
index 0000000..ac2632c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2016 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.spi.source;
+
+import java.util.function.Predicate;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
+
+public interface SupportedFeaturesNamespace
+        extends IdentifierNamespace<SupportedFeaturesNamespace.SupportedFeatures, Predicate<QName>> {
+
+    enum SupportedFeatures {
+        SUPPORTED_FEATURES
+    }
+}
index 66c29cd328ac62cbc98d1f10793a756a835d0a02..4ab08c5cdf2036d52391e0eb8d86a464dbd4e4f9 100644 (file)
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Predicate;
 import javax.annotation.Nonnull;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
@@ -39,6 +40,8 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupportBundle;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.SourceSpecificContext.PhaseCompletionProgress;
@@ -66,18 +69,25 @@ class BuildGlobalContext extends NamespaceStorageSupport implements NamespaceBeh
     private ModelProcessingPhase currentPhase = ModelProcessingPhase.INIT;
     private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT;
 
-    public BuildGlobalContext(final Map<ModelProcessingPhase, StatementSupportBundle> supports) {
+    public BuildGlobalContext(final Map<ModelProcessingPhase, StatementSupportBundle> supports,
+                              final Predicate<QName> isFeatureSupported) {
         super();
         this.supports = Preconditions.checkNotNull(supports, "BuildGlobalContext#supports cannot be null");
+
+        addToNs(SupportedFeaturesNamespace.class, SupportedFeatures.SUPPORTED_FEATURES, isFeatureSupported);
     }
 
-    public BuildGlobalContext(final Map<ModelProcessingPhase, StatementSupportBundle> supports, final Map<ValidationBundleType,Collection<?>> supportedValidation) {
+    public BuildGlobalContext(final Map<ModelProcessingPhase, StatementSupportBundle> supports,
+                              final Map<ValidationBundleType,Collection<?>> supportedValidation,
+                              final Predicate<QName> isFeatureSupported) {
         super();
         this.supports = Preconditions.checkNotNull(supports, "BuildGlobalContext#supports cannot be null");
 
         for (Entry<ValidationBundleType, Collection<?>> validationBundle : supportedValidation.entrySet()) {
             addToNs(ValidationBundlesNamespace.class, validationBundle.getKey(), validationBundle.getValue());
         }
+
+        addToNs(SupportedFeaturesNamespace.class, SupportedFeatures.SUPPORTED_FEATURES, isFeatureSupported);
     }
 
     public StatementSupportBundle getSupportsForPhase(final ModelProcessingPhase currentPhase) {
index e037ae534be63d2b67430e5dbf752213a664813d..9873466b3040976c6fc0350f61939aaab7e01b00 100644 (file)
@@ -7,6 +7,7 @@
  */
 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.File;
@@ -20,6 +21,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Predicate;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
@@ -51,7 +54,11 @@ public class CrossSourceStatementReactor {
     }
 
     public final BuildAction newBuild() {
-        return new BuildAction();
+        return newBuild(t -> true);
+    }
+
+    public final BuildAction newBuild(final Predicate<QName> isFeatureSupported) {
+        return new BuildAction(isFeatureSupported);
     }
 
     public static class Builder implements org.opendaylight.yangtools.concepts.Builder<CrossSourceStatementReactor>{
@@ -80,7 +87,12 @@ public class CrossSourceStatementReactor {
         private final BuildGlobalContext context;
 
         public BuildAction() {
-            this.context = new BuildGlobalContext(supportedTerminology, supportedValidation);
+            this(t -> true);
+        }
+
+        public BuildAction(Predicate<QName> isFeatureSupported) {
+            Preconditions.checkNotNull(isFeatureSupported);
+            this.context = new BuildGlobalContext(supportedTerminology, supportedValidation, isFeatureSupported);
         }
 
         public void addSource(final StatementStreamSource source) {
index 0638d31abdbe763935d0b09c741ecca899df3d1f..97edbf247dbfd06824737354273f1cc982fb4110 100644 (file)
@@ -90,6 +90,10 @@ public class AugmentStatementImpl extends AbstractDeclaredStatement<SchemaNodeId
         @Override
         public void onFullDefinitionDeclared(
                 final StmtContext.Mutable<SchemaNodeIdentifier, AugmentStatement, EffectiveStatement<SchemaNodeIdentifier, AugmentStatement>> augmentNode) {
+            if (!StmtContextUtils.areFeaturesSupported(augmentNode)) {
+                return;
+            }
+
             SUBSTATEMENT_VALIDATOR.validate(augmentNode);
 
             if (StmtContextUtils.isInExtensionBody(augmentNode)) {
@@ -107,7 +111,8 @@ public class AugmentStatementImpl extends AbstractDeclaredStatement<SchemaNodeId
                 @Override
                 public void apply() {
                     final StatementContextBase<?, ?, ?> augmentTargetCtx = (StatementContextBase<?, ?, ?>) target.get();
-                    if (!AugmentUtils.isSupportedAugmentTarget(augmentTargetCtx) || StmtContextUtils.isInExtensionBody(augmentTargetCtx)) {
+                    if (!AugmentUtils.isSupportedAugmentTarget(augmentTargetCtx)
+                            || StmtContextUtils.isInExtensionBody(augmentTargetCtx)) {
                         augmentNode.setIsSupportedToBuildEffective(false);
                         return;
                     }
index f7979c4f01bd71daf82b5f1c050b6ee9e696354a..92083c435ec472f1d68e4ab9bb321ad6604a3cb2 100644 (file)
@@ -71,6 +71,10 @@ public class UsesStatementImpl extends AbstractDeclaredStatement<QName> implemen
         @Override
         public void onFullDefinitionDeclared(
                 final StmtContext.Mutable<QName, UsesStatement, EffectiveStatement<QName, UsesStatement>> usesNode) {
+            if (!StmtContextUtils.areFeaturesSupported(usesNode)) {
+                return;
+            }
+
             SUBSTATEMENT_VALIDATOR.validate(usesNode);
 
             if (StmtContextUtils.isInExtensionBody(usesNode)) {
@@ -104,7 +108,7 @@ public class UsesStatementImpl extends AbstractDeclaredStatement<QName> implemen
                 @Override
                 public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
                     InferenceException.throwIf(failed.contains(sourceGroupingPre),
-                        usesNode.getStatementSourceReference(), "Grouping '%s' was not resolved.", groupingName);
+                            usesNode.getStatementSourceReference(), "Grouping '%s' was not resolved.", groupingName);
                     throw new InferenceException("Unknown error occurred.", usesNode.getStatementSourceReference());
                 }
             });
index 7255a7165af08f24bddae56d05be8e24d0c2ecf5..bbb52f6e9a93d1b1dec0956cc9cc587efa2e9b5b 100644 (file)
@@ -41,6 +41,7 @@ import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName
 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
 import org.opendaylight.yangtools.yang.parser.spi.source.StmtOrderingNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.validation.ValidationBundlesNamespace.ValidationBundleType;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
@@ -49,6 +50,7 @@ public final class YangInferencePipeline {
 
     public static final StatementSupportBundle INIT_BUNDLE = StatementSupportBundle
             .builder().addSupport(global(ValidationBundlesNamespace.class))
+            .addSupport(global(SupportedFeaturesNamespace.class))
             .build();
 
     public static final StatementSupportBundle PRE_LINKAGE_BUNDLE = StatementSupportBundle
index 8b9409578116dc2bdc3bf1eae13bf2a5130dd8a7..15888ae5906beac36a4f6a37fff79c854c09b1b7 100644 (file)
@@ -45,6 +45,15 @@ public abstract class EffectiveStatementBase<A, D extends DeclaredStatement<A>>
         }
     };
 
+    private static final Predicate<StmtContext<?, ?, ?>> ARE_FEATURES_SUPPORTED =
+            new Predicate<StmtContext<?, ?, ?>>() {
+
+                @Override
+                public boolean apply(StmtContext<?, ?, ?> input) {
+                    return StmtContextUtils.areFeaturesSupported(input);
+                }
+            };
+
     private final List<? extends EffectiveStatement<?, ?>> substatements;
     private final List<StatementContextBase<?, ?, ?>> unknownSubstatementsToBuild;
 
@@ -92,6 +101,8 @@ public abstract class EffectiveStatementBase<A, D extends DeclaredStatement<A>>
             this.unknownSubstatementsToBuild = ImmutableList.of();
         }
 
+        substatementsToBuild = Collections2.filter(substatementsToBuild, ARE_FEATURES_SUPPORTED);
+
         Function<StmtContext<?, ?, ? extends EffectiveStatement<?, ?>>, EffectiveStatement<?, ?>> buildEffective = StmtContextUtils.buildEffective();
         this.substatements = ImmutableList.copyOf(Collections2.transform(substatementsToBuild, buildEffective));
     }
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryWithFeaturesTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/repo/SharedSchemaRepositoryWithFeaturesTest.java
new file mode 100644 (file)
index 0000000..18b6fa7
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016 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.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+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.SchemaResolutionException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceFilter;
+import org.opendaylight.yangtools.yang.parser.util.ASTSchemaSource;
+import org.opendaylight.yangtools.yang.parser.util.TextToASTTransformer;
+
+public class SharedSchemaRepositoryWithFeaturesTest {
+
+    @Test
+    public void testSharedSchemaRepositoryWithSomeFeaturesSupported() throws Exception {
+        Predicate<QName> isFeatureSupported = qName -> {
+            Set<QName> supportedFeatures = new HashSet<>();
+            supportedFeatures.add(QName.create("foobar-namespace", "1970-01-01", "test-feature-1"));
+
+            return supportedFeatures.contains(qName);
+        };
+
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository(
+                "shared-schema-repo-with-features-test");
+
+        final SettableSchemaProvider<ASTSchemaSource> foobar = getImmediateYangSourceProviderFromResource
+                ("/if-feature-resolution-test/shared-schema-repository/foobar.yang");
+        foobar.register(sharedSchemaRepository);
+        foobar.setResult();
+
+        final SchemaContextFactory fact = sharedSchemaRepository
+                .createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> testSchemaContextFuture =
+                fact.createSchemaContext(Lists.newArrayList(foobar.getId()), isFeatureSupported);
+        assertTrue(testSchemaContextFuture.isDone());
+        assertSchemaContext(testSchemaContextFuture.checkedGet(), 1);
+
+        Module module = testSchemaContextFuture.checkedGet().findModuleByName("foobar", null);
+        assertNotNull(module);
+        assertEquals(2, module.getChildNodes().size());
+
+        ContainerSchemaNode testContainerA = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-a"));
+        assertNotNull(testContainerA);
+        LeafSchemaNode testLeafA = (LeafSchemaNode) testContainerA.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-leaf-a"));
+        assertNotNull(testLeafA);
+
+        ContainerSchemaNode testContainerB = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-b"));
+        assertNull(testContainerB);
+
+        ContainerSchemaNode testContainerC = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-c"));
+        assertNotNull(testContainerC);
+        LeafSchemaNode testLeafC = (LeafSchemaNode) testContainerC.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-leaf-c"));
+        assertNotNull(testLeafC);
+    }
+
+    @Test
+    public void testSharedSchemaRepositoryWithAllFeaturesSupported() throws Exception {
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository(
+                "shared-schema-repo-with-features-test");
+
+        final SettableSchemaProvider<ASTSchemaSource> foobar = getImmediateYangSourceProviderFromResource
+                ("/if-feature-resolution-test/shared-schema-repository/foobar.yang");
+        foobar.register(sharedSchemaRepository);
+        foobar.setResult();
+
+        final SchemaContextFactory fact = sharedSchemaRepository
+                .createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> testSchemaContextFuture = fact
+                .createSchemaContext(Lists.newArrayList(foobar.getId()));
+        assertTrue(testSchemaContextFuture.isDone());
+        assertSchemaContext(testSchemaContextFuture.checkedGet(), 1);
+
+        Module module = testSchemaContextFuture.checkedGet().findModuleByName("foobar", null);
+        assertNotNull(module);
+        assertEquals(3, module.getChildNodes().size());
+
+        ContainerSchemaNode testContainerA = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-a"));
+        assertNotNull(testContainerA);
+        LeafSchemaNode testLeafA = (LeafSchemaNode) testContainerA.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-leaf-a"));
+        assertNotNull(testLeafA);
+
+        ContainerSchemaNode testContainerB = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-b"));
+        assertNotNull(testContainerB);
+        LeafSchemaNode testLeafB = (LeafSchemaNode) testContainerB.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-leaf-b"));
+        assertNotNull(testLeafB);
+
+        ContainerSchemaNode testContainerC = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-c"));
+        assertNotNull(testContainerC);
+        LeafSchemaNode testLeafC = (LeafSchemaNode) testContainerC.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-leaf-c"));
+        assertNotNull(testLeafC);
+    }
+
+    @Test
+    public void testSharedSchemaRepositoryWithNoFeaturesSupported() throws Exception {
+        Predicate<QName> isFeatureSupported = qName -> false;
+
+        final SharedSchemaRepository sharedSchemaRepository = new SharedSchemaRepository(
+                "shared-schema-repo-with-features-test");
+
+        final SettableSchemaProvider<ASTSchemaSource> foobar = getImmediateYangSourceProviderFromResource
+                ("/if-feature-resolution-test/shared-schema-repository/foobar.yang");
+        foobar.register(sharedSchemaRepository);
+        foobar.setResult();
+
+        final SchemaContextFactory fact = sharedSchemaRepository
+                .createSchemaContextFactory(SchemaSourceFilter.ALWAYS_ACCEPT);
+
+        final CheckedFuture<SchemaContext, SchemaResolutionException> testSchemaContextFuture = fact
+                .createSchemaContext(Lists.newArrayList(foobar.getId()), isFeatureSupported);
+        assertTrue(testSchemaContextFuture.isDone());
+        assertSchemaContext(testSchemaContextFuture.checkedGet(), 1);
+
+        Module module = testSchemaContextFuture.checkedGet().findModuleByName("foobar", null);
+        assertNotNull(module);
+        assertEquals(1, module.getChildNodes().size());
+
+        ContainerSchemaNode testContainerC = (ContainerSchemaNode) module.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-container-c"));
+        assertNotNull(testContainerC);
+        LeafSchemaNode testLeafC = (LeafSchemaNode) testContainerC.getDataChildByName(
+                QName.create(module.getQNameModule(), "test-leaf-c"));
+        assertNotNull(testLeafC);
+    }
+
+    private SettableSchemaProvider<ASTSchemaSource> getImmediateYangSourceProviderFromResource(
+            final String resourceName) throws Exception {
+        final ResourceYangSource yangSource = new ResourceYangSource(resourceName);
+        final CheckedFuture<ASTSchemaSource, SchemaSourceException> aSTSchemaSource = TextToASTTransformer.TRANSFORMATION.apply(yangSource);
+        return SettableSchemaProvider.createImmediate(aSTSchemaSource.get(), ASTSchemaSource.class);
+    }
+
+    private void assertSchemaContext(final SchemaContext schemaContext, final int moduleSize) {
+        assertNotNull(schemaContext);
+        assertEquals(moduleSize, schemaContext.getModules().size());
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/IfFeatureResolutionTest.java b/yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/stmt/IfFeatureResolutionTest.java
new file mode 100644 (file)
index 0000000..c26cb5a
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2016 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.stmt;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Predicate;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
+import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangInferencePipeline;
+import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceImpl;
+
+public class IfFeatureResolutionTest {
+
+    private static final StatementStreamSource FOO_MODULE =
+            new YangStatementSourceImpl("/if-feature-resolution-test/foo.yang", false);
+    private static final StatementStreamSource BAR_MODULE =
+            new YangStatementSourceImpl("/if-feature-resolution-test/bar.yang", false);
+
+    @Test
+    public void testSomeFeaturesSupported() throws ReactorException {
+        Predicate<QName> isFeatureSupported = qName -> {
+            Set<QName> supportedFeatures = new HashSet<>();
+            supportedFeatures.add(QName.create("foo-namespace", "1970-01-01", "test-feature-1"));
+            supportedFeatures.add(QName.create("foo-namespace", "1970-01-01", "test-feature-2"));
+            supportedFeatures.add(QName.create("foo-namespace", "1970-01-01", "test-feature-3"));
+            supportedFeatures.add(QName.create("bar-namespace", "1970-01-01", "imp-feature"));
+
+            return supportedFeatures.contains(qName);
+        };
+
+        CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(isFeatureSupported);
+        reactor.addSources(FOO_MODULE, BAR_MODULE);
+
+        SchemaContext schemaContext = reactor.buildEffective();
+        assertNotNull(schemaContext);
+
+        Module testModule = schemaContext.findModuleByName("foo", null);
+        assertNotNull(testModule);
+
+        assertEquals(9, testModule.getChildNodes().size());
+
+        ContainerSchemaNode testContainerA = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-a"));
+        assertNull(testContainerA);
+
+        ContainerSchemaNode testContainerB = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-b"));
+        assertNotNull(testContainerB);
+        LeafSchemaNode testLeafB = (LeafSchemaNode) testContainerB.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-b"));
+        assertNotNull(testLeafB);
+
+        ContainerSchemaNode testContainerC = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-c"));
+        assertNotNull(testContainerC);
+        LeafSchemaNode testLeafC = (LeafSchemaNode) testContainerC.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-c"));
+        assertNotNull(testLeafC);
+
+        ContainerSchemaNode testContainerD = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-d"));
+        assertNull(testContainerD);
+
+        ContainerSchemaNode testContainerE = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-e"));
+        assertNotNull(testContainerE);
+        ContainerSchemaNode testSubContainerE = (ContainerSchemaNode) testContainerE.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subcontainer-e"));
+        assertNotNull(testSubContainerE);
+        LeafSchemaNode testLeafE = (LeafSchemaNode) testSubContainerE.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-e"));
+        assertNull(testLeafE);
+
+        ContainerSchemaNode testContainerF = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-f"));
+        assertNotNull(testContainerF);
+        ContainerSchemaNode testSubContainerF = (ContainerSchemaNode) testContainerF.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subcontainer-f"));
+        assertNull(testSubContainerF);
+
+        ContainerSchemaNode testContainerG = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-g"));
+        assertNotNull(testContainerG);
+        assertEquals(1, testContainerG.getAvailableAugmentations().size());
+        LeafSchemaNode testLeafG = (LeafSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-g"));
+        assertNotNull(testLeafG);
+        LeafSchemaNode augmentingTestLeafG = (LeafSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-leaf-g"));
+        assertNull(augmentingTestLeafG);
+        AnyXmlSchemaNode augmentingTestAnyxmlG = (AnyXmlSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-anyxml-g"));
+        assertNotNull(augmentingTestAnyxmlG);
+
+        ContainerSchemaNode testContainerH = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-h"));
+        assertNotNull(testContainerH);
+        assertEquals(0, testContainerH.getChildNodes().size());
+        assertEquals(0, testContainerH.getUses().size());
+
+        ContainerSchemaNode testContainerI = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-i"));
+        assertNotNull(testContainerI);
+        assertEquals(1, testContainerI.getUses().size());
+        ContainerSchemaNode testGroupingSubContainer = (ContainerSchemaNode) testContainerI.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        LeafSchemaNode testGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-leaf"));
+        assertNull(testGroupingLeaf);
+
+        ContainerSchemaNode testContainerJ = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-j"));
+        assertNotNull(testContainerJ);
+        LeafSchemaNode testLeafJ = (LeafSchemaNode) testContainerJ.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-j"));
+        assertNotNull(testLeafJ);
+
+        ContainerSchemaNode testContainerK = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-k"));
+        assertNotNull(testContainerK);
+        assertEquals(1, testContainerK.getUses().size());
+        testGroupingSubContainer = (ContainerSchemaNode) testContainerK.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        assertEquals(1, testGroupingSubContainer.getAvailableAugmentations().size());
+        LeafSchemaNode augmentingTestGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-grouping-leaf"));
+        assertNotNull(augmentingTestGroupingLeaf);
+        LeafSchemaNode augmentingTestGroupingLeaf2 = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-grouping-leaf-2"));
+        assertNull(augmentingTestGroupingLeaf2);
+    }
+
+    @Test
+    public void testAllFeaturesSupported() throws ReactorException {
+        CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild();
+        reactor.addSources(FOO_MODULE, BAR_MODULE);
+
+        SchemaContext schemaContext = reactor.buildEffective();
+        assertNotNull(schemaContext);
+
+        Module testModule = schemaContext.findModuleByName("foo", null);
+        assertNotNull(testModule);
+
+        assertEquals(11, testModule.getChildNodes().size());
+
+        ContainerSchemaNode testContainerA = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-a"));
+        assertNotNull(testContainerA);
+        LeafSchemaNode testLeafA = (LeafSchemaNode) testContainerA.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-a"));
+        assertNotNull(testLeafA);
+
+
+        ContainerSchemaNode testContainerB = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-b"));
+        assertNotNull(testContainerB);
+        LeafSchemaNode testLeafB = (LeafSchemaNode) testContainerB.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-b"));
+        assertNotNull(testLeafB);
+
+        ContainerSchemaNode testContainerC = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-c"));
+        assertNotNull(testContainerC);
+        LeafSchemaNode testLeafC = (LeafSchemaNode) testContainerC.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-c"));
+        assertNotNull(testLeafC);
+
+        ContainerSchemaNode testContainerD = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-d"));
+        assertNotNull(testContainerD);
+        LeafSchemaNode testLeafD = (LeafSchemaNode) testContainerD.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-d"));
+        assertNotNull(testLeafD);
+
+        ContainerSchemaNode testContainerE = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-e"));
+        assertNotNull(testContainerE);
+        ContainerSchemaNode testSubContainerE = (ContainerSchemaNode) testContainerE.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subcontainer-e"));
+        assertNotNull(testSubContainerE);
+        LeafSchemaNode testLeafE = (LeafSchemaNode) testSubContainerE.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-e"));
+        assertNotNull(testLeafE);
+
+        ContainerSchemaNode testContainerF = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-f"));
+        assertNotNull(testContainerF);
+        ContainerSchemaNode testSubContainerF = (ContainerSchemaNode) testContainerF.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subcontainer-f"));
+        assertNotNull(testSubContainerF);
+        ContainerSchemaNode testSubSubContainerF = (ContainerSchemaNode) testSubContainerF.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subsubcontainer-f"));
+        assertNotNull(testSubSubContainerF);
+        LeafSchemaNode testLeafF = (LeafSchemaNode) testSubSubContainerF.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-f"));
+        assertNotNull(testLeafF);
+
+        ContainerSchemaNode testContainerG = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-g"));
+        assertNotNull(testContainerG);
+        assertEquals(2, testContainerG.getAvailableAugmentations().size());
+        LeafSchemaNode testLeafG = (LeafSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-g"));
+        assertNotNull(testLeafG);
+        LeafSchemaNode augmentingTestLeafG = (LeafSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-leaf-g"));
+        assertNotNull(augmentingTestLeafG);
+        AnyXmlSchemaNode augmentingTestAnyxmlG = (AnyXmlSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-anyxml-g"));
+        assertNotNull(augmentingTestAnyxmlG);
+
+        ContainerSchemaNode testContainerH = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-h"));
+        assertNotNull(testContainerH);
+        assertEquals(1, testContainerH.getUses().size());
+        ContainerSchemaNode testGroupingSubContainer = (ContainerSchemaNode) testContainerH.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        LeafSchemaNode testGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-leaf"));
+        assertNotNull(testGroupingLeaf);
+
+        ContainerSchemaNode testContainerI = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-i"));
+        assertNotNull(testContainerI);
+        assertEquals(1, testContainerI.getUses().size());
+        testGroupingSubContainer = (ContainerSchemaNode) testContainerI.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        testGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-leaf"));
+        assertNotNull(testGroupingLeaf);
+
+        ContainerSchemaNode testContainerJ = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-j"));
+        assertNotNull(testContainerJ);
+        LeafSchemaNode testLeafJ = (LeafSchemaNode) testContainerJ.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-j"));
+        assertNotNull(testLeafJ);
+
+        ContainerSchemaNode testContainerK = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-k"));
+        assertNotNull(testContainerK);
+        assertEquals(1, testContainerK.getUses().size());
+        testGroupingSubContainer = (ContainerSchemaNode) testContainerK.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        assertEquals(1, testGroupingSubContainer.getAvailableAugmentations().size());
+        LeafSchemaNode augmentingTestGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-grouping-leaf"));
+        assertNotNull(augmentingTestGroupingLeaf);
+        LeafSchemaNode augmentingTestGroupingLeaf2 = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-grouping-leaf-2"));
+        assertNotNull(augmentingTestGroupingLeaf2);
+        testGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-leaf"));
+        assertNotNull(testGroupingLeaf);
+    }
+
+    @Test
+    public void testNoFeaturesSupported() throws ReactorException {
+        Predicate<QName> isFeatureSupported = qName -> false;
+
+        CrossSourceStatementReactor.BuildAction reactor = YangInferencePipeline.RFC6020_REACTOR.newBuild(isFeatureSupported);
+        reactor.addSources(FOO_MODULE, BAR_MODULE);
+
+        SchemaContext schemaContext = reactor.buildEffective();
+        assertNotNull(schemaContext);
+
+        Module testModule = schemaContext.findModuleByName("foo", null);
+        assertNotNull(testModule);
+
+        assertEquals(6, testModule.getChildNodes().size());
+
+        ContainerSchemaNode testContainerE = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-e"));
+        assertNotNull(testContainerE);
+        ContainerSchemaNode testSubContainerE = (ContainerSchemaNode) testContainerE.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subcontainer-e"));
+        assertNotNull(testSubContainerE);
+        LeafSchemaNode testLeafE = (LeafSchemaNode) testSubContainerE.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-e"));
+        assertNull(testLeafE);
+
+        ContainerSchemaNode testContainerF = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-f"));
+        assertNotNull(testContainerF);
+        ContainerSchemaNode testSubContainerF = (ContainerSchemaNode) testContainerF.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-subcontainer-f"));
+        assertNull(testSubContainerF);
+
+        ContainerSchemaNode testContainerG = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-g"));
+        assertNotNull(testContainerG);
+        assertEquals(1, testContainerG.getAvailableAugmentations().size());
+        LeafSchemaNode testLeafG = (LeafSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-leaf-g"));
+        assertNotNull(testLeafG);
+        LeafSchemaNode augmentingTestLeafG = (LeafSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-leaf-g"));
+        assertNull(augmentingTestLeafG);
+        AnyXmlSchemaNode augmentingTestAnyxmlG = (AnyXmlSchemaNode) testContainerG.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-anyxml-g"));
+        assertNotNull(augmentingTestAnyxmlG);
+
+        ContainerSchemaNode testContainerH = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-h"));
+        assertNotNull(testContainerH);
+        assertEquals(0, testContainerH.getChildNodes().size());
+        assertEquals(0, testContainerH.getUses().size());
+
+        ContainerSchemaNode testContainerI = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-i"));
+        assertNotNull(testContainerI);
+        assertEquals(1, testContainerI.getUses().size());
+        ContainerSchemaNode testGroupingSubContainer = (ContainerSchemaNode) testContainerI.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        LeafSchemaNode testGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-leaf"));
+        assertNull(testGroupingLeaf);
+
+        ContainerSchemaNode testContainerK = (ContainerSchemaNode) testModule.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-container-k"));
+        assertNotNull(testContainerK);
+        assertEquals(1, testContainerK.getUses().size());
+        testGroupingSubContainer = (ContainerSchemaNode) testContainerK.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-subcontainer"));
+        assertNotNull(testGroupingSubContainer);
+        assertEquals(1, testGroupingSubContainer.getAvailableAugmentations().size());
+        LeafSchemaNode augmentingTestGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-grouping-leaf"));
+        assertNull(augmentingTestGroupingLeaf);
+        LeafSchemaNode augmentingTestGroupingLeaf2 = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "augmenting-test-grouping-leaf-2"));
+        assertNull(augmentingTestGroupingLeaf2);
+        testGroupingLeaf = (LeafSchemaNode) testGroupingSubContainer.getDataChildByName(
+                QName.create(testModule.getQNameModule(), "test-grouping-leaf"));
+        assertNull(testGroupingLeaf);
+    }
+}
diff --git a/yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/bar.yang b/yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/bar.yang
new file mode 100644 (file)
index 0000000..cbe1ab9
--- /dev/null
@@ -0,0 +1,10 @@
+module bar {
+    namespace "bar-namespace";
+    prefix "bar-prefix";
+
+    container bar-cont {
+        leaf bar-cont-leaf {
+            type string;
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/foo.yang b/yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/foo.yang
new file mode 100644 (file)
index 0000000..1688a31
--- /dev/null
@@ -0,0 +1,125 @@
+module foo {
+    namespace "foo-namespace";
+    prefix "foo-prefix";
+
+    import bar {
+        prefix br;
+    }
+
+    container test-container-a {
+        if-feature foo-feature;
+
+        leaf test-leaf-a {
+            type string;
+        }
+    }
+
+    container test-container-b {
+        if-feature test-feature-1;
+
+        leaf test-leaf-b {
+            type string;
+        }
+    }
+
+    container test-container-c {
+        if-feature test-feature-1;
+        if-feature test-feature-2;
+        if-feature test-feature-3;
+
+        leaf test-leaf-c {
+            type string;
+        }
+    }
+
+    container test-container-d {
+        if-feature test-feature-1;
+        if-feature test-feature-2;
+        if-feature foo-feature;
+        if-feature test-feature-3;
+
+        leaf test-leaf-d {
+            type string;
+        }
+    }
+
+    container test-container-e {
+        container test-subcontainer-e {
+            leaf test-leaf-e {
+                if-feature foo-feature;
+                type string;
+            }
+        }
+    }
+
+    container test-container-f {
+        container test-subcontainer-f {
+            if-feature foo-feature;
+            container test-subsubcontainer-f {
+                leaf test-leaf-f {
+                    type string;
+                }
+            }
+        }
+    }
+
+    container test-container-g {
+        leaf test-leaf-g {
+            type string;
+        }
+    }
+
+    container test-container-h {
+        uses test-grouping {
+            if-feature "foo-feature";
+        }
+    }
+
+    container test-container-i {
+        uses test-grouping;
+    }
+
+    container test-container-j {
+        if-feature br:imp-feature;
+
+        leaf test-leaf-j {
+            type string;
+        }
+    }
+
+    container test-container-k {
+        uses test-grouping {
+            augment "test-grouping-subcontainer" {
+                leaf augmenting-test-grouping-leaf {
+                    if-feature test-feature-1;
+                    type string;
+                }
+
+                leaf augmenting-test-grouping-leaf-2 {
+                    if-feature foo-feature;
+                    type string;
+                }
+            }
+        }
+    }
+
+    augment "/test-container-g" {
+        if-feature foo-feature;
+        leaf augmenting-test-leaf-g {
+            type string;
+        }
+    }
+
+    augment "/test-container-g" {
+        anyxml augmenting-test-anyxml-g;
+    }
+
+    grouping test-grouping {
+        container test-grouping-subcontainer {
+            leaf test-grouping-leaf {
+                if-feature foo-feature;
+                type string;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/shared-schema-repository/foobar.yang b/yang/yang-parser-impl/src/test/resources/if-feature-resolution-test/shared-schema-repository/foobar.yang
new file mode 100644 (file)
index 0000000..d839150
--- /dev/null
@@ -0,0 +1,26 @@
+module foobar {
+    namespace "foobar-namespace";
+    prefix "foobar-prefix";
+
+    container test-container-a {
+        if-feature test-feature-1;
+
+        leaf test-leaf-a {
+            type string;
+        }
+    }
+
+    container test-container-b {
+        if-feature foobar-feature;
+
+        leaf test-leaf-b {
+            type string;
+        }
+    }
+
+    container test-container-c {
+        leaf test-leaf-c {
+            type string;
+        }
+    }
+}
\ No newline at end of file