Merge "Bug 2512: Initial design of YANG statement meta-model."
authorRobert Varga <nite@hq.sk>
Fri, 13 Feb 2015 18:22:46 +0000 (18:22 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 13 Feb 2015 18:22:46 +0000 (18:22 +0000)
common/features-builder/pom.xml
common/parent/pom.xml
yang/yang-data-impl/src/main/java/org/opendaylight/yangtools/yang/data/impl/codec/SchemaTracker.java
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/AbstractSchemaContext.java [new file with mode: 0644]
yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/FilteringSchemaContextProxy.java [new file with mode: 0644]
yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaContextProxyTest.java [new file with mode: 0644]
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/SchemaContextImpl.java

index 0576893ad410ec94f90adad2ee13361ffbb779c5..e82bf929e9b54bf24d55d412b2aac77fe274f8aa 100644 (file)
                     <artifactId>maven-surefire-plugin</artifactId>
                     <configuration>
                         <dependenciesToScan>
-                            <dependency>org.opendaylight.yangtools:features-test</dependency>
+                            <dependency>org.opendaylight.odlparent:features-test</dependency>
                         </dependenciesToScan>
                     </configuration>
                 </plugin>
     <dependencies>
         <!-- test the features.xml -->
         <dependency>
-            <groupId>org.opendaylight.yangtools</groupId>
+            <groupId>org.opendaylight.odlparent</groupId>
             <artifactId>features-test</artifactId>
-            <version>0.7.0-SNAPSHOT</version>
+            <version>1.5.0-SNAPSHOT</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
index 812b59665b6bc28d03f66b6973ab993aaf55e7f9..d0e43ef25f2e4acf51af270696092dba4c700079 100644 (file)
             </plugin>
         </plugins>
     </reporting>
-
-
-    <!-- Note: we can not use variables for these URLs because we need to
-         be able to download the parent pom from the repository the first
-         time we go to use it (since it is in a different project).
-         To override the settings, use the "mirror" section of the
-         settings.xml. See http://maven.apache.org/settings.html -->
-    <repositories>
-        <!-- OpenDayLight Repo Mirror -->
-        <repository>
-            <id>opendaylight-mirror</id>
-            <name>opendaylight-mirror</name>
-            <url>http://nexus.opendaylight.org/content/groups/public/</url>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-            <releases>
-                <enabled>true</enabled>
-                <updatePolicy>never</updatePolicy>
-            </releases>
-        </repository>
-
-        <!-- OpenDayLight Snapshot artifact -->
-        <repository>
-            <id>opendaylight-snapshot</id>
-            <name>opendaylight-snapshot</name>
-            <url>http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/</url>
-            <snapshots>
-                <enabled>true</enabled>
-            </snapshots>
-            <releases>
-                <enabled>false</enabled>
-            </releases>
-        </repository>
-    </repositories>
 </project>
index 725c115afb76ab167624c0deb60ab65a326df5fb..134557b7c9e544ac1e6706138fc4c88581d95f79 100644 (file)
@@ -31,6 +31,7 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
@@ -58,6 +59,10 @@ public final class SchemaTracker {
             if(current instanceof DataNodeContainer) {
                 child = ((DataNodeContainer) current).getDataChildByName(qname);
 
+                if (child == null && current instanceof SchemaContext) {
+                    child = tryFindGroupings((SchemaContext) current, qname).orNull();
+                }
+
                 if(child == null && current instanceof SchemaContext) {
                     child = tryFindNotification((SchemaContext) current, qname)
                             .orNull();
@@ -70,7 +75,11 @@ public final class SchemaTracker {
             current = child;
         }
         Preconditions.checkArgument(current instanceof DataNodeContainer,"Schema path must point to container or list. Supplied path %s pointed to: %s",path,current);
-        this.root = (DataNodeContainer) current;
+        root = (DataNodeContainer) current;
+    }
+
+    private Optional<SchemaNode> tryFindGroupings(final SchemaContext ctx, final QName qname) {
+        return Optional.<SchemaNode> fromNullable(Iterables.find(ctx.getGroupings(), new SchemaNodePredicate(qname), null));
     }
 
     private Optional<SchemaNode> tryFindNotification(final SchemaContext ctx, final QName qname) {
@@ -113,12 +122,16 @@ public final class SchemaTracker {
         if(parent instanceof DataNodeContainer) {
             schema = ((DataNodeContainer)parent).getDataChildByName(qname);
 
+            if(schema == null && parent instanceof GroupingDefinition) {
+                schema = ((GroupingDefinition) parent);
+            }
+
             if(schema == null && parent instanceof NotificationDefinition) {
                 schema = ((NotificationDefinition) parent);
             }
         } else if(parent instanceof ChoiceNode) {
-            for(ChoiceCaseNode caze : ((ChoiceNode) parent).getCases()) {
-                DataSchemaNode potential = caze.getDataChildByName(qname);
+            for(final ChoiceCaseNode caze : ((ChoiceNode) parent).getCases()) {
+                final DataSchemaNode potential = caze.getDataChildByName(qname);
                 if(potential != null) {
                     schema = potential;
                     break;
@@ -193,11 +206,11 @@ public final class SchemaTracker {
         Preconditions.checkArgument(parent instanceof AugmentationTarget, "Augmentation not allowed under %s", parent);
         Preconditions.checkArgument(parent instanceof DataNodeContainer, "Augmentation allowed only in DataNodeContainer",parent);
         final AugmentationSchema schema = SchemaUtils.findSchemaForAugment((AugmentationTarget) parent, identifier.getPossibleChildNames());
-        HashSet<DataSchemaNode> realChildSchemas = new HashSet<>();
-        for(DataSchemaNode child : schema.getChildNodes()) {
+        final HashSet<DataSchemaNode> realChildSchemas = new HashSet<>();
+        for(final DataSchemaNode child : schema.getChildNodes()) {
             realChildSchemas.add(((DataNodeContainer) parent).getDataChildByName(child.getQName()));
         }
-        AugmentationSchema resolvedSchema = new AugmentationSchemaProxy(schema, realChildSchemas);
+        final AugmentationSchema resolvedSchema = new AugmentationSchemaProxy(schema, realChildSchemas);
         schemaStack.push(resolvedSchema);
         return resolvedSchema;
     }
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/AbstractSchemaContext.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/AbstractSchemaContext.java
new file mode 100644 (file)
index 0000000..e04d72a
--- /dev/null
@@ -0,0 +1,266 @@
+package org.opendaylight.yangtools.yang.model.util;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.collect.SetMultimap;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+
+public abstract class AbstractSchemaContext implements SchemaContext {
+
+    protected static final Supplier<TreeSet<Module>> MODULE_SET_SUPPLIER = new Supplier<TreeSet<Module>>() {
+        @Override
+        public TreeSet<Module> get() {
+            return new TreeSet<>(REVISION_COMPARATOR);
+        }
+    };
+
+    protected static final Comparator<Module> REVISION_COMPARATOR = new Comparator<Module>() {
+        @Override
+        public int compare(final Module o1, final Module o2) {
+            if (o2.getRevision() == null) {
+                return -1;
+            }
+
+            return o2.getRevision().compareTo(o1.getRevision());
+        }
+    };
+
+    /**
+     * @return yang sources where key is ModuleIdentifier
+     */
+    protected abstract Map<ModuleIdentifier, String> getIdentifiersToSources();
+
+    /**
+     * @return Map of modules where key is namespace
+     */
+    protected abstract SetMultimap<URI, Module> getNamespaceToModules();
+
+    /**
+     * @return Map of modules where key is name of module
+     */
+    protected abstract SetMultimap<String, Module> getNameToModules();
+
+    @Override
+    public Set<DataSchemaNode> getDataDefinitions() {
+        final Set<DataSchemaNode> dataDefs = new HashSet<>();
+        for (Module m : getModules()) {
+            dataDefs.addAll(m.getChildNodes());
+        }
+        return dataDefs;
+    }
+
+    @Override
+    public Set<NotificationDefinition> getNotifications() {
+        final Set<NotificationDefinition> notifications = new HashSet<>();
+        for (Module m : getModules()) {
+            notifications.addAll(m.getNotifications());
+        }
+        return notifications;
+    }
+
+    @Override
+    public Set<RpcDefinition> getOperations() {
+        final Set<RpcDefinition> rpcs = new HashSet<>();
+        for (Module m : getModules()) {
+            rpcs.addAll(m.getRpcs());
+        }
+        return rpcs;
+    }
+
+    @Override
+    public Set<ExtensionDefinition> getExtensions() {
+        final Set<ExtensionDefinition> extensions = new HashSet<>();
+        for (Module m : getModules()) {
+            extensions.addAll(m.getExtensionSchemaNodes());
+        }
+        return extensions;
+    }
+
+    @Override
+    public Module findModuleByName(final String name, final Date revision) {
+        for (final Module module : getNameToModules().get(name)) {
+            if (revision == null || revision.equals(module.getRevision())) {
+                return module;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public Set<Module> findModuleByNamespace(final URI namespace) {
+        final Set<Module> ret = getNamespaceToModules().get(namespace);
+        return ret == null ? Collections.<Module>emptySet() : ret;
+    }
+
+    @Override
+    public Module findModuleByNamespaceAndRevision(final URI namespace, final Date revision) {
+        if (namespace == null) {
+            return null;
+        }
+        for (Module module : findModuleByNamespace(namespace)) {
+            if (revision == null || revision.equals(module.getRevision())) {
+                return module;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        return false;
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return false;
+    }
+
+    @Override
+    public boolean isConfiguration() {
+        return false;
+    }
+
+    @Override
+    public ConstraintDefinition getConstraints() {
+        return null;
+    }
+
+    @Override
+    public QName getQName() {
+        return SchemaContext.NAME;
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return SchemaPath.ROOT;
+    }
+
+    @Override
+    public String getDescription() {
+        return null;
+    }
+
+    @Override
+    public String getReference() {
+        return null;
+    }
+
+    @Override
+    public Status getStatus() {
+        return Status.CURRENT;
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        final List<UnknownSchemaNode> result = new ArrayList<>();
+        for (Module module : getModules()) {
+            result.addAll(module.getUnknownSchemaNodes());
+        }
+        return Collections.unmodifiableList(result);
+    }
+
+    @Override
+    public Set<TypeDefinition<?>> getTypeDefinitions() {
+        final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
+        for (Module module : getModules()) {
+            result.addAll(module.getTypeDefinitions());
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    @Override
+    public Set<DataSchemaNode> getChildNodes() {
+        final Set<DataSchemaNode> result = new LinkedHashSet<>();
+        for (Module module : getModules()) {
+            result.addAll(module.getChildNodes());
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        final Set<GroupingDefinition> result = new LinkedHashSet<>();
+        for (Module module : getModules()) {
+            result.addAll(module.getGroupings());
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final QName name) {
+        for (Module module : getModules()) {
+            final DataSchemaNode result = module.getDataChildByName(name);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final String name) {
+        for (Module module : getModules()) {
+            final DataSchemaNode result = module.getDataChildByName(name);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Set<UsesNode> getUses() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public boolean isPresenceContainer() {
+        return false;
+    }
+
+    @Override
+    public Set<AugmentationSchema> getAvailableAugmentations() {
+        return Collections.emptySet();
+    }
+
+    //FIXME: should work for submodules too
+    @Override
+    public Set<ModuleIdentifier> getAllModuleIdentifiers() {
+        return getIdentifiersToSources().keySet();
+    }
+
+    @Override
+    public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
+        String maybeSource = getIdentifiersToSources().get(moduleIdentifier);
+        return Optional.fromNullable(maybeSource);
+    }
+
+}
diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/FilteringSchemaContextProxy.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/FilteringSchemaContextProxy.java
new file mode 100644 (file)
index 0000000..3421cad
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015 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.html
+ */
+
+package org.opendaylight.yangtools.yang.model.util;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.TreeMultimap;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+@Immutable
+public final class FilteringSchemaContextProxy extends AbstractSchemaContext {
+
+    //collection to be filled with filtered modules
+    private final Set<Module> filteredModules;
+
+    //collections to be filled in with filtered data
+    private final Map<ModuleIdentifier, String> identifiersToSources;
+    private final SetMultimap<URI, Module> namespaceToModules;
+    private final SetMultimap<String, Module> nameToModules;
+
+    /**
+     * Filters SchemaContext for yang modules
+     *
+     * @param delegate original SchemaContext
+     * @param rootModules modules (yang schemas) to be available and all their dependencies (modules importing rootModule and whole chain of their imports)
+     * @param additionalModuleIds (additional) modules (yang schemas) to be available and whole chain of their imports
+     *
+     */
+    public FilteringSchemaContextProxy(final SchemaContext delegate, final Collection<ModuleId> rootModules, final Set<ModuleId> additionalModuleIds) {
+
+        Preconditions.checkArgument(rootModules!=null,"Base modules cannot be null.");
+        Preconditions.checkArgument(additionalModuleIds!=null,"Additional modules cannot be null.");
+
+        final Builder<Module> filteredModulesBuilder = new Builder<>();
+
+        final SetMultimap<URI, Module> nsMap = Multimaps.newSetMultimap(new TreeMap<URI, Collection<Module>>(), MODULE_SET_SUPPLIER);
+        final SetMultimap<String, Module> nameMap = Multimaps.newSetMultimap(new TreeMap<String, Collection<Module>>(), MODULE_SET_SUPPLIER);
+
+        ImmutableMap.Builder<ModuleIdentifier, String> identifiersToSourcesBuilder = ImmutableMap.builder();
+
+        //preparing map to get all modules with one name but difference in revision
+        final TreeMultimap<String, Module> nameToModulesAll = getStringModuleTreeMultimap();
+
+        nameToModulesAll.putAll(getStringModuleMap(delegate));
+
+        //in case there is a particular dependancy to view filteredModules/yang models
+        //dependancy is checked for module name and imports
+        processForRootModules(delegate, rootModules, filteredModulesBuilder);
+
+        //adding additional modules
+        processForAdditionalModules(delegate, additionalModuleIds, filteredModulesBuilder);
+
+        filteredModulesBuilder.addAll(getImportedModules(
+                Maps.uniqueIndex(delegate.getModules(), ModuleId.MODULE_TO_MODULE_ID), filteredModulesBuilder.build(), nameToModulesAll));
+
+        /**
+         * Instead of doing this on each invocation of getModules(), pre-compute
+         * it once and keep it around -- better than the set we got in.
+         */
+        this.filteredModules = filteredModulesBuilder.build();
+
+        for (final Module module :filteredModules) {
+            nameMap.put(module.getName(), module);
+            nsMap.put(module.getNamespace(), module);
+            identifiersToSourcesBuilder.put(module, module.getSource());
+        }
+
+        namespaceToModules = ImmutableSetMultimap.copyOf(nsMap);
+        nameToModules = ImmutableSetMultimap.copyOf(nameMap);
+        identifiersToSources = identifiersToSourcesBuilder.build();
+    }
+
+    private static TreeMultimap<String, Module> getStringModuleTreeMultimap() {
+        return TreeMultimap.create(new Comparator<String>() {
+                @Override
+                public int compare(String o1, String o2) {
+                    return o1.compareTo(o2);
+                }
+            }, REVISION_COMPARATOR);
+    }
+
+    private void processForAdditionalModules(SchemaContext delegate, final Set<ModuleId> additionalModuleIds, Builder<Module> filteredModulesBuilder) {
+        filteredModulesBuilder.addAll(Collections2.filter(delegate.getModules(), new Predicate<Module>() {
+            @Override
+            public boolean apply(@Nullable Module module) {
+                return selectAdditionalModules(module, additionalModuleIds);
+            }
+        }));
+    }
+
+    private void processForRootModules(SchemaContext delegate, final Collection<ModuleId> rootModules, Builder<Module> filteredModulesBuilder) {
+        filteredModulesBuilder.addAll(Collections2.filter(delegate.getModules(), new Predicate<Module>() {
+            @Override
+            public boolean apply(@Nullable Module module) {
+                return checkModuleDependency(module, rootModules);
+            }
+        }));
+    }
+
+    private Multimap<String, Module> getStringModuleMap(SchemaContext delegate) {
+        return Multimaps.index(delegate.getModules(), new Function<Module, String>() {
+            @Override
+            public String apply(Module input) {
+                return input.getName();
+            }
+        });
+    }
+
+    //dealing with imported module other than root and directly importing root
+    private static Collection<Module> getImportedModules(Map<ModuleId, Module> allModules, Set<Module> baseModules, TreeMultimap<String, Module> nameToModulesAll) {
+
+        List<Module> relatedModules = Lists.newLinkedList();
+
+        for (Module module : baseModules) {
+            for (ModuleImport moduleImport : module.getImports()) {
+
+                Date revisionDate = moduleImport.getRevision() == null ?
+                        nameToModulesAll.get(moduleImport.getModuleName()).first().getRevision() : moduleImport.getRevision();
+
+                ModuleId key = new ModuleId(moduleImport.getModuleName(),revisionDate);
+                Module importedModule = allModules.get(key);
+
+                Preconditions.checkArgument(importedModule != null,  "Invalid schema, cannot find imported module: %s from module: %s, %s, modules:%s", key, module.getQNameModule(), module.getName() );
+                relatedModules.add(importedModule);
+
+                //calling imports recursive
+                relatedModules.addAll(getImportedModules(allModules, Collections.singleton(importedModule), nameToModulesAll));
+
+            }
+        }
+
+        return relatedModules;
+    }
+
+    @Override
+    protected Map<ModuleIdentifier, String> getIdentifiersToSources() {
+        return identifiersToSources;
+    }
+
+    public Set<Module> getModules() {
+        return filteredModules;
+    }
+
+    @Override
+    protected SetMultimap<URI, Module> getNamespaceToModules() {
+        return namespaceToModules;
+    }
+
+    @Override
+    protected SetMultimap<String, Module> getNameToModules() {
+        return nameToModules;
+    }
+
+    private boolean selectAdditionalModules(Module module, Set<ModuleId> additionalModules){
+
+        if(additionalModules.contains(new ModuleId(module.getName(), module.getRevision()))){
+
+            return true;
+        }
+
+        return false;
+    };
+
+    //check for any dependency regarding given string
+    private boolean checkModuleDependency(Module module, Collection<ModuleId> rootModules) {
+
+        for (ModuleId rootModule : rootModules) {
+
+            if(rootModule.equals(new ModuleId(module.getName(), module.getRevision()))) {
+                return true;
+            }
+
+            //handling/checking imports regarding root modules
+            for (ModuleImport moduleImport : module.getImports()) {
+
+                if(moduleImport.getModuleName().equals(rootModule.getName())) {
+
+                    if(moduleImport.getRevision() != null && !moduleImport.getRevision().equals(rootModule.getRev())) {
+                        return false;
+                    }
+
+                    return true;
+                }
+            }
+
+            //submodules handling
+            for (Module moduleSub : module.getSubmodules()) {
+                return checkModuleDependency(moduleSub, rootModules);
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("SchemaContextProxyImpl{filteredModules=%s}", filteredModules);
+    }
+
+    public static final class ModuleId {
+        private final String name;
+        private final Date rev;
+
+        public ModuleId(String name, Date rev) {
+            Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "No module dependency name given. Nothing to do.");
+            this.name = name;
+            this.rev = Preconditions.checkNotNull(rev, "No revision date given. Nothing to do.");
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Date getRev() {
+            return rev;
+        }
+
+        public static final Function<Module, ModuleId> MODULE_TO_MODULE_ID = new Function<Module, ModuleId>() {
+            @Override
+            public ModuleId apply(Module input) {
+                return new ModuleId(input.getName(), input.getRevision());
+            }
+        };
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            ModuleId moduleId = (ModuleId) o;
+
+            if (name != null ? !name.equals(moduleId.name) : moduleId.name != null) return false;
+            if (rev != null ? !rev.equals(moduleId.rev) : moduleId.rev != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name != null ? name.hashCode() : 0;
+            result = 31 * result + (rev != null ? rev.hashCode() : 0);
+            return result;
+        }
+
+        @Override
+        public String toString() {
+
+            return String.format("ModuleId{name='%s', rev=%s}",name,rev);
+        }
+    }
+}
diff --git a/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaContextProxyTest.java b/yang/yang-model-util/src/test/java/org/opendaylight/yangtools/yang/model/util/SchemaContextProxyTest.java
new file mode 100644 (file)
index 0000000..e9a34d8
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2015 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.html
+ */
+
+package org.opendaylight.yangtools.yang.model.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.Sets;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.util.FilteringSchemaContextProxy.ModuleId;
+
+public class SchemaContextProxyTest {
+
+    private static URI namespace;
+    private static Date revision;
+    private static Date revision2;
+
+    private static final String CONFIG_NAME = "config";
+    private static final String ROOT_NAME = "root";
+    private static final String MODULE2_NAME = "module2";
+    private static final String MODULE3_NAME = "module3";
+    private static final String MODULE4_NAME = "module4";
+    private static final String MODULE41_NAME = "module41";
+    private static final String MODULE5_NAME = "module5";
+    private static final String TEST_SOURCE = "test source";
+
+    @BeforeClass
+    public static void setUp() throws ParseException, URISyntaxException {
+
+        namespace = new URI("urn:opendaylight:params:xml:ns:yang:controller:config");
+
+        revision = SimpleDateFormatUtil.getRevisionFormat().parse("2015-01-01");
+        revision2 = SimpleDateFormatUtil.getRevisionFormat().parse("2015-01-15");
+    }
+
+    private SchemaContext mockSchema(Module... module) {
+
+        SchemaContext mock = mock(SchemaContext.class);
+        doReturn(Sets.newHashSet(module)).when(mock).getModules();
+        return mock;
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     *  | \
+     *  |  \
+     * M2 <- M3
+     * </pre>
+     */
+    @Test
+    public void testBasic() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module2, moduleConfig);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3);
+    }
+
+    /**
+     * <pre>
+     * No root or additional modules
+     *  | \
+     *  |  \
+     * M2 <- M3
+     * </pre>
+     */
+    @Test
+    public void testNull() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module2, moduleConfig);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, null);
+        assertProxyContext(filteringSchemaContextProxy, null);
+    }
+
+    /**
+     * <pre>
+     *  Config
+     *  | \ (NR)
+     *  |  \
+     * M2 <- M3
+     * </pre>
+     */
+    @Test
+    public void testConfigDifferentRevisions() {
+        Module moduleConfigNullRevision = mockModule(CONFIG_NAME, null);
+        Module moduleConfig = mockModule(CONFIG_NAME, revision);
+        Module moduleConfig2 = mockModule(CONFIG_NAME, revision2);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module2, moduleConfigNullRevision);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, moduleConfig2, module2, module3);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, moduleConfig2, module2, module3);
+    }
+
+    /**
+     * <pre>
+     *     CFG(R)
+     *    |      \
+     *   |         \
+     * M2<-(NullRev)M3
+     * </pre>
+     */
+    @Test
+    public void testBasicNullRevision() throws Exception {
+        Module moduleConfig = mockModule(CONFIG_NAME,SimpleDateFormatUtil.getRevisionFormat().parse("2013-04-05"));
+        Module module2 = mockModule(MODULE2_NAME, SimpleDateFormatUtil.getRevisionFormat().parse("2014-06-17"));
+        Module module20 = mockModule(MODULE2_NAME, null);
+        Module module3 = mockModule(MODULE3_NAME, SimpleDateFormatUtil.getRevisionFormat().parse("2014-06-12"));
+        Module module30 = mockModule(MODULE3_NAME, null);
+
+        mockModuleImport(module20, moduleConfig);
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module20, moduleConfig);
+        mockModuleImport(module30, module20, moduleConfig);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)   ROOT(R)
+     *  |         \
+     *  |          \
+     * M2          M3
+     * </pre>
+     */
+    @Test
+    public void testBasicMoreRootModules() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module moduleRoot = mockModule(ROOT_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, moduleRoot);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, moduleRoot, module2, module3);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleRoot, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleRoot, module3, moduleConfig, module2);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     *  |
+     *  |
+     * M2 <- M3
+     * </pre>
+     */
+    @Test
+    public void testChainNotDepend() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module2);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     *  |
+     *  |
+     * M2 -> M3 -> M4 -> M5
+     * </pre>
+     */
+    @Test
+    public void testChainDependMulti() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+        Module module4 = mockModule(MODULE4_NAME);
+        Module module5 = mockModule(MODULE5_NAME);
+
+        mockModuleImport(module2, moduleConfig, module3);
+        mockModuleImport(module3, module4);
+        mockModuleImport(module4, module5);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3, module4, module5);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3, module4, module5);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     *  |
+     *  |
+     * M2 -> M3 <- M4
+     * </pre>
+     */
+    @Test
+    public void testChainNotDependMulti() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+        Module module4 = mockModule(MODULE4_NAME);
+
+        mockModuleImport(module2, moduleConfig, module3);
+        mockModuleImport(module4, module3);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3, module4);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3);
+    }
+
+    /**
+     * <pre>
+     *  CFG(R)
+     *  | \ \ \
+     *  |  \ \ \
+     * M2 M3 M4 M5
+     * </pre>
+     */
+    @Test
+    public void testChainNotMulti() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+        Module module4 = mockModule(MODULE4_NAME);
+        Module module5 = mockModule(MODULE5_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, moduleConfig);
+        mockModuleImport(module4, moduleConfig);
+        mockModuleImport(module5, moduleConfig);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3, module4, module5);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3, module4, module5);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     *  | \
+     *  |  \
+     * M2 <- M3 M4=M3(Different revision)
+     * </pre>
+     */
+    @Test
+    public void testBasicRevisionChange() throws Exception {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+
+        Date dat = SimpleDateFormatUtil.getRevisionFormat().parse("2015-10-10");
+        Module module4 = mockModule(MODULE3_NAME, dat);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module2, moduleConfig);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3, module4);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     * |
+     * M2 -(no revision)-> M3(R2) ... M3(R1)
+     * </pre>
+     */
+    @Test
+    public void testImportNoRevision() throws Exception {
+        Module moduleConfig = mockModule(CONFIG_NAME, revision);
+        Module module2 = mockModule(MODULE2_NAME, revision);
+
+        Module module3  = mockModule(MODULE3_NAME, null);
+        Module module30 = mockModule(MODULE3_NAME, revision);
+        Module module31 = mockModule(MODULE3_NAME, revision2);
+        mockModuleImport(module2, moduleConfig, module3);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module30, module31);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module31);
+    }
+
+    /**
+     * <pre>
+     * CFG(R)
+     * |   \
+     * |    \
+     * |    M2 -> M3
+     * |
+     * M41(S) => M4
+     * </pre>
+     */
+    @Test
+    public void testBasicSubmodule() throws Exception {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+        Module module4 = mockModule(MODULE4_NAME);
+        Module module41 = mockModule(MODULE41_NAME);
+
+        mockSubmodules(module4, module41);
+        mockModuleImport(module2, moduleConfig, module3);
+        mockModuleImport(module41, moduleConfig);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3, module4);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, null, moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3, module4);
+    }
+
+    /**
+     * <pre>
+     *
+     * M2 -> M3 -> M4 -> M5
+     *
+     * </pre>
+     */
+    @Test
+    public void testChainAdditionalModules() {
+        Module module2 = mockModule(MODULE2_NAME);
+        Module module3 = mockModule(MODULE3_NAME);
+        Module module4 = mockModule(MODULE4_NAME);
+        Module module5 = mockModule(MODULE5_NAME);
+
+        mockModuleImport(module2, module3);
+        mockModuleImport(module3, module4);
+        mockModuleImport(module4, module5);
+
+        SchemaContext schemaContext = mockSchema(module2, module3, module4, module5);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, Sets.newHashSet(module2), null);
+        assertProxyContext(filteringSchemaContextProxy, module2, module3, module4, module5);
+    }
+
+    /**
+     * <pre>
+     *
+     * CFG(R)
+     *  |
+     *  |       M5
+     * M2
+     *
+     * M3 -> M4
+     *
+     * </pre>
+     */
+    @Test
+    public void testChainAdditionalModulesConfig() {
+        Module moduleConfig = mockModule(CONFIG_NAME);
+        Module module2 = mockModule(MODULE2_NAME);
+
+        Module module3 = mockModule(MODULE3_NAME);
+        Module module4 = mockModule(MODULE4_NAME);
+        Module module5 = mockModule(MODULE5_NAME);
+
+        mockModuleImport(module2, moduleConfig);
+        mockModuleImport(module3, module4);
+
+        SchemaContext schemaContext = mockSchema(moduleConfig, module2, module3, module4, module5);
+
+        FilteringSchemaContextProxy filteringSchemaContextProxy = createProxySchemaCtx(schemaContext, Sets.newHashSet(module3), moduleConfig);
+        assertProxyContext(filteringSchemaContextProxy, moduleConfig, module2, module3, module4);
+    }
+
+    private void assertProxyContext(FilteringSchemaContextProxy filteringSchemaContextProxy, Module... expected) {
+
+        Set<Module> modSet = Sets.newHashSet();
+
+        if(expected!=null) {
+
+            modSet = Sets.newHashSet(expected);
+        }
+
+        Set<Module> modSetFiltering = filteringSchemaContextProxy.getModules();
+
+        assertEquals(modSet, modSetFiltering);
+
+        //asserting collections
+        if(expected!=null) {
+            for (final Module module : expected) {
+                assertEquals(module, filteringSchemaContextProxy.findModuleByName(module.getName(), module.getRevision()));
+
+                Set<Module> mod = filteringSchemaContextProxy.findModuleByNamespace(module.getNamespace());
+                assertTrue(mod.contains(module));
+
+                assertEquals(module, filteringSchemaContextProxy.findModuleByNamespaceAndRevision(module.getNamespace(), module.getRevision()));
+
+                assertEquals(module.getSource(), filteringSchemaContextProxy.getModuleSource(module).get());
+            }
+        }
+    }
+
+    private FilteringSchemaContextProxy createProxySchemaCtx(SchemaContext schemaContext, Set<Module> additionalModules, Module... modules) {
+
+        Set<Module> modulesSet = new HashSet();
+
+        if(modules!=null) {
+
+            modulesSet = Sets.newHashSet(modules);
+
+        }
+
+        return new FilteringSchemaContextProxy(schemaContext, createModuleIds(modulesSet) , createModuleIds(additionalModules));
+    }
+
+    private Set<ModuleId> createModuleIds(Set<Module> modules) {
+
+        Set<ModuleId> moduleIds = Sets.newHashSet();
+
+        if(modules!=null && modules.size()>0) {
+
+            for (Module module : modules) {
+
+                moduleIds.add(new ModuleId(module.getName(), module.getRevision()));
+            }
+        }
+
+        return moduleIds;
+    }
+
+    private void mockSubmodules(Module mainModule, Module... submodules){
+
+        Set<Module> submodulesSet = new HashSet<>();
+        submodulesSet.addAll(Arrays.asList(submodules));
+
+        doReturn(submodulesSet).when(mainModule).getSubmodules();
+    }
+
+    private void mockModuleImport(Module importer, Module... imports) {
+        Set<ModuleImport> mockedImports = Sets.newHashSet();
+        for (final Module module : imports) {
+            mockedImports.add(new ModuleImport() {
+                @Override
+                public String getModuleName() {
+                    return module.getName();
+                }
+
+                @Override
+                public Date getRevision() {
+                    return module.getRevision();
+                }
+
+                @Override
+                public String getPrefix() {
+                    return module.getName();
+                }
+
+                @Override
+                public String toString() {
+
+                    return String.format("Module: %s, revision:%s", module.getName(), module.getRevision());
+                }
+            });
+        }
+        doReturn(mockedImports).when(importer).getImports();
+    }
+
+    //mock module with revision
+    private Module mockModule(String name, final Date rev){
+
+        final Module mod = mockModule(name);
+
+        doReturn(QNameModule.create(mod.getNamespace(), rev)).when(mod).getQNameModule();
+        doReturn(rev).when(mod).getRevision();
+        doReturn(mod.getQNameModule().toString()).when(mod).toString();
+
+        return mod;
+    }
+
+    //mock module with default revision
+    private Module mockModule(String mName) {
+
+        Module mockedModule = mock(Module.class);
+        doReturn(mName).when(mockedModule).getName();
+        doReturn(revision).when(mockedModule).getRevision();
+        final URI newNamespace = URI.create(namespace.toString() + ":" + mName);
+        doReturn(newNamespace).when(mockedModule).getNamespace();
+        doReturn(QNameModule.create(newNamespace, revision)).when(mockedModule).getQNameModule();
+        doReturn(TEST_SOURCE).when(mockedModule).getSource();
+        doReturn(Sets.newHashSet()).when(mockedModule).getSubmodules();
+        doReturn(mockedModule.getQNameModule().toString()).when(mockedModule).toString();
+        mockModuleImport(mockedModule);
+
+        return mockedModule;
+    }
+}
index 5a4bb3df25aa69fd2324b7def8dd1a59c69339ee..652011a2250d681bc0e81b22650dd143a93a021d 100644 (file)
@@ -7,80 +7,40 @@
  */
 package org.opendaylight.yangtools.yang.parser.impl;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
 import com.google.common.collect.Multimaps;
 import com.google.common.collect.SetMultimap;
 import java.net.URI;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
