Add XMLNamespace
[yangtools.git] / yang / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / util / ModuleDependencySort.java
index a424e70e391525a369373c9d37b27271bb177a0d..fc6a458d958d130b4cd2e397b8ed7d43f71ace63 100644 (file)
@@ -7,27 +7,28 @@
  */
 package org.opendaylight.yangtools.yang.model.util;
 
-import static org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil.DEFAULT_DATE_REV;
-
 import com.google.common.annotations.Beta;
 import com.google.common.collect.HashBasedTable;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Table;
-import java.net.URI;
+import java.util.Arrays;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import org.opendaylight.yangtools.util.TopologicalSort;
 import org.opendaylight.yangtools.util.TopologicalSort.Node;
 import org.opendaylight.yangtools.util.TopologicalSort.NodeImpl;
-import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
 import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.Submodule;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,11 +41,8 @@ import org.slf4j.LoggerFactory;
 public final class ModuleDependencySort {
     private static final Logger LOG = LoggerFactory.getLogger(ModuleDependencySort.class);
 
-    /**
-     * It is not desirable to instance this class.
-     */
     private ModuleDependencySort() {
-        throw new UnsupportedOperationException();
+        // Hidden on purpose
     }
 
     /**
@@ -54,34 +52,31 @@ public final class ModuleDependencySort {
      * @return Sorted list of Modules. Modules can be further processed in returned order.
      * @throws IllegalArgumentException when provided modules are not consistent.
      */
-    public static List<Module> sort(final Collection<Module> modules) {
-        return sort((Iterable<Module>)modules);
+    public static List<Module> sort(final Module... modules) {
+        return sort(Arrays.asList(modules));
     }
 
     /**
      * Topological sort of module dependency graph.
      *
      * @param modules YANG modules
-     * @return Sorted list of Modules. Modules can be further processed in
-     *         returned order.
+     * @return Sorted list of Modules. Modules can be further processed in returned order.
      * @throws IllegalArgumentException when provided modules are not consistent.
-     *
-     * @deprecated Use {@link #sort(Collection)} instead.
      */
-    @Deprecated
-    public static List<Module> sort(final Iterable<Module> modules) {
+    public static List<Module> sort(final Collection<? extends Module> modules) {
         final List<Node> sorted = sortInternal(modules);
         // Cast to Module from Node and return
         return Lists.transform(sorted, input -> input == null ? null : ((ModuleNodeImpl) input).getReference());
     }
 
-    private static List<Node> sortInternal(final Iterable<Module> modules) {
-        final Table<String, Date, ModuleNodeImpl> moduleGraph = createModuleGraph(modules);
+    private static List<Node> sortInternal(final Collection<? extends Module> modules) {
+        final Table<String, Optional<Revision>, ModuleNodeImpl> moduleGraph = createModuleGraph(modules);
         return TopologicalSort.sort(new HashSet<>(moduleGraph.values()));
     }
 
-    private static Table<String, Date, ModuleNodeImpl> createModuleGraph(final Iterable<Module> builders) {
-        final Table<String, Date, ModuleNodeImpl> moduleGraph = HashBasedTable.create();
+    private static Table<String, Optional<Revision>, ModuleNodeImpl> createModuleGraph(
+            final Collection<? extends Module> builders) {
+        final Table<String, Optional<Revision>, ModuleNodeImpl> moduleGraph = HashBasedTable.create();
 
         processModules(moduleGraph, builders);
         processDependencies(moduleGraph, builders);
@@ -92,16 +87,16 @@ public final class ModuleDependencySort {
     /**
      * Extract module:revision from modules.
      */
-    private static void processDependencies(final Table<String, Date, ModuleNodeImpl> moduleGraph,
-            final Iterable<Module> mmbs) {
-        final Map<URI, Module> allNS = new HashMap<>();
+    private static void processDependencies(final Table<String, Optional<Revision>, ModuleNodeImpl> moduleGraph,
+            final Collection<? extends Module> mmbs) {
+        final Map<XMLNamespace, Module> allNS = new HashMap<>();
 
         // Create edges in graph
         for (final Module module : mmbs) {
-            final Map<String, Date> imported = new HashMap<>();
+            final Map<String, Optional<Revision>> imported = new HashMap<>();
             final String fromName = module.getName();
-            final URI ns = module.getNamespace();
-            Date fromRevision = module.getRevision();
+            final XMLNamespace ns = module.getNamespace();
+            final Optional<Revision> fromRevision = module.getRevision();
 
             // check for existence of module with same namespace
             final Module prev = allNS.putIfAbsent(ns, module);
@@ -113,19 +108,12 @@ public final class ModuleDependencySort {
                 }
             }
 
-            // no need to check if other Type of object, check is performed in
-            // process modules
-
-            if (fromRevision == null) {
-                fromRevision = DEFAULT_DATE_REV;
-            }
-
-            for (final ModuleImport imprt : module.getImports()) {
+            // no need to check if other Type of object, check is performed in process modules
+            for (final ModuleImport imprt : allImports(module)) {
                 final String toName = imprt.getModuleName();
-                final Date toRevision = imprt.getRevision() == null ? DEFAULT_DATE_REV : imprt.getRevision();
+                final Optional<Revision> toRevision = imprt.getRevision();
 
                 final ModuleNodeImpl from = moduleGraph.get(fromName, fromRevision);
-
                 final ModuleNodeImpl to = getModuleByNameAndRevision(moduleGraph, fromName, fromRevision, toName,
                     toRevision);
 
@@ -133,10 +121,10 @@ public final class ModuleDependencySort {
                  * If it is an yang 1 module, check imports: If module is imported twice with different
                  * revisions then throw exception
                  */
-                if (YangVersion.VERSION_1.toString().equals(module.getYangVersion())) {
-                    final Date impRevision = imported.get(toName);
-                    if (impRevision != null && !impRevision.equals(toRevision)
-                        && !DEFAULT_DATE_REV.equals(impRevision) && !DEFAULT_DATE_REV.equals(toRevision)) {
+                if (module.getYangVersion() == YangVersion.VERSION_1) {
+                    final Optional<Revision> impRevision = imported.get(toName);
+                    if (impRevision != null && impRevision.isPresent() && !impRevision.equals(toRevision)
+                            && toRevision.isPresent()) {
                         throw new IllegalArgumentException(String.format(
                             "Module:%s imported twice with different revisions:%s, %s", toName,
                             formatRevDate(impRevision), formatRevDate(toRevision)));
@@ -150,11 +138,25 @@ public final class ModuleDependencySort {
         }
     }
 
+    private static Collection<? extends ModuleImport> allImports(final Module mod) {
+        if (mod.getSubmodules().isEmpty()) {
+            return mod.getImports();
+        }
+
+        final Collection<ModuleImport> concat = new LinkedHashSet<>();
+        concat.addAll(mod.getImports());
+        for (Submodule sub : mod.getSubmodules()) {
+            concat.addAll(sub.getImports());
+        }
+        return concat;
+    }
+
     /**
      * Get imported module by its name and revision from moduleGraph.
      */
-    private static ModuleNodeImpl getModuleByNameAndRevision(final Table<String, Date, ModuleNodeImpl> moduleGraph,
-            final String fromName, final Date fromRevision, final String toName, final Date toRevision) {
+    private static ModuleNodeImpl getModuleByNameAndRevision(
+            final Table<String, Optional<Revision>, ModuleNodeImpl> moduleGraph, final String fromName,
+            final Optional<Revision> fromRevision, final String toName, final Optional<Revision> toRevision) {
 
         final ModuleNodeImpl exact = moduleGraph.get(toName, toRevision);
         if (exact != null) {
@@ -162,8 +164,8 @@ public final class ModuleDependencySort {
         }
 
         // If revision is not specified in import, but module exists with different revisions, take first one
-        if (DEFAULT_DATE_REV.equals(toRevision)) {
-            final Map<Date, ModuleNodeImpl> modulerevs = moduleGraph.row(toName);
+        if (toRevision.isEmpty()) {
+            final Map<Optional<Revision>, ModuleNodeImpl> modulerevs = moduleGraph.row(toName);
 
             if (!modulerevs.isEmpty()) {
                 final ModuleNodeImpl first = modulerevs.values().iterator().next();
@@ -186,38 +188,34 @@ public final class ModuleDependencySort {
     /**
      * Extract dependencies from modules to fill dependency graph.
      */
-    private static void processModules(final Table<String, Date, ModuleNodeImpl> moduleGraph,
-            final Iterable<Module> modules) {
+    private static void processModules(final Table<String, Optional<Revision>, ModuleNodeImpl> moduleGraph,
+            final Iterable<? extends Module> modules) {
 
         // Process nodes
         for (final Module momb : modules) {
 
             final String name = momb.getName();
-            Date rev = momb.getRevision();
-            if (rev == null) {
-                rev = DEFAULT_DATE_REV;
-            }
-
-            final Map<Date, ModuleNodeImpl> revs = moduleGraph.row(name);
+            final Optional<Revision> rev = momb.getRevision();
+            final Map<Optional<Revision>, ModuleNodeImpl> revs = moduleGraph.row(name);
             if (revs.containsKey(rev)) {
                 throw new IllegalArgumentException(String.format("Module:%s with revision:%s declared twice", name,
                     formatRevDate(rev)));
             }
 
-            revs.put(rev, new ModuleNodeImpl(name, rev, momb));
+            revs.put(rev, new ModuleNodeImpl(name, rev.orElse(null), momb));
         }
     }
 
-    private static String formatRevDate(final Date rev) {
-        return rev.equals(DEFAULT_DATE_REV) ? "default" : SimpleDateFormatUtil.getRevisionFormat().format(rev);
+    private static String formatRevDate(final Optional<Revision> rev) {
+        return rev.map(Revision::toString).orElse("default");
     }
 
     private static final class ModuleNodeImpl extends NodeImpl {
         private final String name;
-        private final Date revision;
+        private final Revision revision;
         private final Module originalObject;
 
-        ModuleNodeImpl(final String name, final Date revision, final Module module) {
+        ModuleNodeImpl(final String name, final Revision revision, final Module module) {
             this.name = name;
             this.revision = revision;
             this.originalObject = module;
@@ -227,8 +225,8 @@ public final class ModuleDependencySort {
             return name;
         }
 
-        Date getRevision() {
-            return revision;
+        Optional<Revision> getRevision() {
+            return Optional.ofNullable(revision);
         }
 
         @Override
@@ -252,18 +250,10 @@ public final class ModuleDependencySort {
                 return false;
             }
             final ModuleNodeImpl other = (ModuleNodeImpl) obj;
-            if (name == null) {
-                if (other.name != null) {
-                    return false;
-                }
-            } else if (!name.equals(other.name)) {
+            if (!Objects.equals(name, other.name)) {
                 return false;
             }
-            if (revision == null) {
-                if (other.revision != null) {
-                    return false;
-                }
-            } else if (!revision.equals(other.revision)) {
+            if (!Objects.equals(revision, other.revision)) {
                 return false;
             }
             return true;
@@ -271,7 +261,7 @@ public final class ModuleDependencySort {
 
         @Override
         public String toString() {
-            return "Module [name=" + name + ", revision=" + formatRevDate(revision) + "]";
+            return "Module [name=" + name + ", revision=" + formatRevDate(getRevision()) + "]";
         }
 
         public Module getReference() {