Merge "BUG 2413 - tracking in yang grouping"
authorTony Tkacik <ttkacik@cisco.com>
Fri, 13 Feb 2015 14:39:37 +0000 (14:39 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 13 Feb 2015 14:39:37 +0000 (14:39 +0000)
12 files changed:
code-generator/binding-parent/pom.xml
common/features-builder/pom.xml
common/parent/pom.xml
yang/yang-data-codec-gson/src/main/java/org/opendaylight/yangtools/yang/data/codec/gson/JSONNormalizedNodeStreamWriter.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/builder/impl/CopyUtils.java
yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/SchemaContextImpl.java
yang/yang-parser-impl/src/test/java/org/opendaylight/yangtools/yang/parser/impl/GroupingTest.java
yang/yang-parser-impl/src/test/resources/added-by-uses-leaf-test/foo.yang [new file with mode: 0644]
yang/yang-parser-impl/src/test/resources/added-by-uses-leaf-test/import-module.yang [new file with mode: 0644]

index e3e22309680467997415b8960f056e3400d493d9..c38481e8d499af78d692e66f4c70d63ac1e3ed8c 100644 (file)
                 </file>
             </activation>
             <dependencies>
-              <dependency>
-                <groupId>org.opendaylight.yangtools</groupId>
-                <artifactId>yang-binding</artifactId>
-              </dependency>
+                <dependency>
+                    <groupId>org.opendaylight.yangtools</groupId>
+                    <artifactId>yang-binding</artifactId>
+                </dependency>
             </dependencies>
             <build>
                 <pluginManagement>
                                 </execution>
                             </executions>
                         </plugin>
-                      <plugin>
-                        <artifactId>maven-clean-plugin</artifactId>
-                        <configuration>
-                          <filesets>
-                            <fileset>
-                              <directory>${salGeneratorPath}</directory>
-                              <includes>
-                                <include>**</include>
-                              </includes>
-                            </fileset>
-                          </filesets>
-                        </configuration>
-                      </plugin>
+                        <plugin>
+                            <artifactId>maven-clean-plugin</artifactId>
+                            <configuration>
+                                <filesets>
+                                    <fileset>
+                                        <directory>${salGeneratorPath}</directory>
+                                        <includes>
+                                            <include>**</include>
+                                        </includes>
+                                    </fileset>
+                                </filesets>
+                            </configuration>
+                        </plugin>
+                        <plugin>
+                            <groupId>org.codehaus.mojo</groupId>
+                            <artifactId>build-helper-maven-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <id>add-yang-sources</id>
+                                    <phase>generate-sources</phase>
+                                    <goals>
+                                        <goal>add-source</goal>
+                                    </goals>
+                                    <configuration>
+                                        <sources>
+                                            <source>${salGeneratorPath}</source>
+                                        </sources>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
                     </plugins>
                 </pluginManagement>
-              <plugins>
-                <plugin>
-                  <groupId>org.opendaylight.yangtools</groupId>
-                  <artifactId>yang-maven-plugin</artifactId>
-                  <version>${yangtools.version}</version>
-                </plugin>
-              </plugins>
+                <plugins>
+                    <plugin>
+                        <groupId>org.opendaylight.yangtools</groupId>
+                        <artifactId>yang-maven-plugin</artifactId>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>build-helper-maven-plugin</artifactId>
+                    </plugin>
+                </plugins>
             </build>
         </profile>
     </profiles>
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 53c8d5439eee25017127ca65541f46b24eabe316..59ef1f1e501ffc53011230f5f2f8ba61271f530c 100644 (file)
@@ -20,7 +20,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -163,10 +162,9 @@ public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWrite
     public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
         final SchemaNode schema = tracker.startContainerNode(name);
 
-        final boolean isPresence = schema instanceof ContainerSchemaNode ?
-                ((ContainerSchemaNode) schema).isPresenceContainer() : DEFAULT_EMIT_EMPTY_CONTAINERS;
-
-        context = new JSONStreamWriterNamedObjectContext(context, name, isPresence);
+        // FIXME this code ignores presence for containers
+        // but datastore does as well and it needs be fixed first (2399)
+        context = new JSONStreamWriterNamedObjectContext(context, name, DEFAULT_EMIT_EMPTY_CONTAINERS);
     }
 
     @Override
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 0ca3d88b276ce03c509f8a2705cd469603592de1..55cf82726d8d104a4d9c32facff1bcf6d77bc6ab 100644 (file)
@@ -202,7 +202,7 @@ public final class CopyUtils {
         }
 
         if (old.getType() == null) {
-            copy.setTypedef(copy(old.getTypedef(), copy, updateQName));
+            copy.setTypedef(old.getTypedef());
         } else {
             copy.setType(old.getType());
         }