-import java.util.TreeSet;
 import javax.annotation.concurrent.Immutable;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.Status;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.util.AbstractSchemaContext;
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
 
 @Immutable
-final class SchemaContextImpl implements SchemaContext {
-    private static final Comparator<Module> REVISION_COMPARATOR = new Comparator<Module>() {
-        @Override
-        public int compare(final Module o1, final Module o2) {
-            if (o2.getRevision() == null) {
-                return -1;
-            }
+final class SchemaContextImpl extends AbstractSchemaContext {
 
-            return o2.getRevision().compareTo(o1.getRevision());
-        }
-    };
-
-    private static final Supplier<TreeSet<Module>> MODULE_SET_SUPPLIER = new Supplier<TreeSet<Module>>() {
-        @Override
-        public TreeSet<Module> get() {
-            return new TreeSet<>(REVISION_COMPARATOR);
-        }
-    };
-
-    private final Map<ModuleIdentifier, String> identifiersToSources;
-    private final SetMultimap<URI, Module> namespaceToModules;
-    private final SetMultimap<String, Module> nameToModules;
-    private final Set<Module> modules;
+    private  final Map<ModuleIdentifier, String> identifiersToSources;
+    private  final SetMultimap<URI, Module> namespaceToModules;
+    private  final SetMultimap<String, Module> nameToModules;
+    private  final Set<Module> modules;
 
     SchemaContextImpl(final Set<Module> modules, final Map<ModuleIdentifier, String> identifiersToSources) {
         this.identifiersToSources = ImmutableMap.copyOf(identifiersToSources);
 
-        /*
+         /*
          * Instead of doing this on each invocation of getModules(), pre-compute
          * it once and keep it around -- better than the set we got in.
          */
         this.modules = ImmutableSet.copyOf(ModuleDependencySort.sort(modules.toArray(new Module[modules.size()])));
 
-        /*
+         /*
          * The most common lookup is from Namespace->Module.
          *
          * RESTCONF performs lookups based on module name only, where it wants
@@ -92,6 +52,7 @@ final class SchemaContextImpl implements SchemaContext {
                 new TreeMap<URI, Collection<Module>>(), MODULE_SET_SUPPLIER);
         final SetMultimap<String, Module> nameMap = Multimaps.newSetMultimap(
                 new TreeMap<String, Collection<Module>>(), MODULE_SET_SUPPLIER);
+
         for (Module m : modules) {
             nameMap.put(m.getName(), m);
             nsMap.put(m.getNamespace(), m);
@@ -102,210 +63,32 @@ final class SchemaContextImpl implements SchemaContext {
     }
 
     @Override
-    public Set<DataSchemaNode> getDataDefinitions() {
-        final Set<DataSchemaNode> dataDefs = new HashSet<>();
-        for (Module m : modules) {
-            dataDefs.addAll(m.getChildNodes());
-        }
-        return dataDefs;
-    }
-
-    @Override
-    public Set<Module> getModules() {
-        return modules;
-    }
-
-    @Override
-    public Set<NotificationDefinition> getNotifications() {
-        final Set<NotificationDefinition> notifications = new HashSet<>();
-        for (Module m : modules) {
-            notifications.addAll(m.getNotifications());
-        }
-        return notifications;
-    }
-
-    @Override
-    public Set<RpcDefinition> getOperations() {
-        final Set<RpcDefinition> rpcs = new HashSet<>();
-        for (Module m : modules) {
-            rpcs.addAll(m.getRpcs());
-        }
-        return rpcs;
-    }
-
-    @Override
-    public Set<ExtensionDefinition> getExtensions() {
-        final Set<ExtensionDefinition> extensions = new HashSet<>();
-        for (Module m : modules) {
-            extensions.addAll(m.getExtensionSchemaNodes());
-        }
-        return extensions;
-    }
-
-    @Override
-    public Module findModuleByName(final String name, final Date revision) {
-        for (final Module module : nameToModules.get(name)) {
-            if (revision == null || revision.equals(module.getRevision())) {
-                return module;
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public Set<Module> findModuleByNamespace(final URI namespace) {
-        final Set<Module> ret = namespaceToModules.get(namespace);
-        return ret == null ? Collections.<Module>emptySet() : ret;
-    }
-
-    @Override
-    public Module findModuleByNamespaceAndRevision(final URI namespace, final Date revision) {
-        if (namespace == null) {
-            return null;
-        }
-        for (Module module : findModuleByNamespace(namespace)) {
-            if (revision == null || revision.equals(module.getRevision())) {
-                return module;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public boolean isAugmenting() {
-        return false;
-    }
-
-    @Override
-    public boolean isAddedByUses() {
-        return false;
-    }
-
-    @Override
-    public boolean isConfiguration() {
-        return false;
-    }
-
-    @Override
-    public ConstraintDefinition getConstraints() {
-        return null;
-    }
-
-    @Override
-    public QName getQName() {
-        return SchemaContext.NAME;
-    }
-
-    @Override
-    public SchemaPath getPath() {
-        return SchemaPath.ROOT;
-    }
-
-    @Override
-    public String getDescription() {
-        return null;
-    }
-
-    @Override
-    public String getReference() {
-        return null;
-    }
-
-    @Override
-    public Status getStatus() {
-        return Status.CURRENT;
-    }
+    protected Map<ModuleIdentifier, String> getIdentifiersToSources(){
 
-    @Override
-    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
-        final List<UnknownSchemaNode> result = new ArrayList<>();
-        for (Module module : modules) {
-            result.addAll(module.getUnknownSchemaNodes());
-        }
-        return Collections.unmodifiableList(result);
+        return identifiersToSources;
     }
 
     @Override
-    public Set<TypeDefinition<?>> getTypeDefinitions() {
-        final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
-        for (Module module : modules) {
-            result.addAll(module.getTypeDefinitions());
-        }
-        return Collections.unmodifiableSet(result);
-    }
+    public Set<Module> getModules(){
 
-    @Override
-    public Set<DataSchemaNode> getChildNodes() {
-        final Set<DataSchemaNode> result = new LinkedHashSet<>();
-        for (Module module : modules) {
-            result.addAll(module.getChildNodes());
-        }
-        return Collections.unmodifiableSet(result);
-    }
-
-    @Override
-    public Set<GroupingDefinition> getGroupings() {
-        final Set<GroupingDefinition> result = new LinkedHashSet<>();
-        for (Module module : modules) {
-            result.addAll(module.getGroupings());
-        }
-        return Collections.unmodifiableSet(result);
-    }
-
-    @Override
-    public DataSchemaNode getDataChildByName(final QName name) {
-        for (Module module : modules) {
-            final DataSchemaNode result = module.getDataChildByName(name);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public DataSchemaNode getDataChildByName(final String name) {
-        for (Module module : modules) {
-            final DataSchemaNode result = module.getDataChildByName(name);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
+        return modules;
     }
 
     @Override
-    public Set<UsesNode> getUses() {
-        return Collections.emptySet();
-    }
+    protected SetMultimap<URI, Module> getNamespaceToModules() {
 
-    @Override
-    public boolean isPresenceContainer() {
-        return false;
+        return namespaceToModules;
     }
 
     @Override
-    public Set<AugmentationSchema> getAvailableAugmentations() {
-        return Collections.emptySet();
-    }
+    protected SetMultimap<String, Module> getNameToModules() {
 
-    //FIXME: should work for submodules too
-    @Override
-    public Set<ModuleIdentifier> getAllModuleIdentifiers() {
-        return identifiersToSources.keySet();
-    }
-
-    @Override
-    public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
-        String maybeSource = identifiersToSources.get(moduleIdentifier);
-        return Optional.fromNullable(maybeSource);
+        return nameToModules;
     }
 
     @Override
     public String toString() {
-        return "SchemaContextImpl{" +
-                "modules=" + modules +
-                '}';
+
+        return String.format("SchemaContextImpl{modules=%s}", modules);
     }
 }