@@ -235,7 +235,7 @@ public final class CopyUtils {
         }
 
         if (old.getType() == null) {
-            copy.setTypedef(copy(old.getTypedef(), copy, updateQName));
+            copy.setTypedef(old.getTypedef());
         } else {
             copy.setType(old.getType());
         }
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);
     }
 }
index a4360a5a67a93345f8e121781ae64ac4bee919c6..3abb8508e7b337b933fbf1b9d121a789319c7131 100644 (file)
@@ -13,6 +13,8 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
@@ -545,4 +547,41 @@ public class GroupingTest {
         assertEquals(gy.getDataChildByName("leaf-grouping-Y"),SchemaNodeUtils.getRootOriginalIfPossible( gx.getDataChildByName("leaf-grouping-Y")));
     }
 
+    @Test
+    public void testAddedByUsesLeafTypeQName() throws IOException,
+            URISyntaxException {
+
+        Set<Module> loadModules = TestUtils.loadModules(getClass().getResource(
+                "/added-by-uses-leaf-test").toURI());
+
+        assertEquals(2, loadModules.size());
+
+        Module foo = null;
+        Module imp = null;
+        for (Module module : loadModules) {
+            if (module.getName().equals("foo")) {
+                foo = module;
+            }
+            if (module.getName().equals("import-module")) {
+                imp = module;
+            }
+        }
+
+        LeafSchemaNode leaf = (LeafSchemaNode) ((ContainerSchemaNode) foo
+                .getDataChildByName("my-container"))
+                .getDataChildByName("my-leaf");
+
+        TypeDefinition impType = null;
+        Set<TypeDefinition<?>> typeDefinitions = imp.getTypeDefinitions();
+        for (TypeDefinition<?> typeDefinition : typeDefinitions) {
+            if (typeDefinition.getQName().getLocalName().equals("imp-type")) {
+                impType = typeDefinition;
+                break;
+            }
+        }
+
+        assertEquals(leaf.getType().getQName(), impType.getQName());
+
+    }
+
 }
diff --git a/yang/yang-parser-impl/src/test/resources/added-by-uses-leaf-test/foo.yang b/yang/yang-parser-impl/src/test/resources/added-by-uses-leaf-test/foo.yang
new file mode 100644 (file)
index 0000000..413d7c6
--- /dev/null
@@ -0,0 +1,20 @@
+module foo {
+    prefix foo;
+    namespace "namespace-foo";
+
+    import import-module { prefix imp; revision-date 1970-01-02; } 
+    
+    grouping grp {
+        leaf my-leaf {
+            type imp:imp-type;
+        }
+        
+    }
+    
+    container my-container {
+        uses grp;
+        uses imp:imp_grp;
+    }
+    
+}
+
diff --git a/yang/yang-parser-impl/src/test/resources/added-by-uses-leaf-test/import-module.yang b/yang/yang-parser-impl/src/test/resources/added-by-uses-leaf-test/import-module.yang
new file mode 100644 (file)
index 0000000..6cb9f69
--- /dev/null
@@ -0,0 +1,35 @@
+module import-module {
+    prefix imp;
+    namespace "import-module";
+
+    revision 1970-01-02 {
+        description "Initial revision.";
+    }
+
+    typedef imp-type {
+        type string {
+            length "0..100";
+        }
+    }
+
+    grouping imp_grp {
+        
+        typedef grp-type {
+            type string {
+                length "20..30";
+            }
+        }
+
+        leaf my-leaf2 {
+            type grp-type;
+        }
+        
+        leaf union-leaf {
+            type union {
+                type int16;
+                type string;
+            }
+        }
+    }
+}
+