BUG-576: modified parser to handle augmentation of extension instances.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / BuilderUtils.java
index 167b62f665eb8ccf0481e79a4fa86d268890ddaf..4a61d7b0f6d0eef9458a16fbc1c3becd97d3976c 100644 (file)
@@ -12,6 +12,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.Iterables;
 import com.google.common.io.ByteSource;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -19,17 +20,25 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+import org.antlr.v4.runtime.tree.ParseTree;
 import org.apache.commons.io.IOUtils;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_header_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_stmtsContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -57,7 +66,10 @@ import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
+import org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils;
+import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
 import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream;
 import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
@@ -66,9 +78,11 @@ import org.slf4j.LoggerFactory;
 
 public final class BuilderUtils {
 
+    private static final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
     private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
-    private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+    private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings();
     private static final Splitter COLON_SPLITTER = Splitter.on(':');
+    private static final Date NULL_DATE = new Date(0L);
     private static final String INPUT = "input";
     private static final String OUTPUT = "output";
 
@@ -107,40 +121,6 @@ public final class BuilderUtils {
         });
     }
 
-    /**
-     * Set string representation of source to ModuleBuilder.
-     *
-     * @param sourceToBuilder
-     *            source to module mapping
-     */
-    public static void setSourceToBuilder(final Map<ByteSource, ModuleBuilder> sourceToBuilder) throws IOException {
-        for (Map.Entry<ByteSource, ModuleBuilder> entry : sourceToBuilder.entrySet()) {
-            ModuleBuilder builder = entry.getValue();
-            ByteSource source = entry.getKey();
-
-            String content = null;
-            InputStream stream = null;
-            try {
-                stream = source.openStream();
-                content = IOUtils.toString(stream);
-            } finally {
-                if (stream != null) {
-                    try {
-                        stream.close();
-                    } catch (IOException e) {
-                        /*
-                         * Failed stream close does not prevent us from
-                         * continuing to work correctly, we just report that and
-                         * continue.
-                         */
-                        LOG.warn("Failed to close stream {}. Leaving stream unclosed.", stream, e);
-                    }
-                }
-            }
-            builder.setSource(content);
-        }
-    }
-
     /**
      * Create new SchemaPath from given path and qname.
      *
@@ -154,28 +134,7 @@ public final class BuilderUtils {
      */
     @Deprecated
     public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) {
-        List<QName> path = new ArrayList<>(schemaPath.getPath());
-        path.addAll(Arrays.asList(qname));
-        return SchemaPath.create(path, schemaPath.isAbsolute());
-    }
-
-    /**
-     * Get module import referenced by given prefix.
-     *
-     * @param builder
-     *            module to search
-     * @param prefix
-     *            prefix associated with import
-     * @return ModuleImport based on given prefix
-     */
-    public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
-        for (ModuleImport mi : builder.getModuleImports()) {
-            if (mi.getPrefix().equals(prefix)) {
-                return mi;
-
-            }
-        }
-        return null;
+        return schemaPath.createChild(qname);
     }
 
     /**
@@ -193,15 +152,15 @@ public final class BuilderUtils {
      */
     public static ModuleBuilder findModuleFromBuilders(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final ModuleBuilder module, final String prefix, final int line) {
-        ModuleBuilder dependentModule = null;
-        Date dependentModuleRevision = null;
+        ModuleBuilder dependentModule;
+        Date dependentModuleRevision;
 
         if (prefix == null) {
             dependentModule = module;
         } else if (prefix.equals(module.getPrefix())) {
             dependentModule = module;
         } else {
-            ModuleImport dependentModuleImport = getModuleImport(module, prefix);
+            ModuleImport dependentModuleImport = module.getImport(prefix);
             if (dependentModuleImport == null) {
                 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
             }
@@ -221,6 +180,26 @@ public final class BuilderUtils {
         return dependentModule;
     }
 
+    public static ModuleBuilder findModuleFromBuilders(ModuleImport imp, Iterable<ModuleBuilder> modules) {
+        String name = imp.getModuleName();
+        Date revision = imp.getRevision();
+        TreeMap<Date, ModuleBuilder> map = new TreeMap<>();
+        for (ModuleBuilder module : modules) {
+            if (module != null) {
+                if (module.getName().equals(name)) {
+                    map.put(module.getRevision(), module);
+                }
+            }
+        }
+        if (map.isEmpty()) {
+            return null;
+        }
+        if (revision == null) {
+            return map.lastEntry().getValue();
+        }
+        return map.get(revision);
+    }
+
     /**
      * Find module from context based on prefix.
      *
@@ -229,20 +208,19 @@ public final class BuilderUtils {
      * @param currentModule
      *            current module
      * @param prefix
-     *            current prefix used to reference dependent module
+     *            prefix used to reference dependent module
      * @param line
      *            current line in yang model
-     * @return module based on given prefix if found in context, null otherwise
+     * @return module based on import with given prefix if found in context,
+     *         null otherwise
+     * @throws YangParseException
+     *             if no import found with given prefix
      */
     public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
             final String prefix, final int line) {
-        if (context == null) {
-            throw new YangParseException(currentModule.getName(), line, "Cannot find module with prefix '" + prefix
-                    + "'.");
-        }
         TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
 
-        ModuleImport dependentModuleImport = BuilderUtils.getModuleImport(currentModule, prefix);
+        ModuleImport dependentModuleImport = currentModule.getImport(prefix);
         if (dependentModuleImport == null) {
             throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
         }
@@ -253,47 +231,23 @@ public final class BuilderUtils {
             if (contextModule.getName().equals(dependentModuleName)) {
                 Date revision = contextModule.getRevision();
                 if (revision == null) {
-                    revision = new Date(0L);
+                    revision = NULL_DATE;
                 }
                 modulesByRevision.put(revision, contextModule);
             }
         }
 
-        Module result = null;
+        Module result;
         if (dependentModuleRevision == null) {
             result = modulesByRevision.get(modulesByRevision.firstKey());
         } else {
             result = modulesByRevision.get(dependentModuleRevision);
         }
-        return result;
-    }
-
-    /**
-     * Parse XPath string.
-     *
-     * @param xpathString
-     *            XPath as String
-     * @return SchemaPath from given String
-     */
-    public static SchemaPath parseXPathString(final String xpathString) {
-        final boolean absolute = xpathString.indexOf('/') == 0;
-
-        final List<QName> path = new ArrayList<QName>();
-        for (String pathElement : SLASH_SPLITTER.split(xpathString)) {
-            if (pathElement.length() > 0) {
-                final Iterator<String> it = COLON_SPLITTER.split(pathElement).iterator();
-                final String s = it.next();
-
-                final QName name;
-                if (it.hasNext()) {
-                    name = new QName(null, null, s, it.next());
-                } else {
-                    name = new QName(null, null, null, s);
-                }
-                path.add(name);
-            }
+        if (result == null) {
+            throw new YangParseException(currentModule.getName(), line, "Module not found for prefix " + prefix);
         }
-        return SchemaPath.create(path, absolute);
+
+        return result;
     }
 
     /**
@@ -408,56 +362,38 @@ public final class BuilderUtils {
         }
     }
 
-    /**
-     * Set config flag to new value.
-     *
-     * @param node
-     *            node to update
-     * @param config
-     *            new config value
-     */
-    public static void setNodeConfig(final DataSchemaNodeBuilder node, final Boolean config) {
-        if (node instanceof ContainerSchemaNodeBuilder || node instanceof LeafSchemaNodeBuilder
-                || node instanceof LeafListSchemaNodeBuilder || node instanceof ListSchemaNodeBuilder
-                || node instanceof ChoiceBuilder || node instanceof AnyXmlBuilder) {
-            node.setConfiguration(config);
-        }
-        if (node instanceof DataNodeContainerBuilder) {
-            DataNodeContainerBuilder dataNodeChild = (DataNodeContainerBuilder) node;
-            for (DataSchemaNodeBuilder inner : dataNodeChild.getChildNodeBuilders()) {
-                setNodeConfig(inner, config);
-            }
-        } else if (node instanceof ChoiceBuilder) {
-            ChoiceBuilder choiceChild = (ChoiceBuilder) node;
-            for (ChoiceCaseBuilder inner : choiceChild.getCases()) {
-                setNodeConfig(inner, config);
-            }
-        }
-    }
-
-    public static DataSchemaNodeBuilder findSchemaNode(final List<QName> path, final SchemaNodeBuilder parentNode) {
-        DataSchemaNodeBuilder node = null;
+    public static SchemaNodeBuilder findSchemaNode(final Iterable<QName> path, final SchemaNodeBuilder parentNode) {
+        SchemaNodeBuilder node = null;
         SchemaNodeBuilder parent = parentNode;
+        int size = Iterables.size(path);
         int i = 0;
-        while (i < path.size()) {
-            String name = path.get(i).getLocalName();
+        for (QName qname : path) {
+            String name = qname.getLocalName();
             if (parent instanceof DataNodeContainerBuilder) {
                 node = ((DataNodeContainerBuilder) parent).getDataChildByName(name);
+                if (node == null) {
+                    node = findUnknownNode(name, parent);
+                }
             } else if (parent instanceof ChoiceBuilder) {
                 node = ((ChoiceBuilder) parent).getCaseNodeByName(name);
+                if (node == null) {
+                    node = findUnknownNode(name, parent);
+                }
             } else if (parent instanceof RpcDefinitionBuilder) {
                 if ("input".equals(name)) {
                     node = ((RpcDefinitionBuilder) parent).getInput();
                 } else if ("output".equals(name)) {
                     node = ((RpcDefinitionBuilder) parent).getOutput();
                 } else {
-                    return null;
+                    if (node == null) {
+                        node = findUnknownNode(name, parent);
+                    }
                 }
             } else {
-                return null;
+                node = findUnknownNode(name, parent);
             }
 
-            if (i < path.size() - 1) {
+            if (i < size - 1) {
                 parent = node;
             }
             i = i + 1;
@@ -466,6 +402,15 @@ public final class BuilderUtils {
         return node;
     }
 
+    private static UnknownSchemaNodeBuilder findUnknownNode(final String name, final Builder parent) {
+        for (UnknownSchemaNodeBuilder un : parent.getUnknownNodes()) {
+            if (un.getQName().getLocalName().equals(name)) {
+                return un;
+            }
+        }
+        return null;
+    }
+
     /**
      *
      * Find a builder for node in data namespace of YANG module.
@@ -492,7 +437,16 @@ public final class BuilderUtils {
         Optional<SchemaNodeBuilder> currentNode = getDataNamespaceChild(module, first);
 
         while (currentNode.isPresent() && path.hasNext()) {
-            currentNode = findDataChild(currentNode.get(), path.next());
+            SchemaNodeBuilder currentParent = currentNode.get();
+            QName currentPath = path.next();
+            currentNode = findDataChild(currentParent, currentPath);
+            if (!currentNode.isPresent()) {
+                for (SchemaNodeBuilder un : currentParent.getUnknownNodes()) {
+                    if (un.getQName().equals(currentPath)) {
+                        currentNode = Optional.of(un);
+                    }
+                }
+            }
         }
         return currentNode;
     }
@@ -534,6 +488,7 @@ public final class BuilderUtils {
         return Optional.absent();
     }
 
+    // FIXME: if rpc does not define input or output, this method creates it
     /**
      *
      * Gets input / output container from {@link RpcDefinitionBuilder} if QName
@@ -547,10 +502,27 @@ public final class BuilderUtils {
      * @return Optional of input/output if defined and QName is input/output.
      *         Otherwise {@link Optional#absent()}.
      */
-    private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent, final QName child) {
+    private static Optional<ContainerSchemaNodeBuilder> findContainerInRpc(final RpcDefinitionBuilder parent,
+            final QName child) {
         if (INPUT.equals(child.getLocalName())) {
+            if (parent.getInput() == null) {
+                QName qname = QName.create(parent.getQName().getModule(), "input");
+                final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(),
+                        parent.getLine(), qname, parent.getPath().createChild(qname));
+                inputBuilder.setParent(parent);
+                parent.setInput(inputBuilder);
+                return Optional.of(inputBuilder);
+            }
             return Optional.of(parent.getInput());
         } else if (OUTPUT.equals(child.getLocalName())) {
+            if (parent.getOutput() == null) {
+                QName qname = QName.create(parent.getQName().getModule(), "output");
+                final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(parent.getModuleName(),
+                        parent.getLine(), qname, parent.getPath().createChild(qname));
+                outputBuilder.setParent(parent);
+                parent.setOutput(outputBuilder);
+                return Optional.of(outputBuilder);
+            }
             return Optional.of(parent.getOutput());
         }
         LOG.trace("Child {} not found in node {}", child, parent);
@@ -671,10 +643,13 @@ public final class BuilderUtils {
      */
     public static boolean processAugmentation(final AugmentationSchemaBuilder augment,
             final ModuleBuilder firstNodeParent) {
-        Optional<SchemaNodeBuilder> potentialTargetNode = findSchemaNodeInModule(augment.getTargetNodeSchemaPath(),
+        Optional<SchemaNodeBuilder> potentialTargetNode = findSchemaNodeInModule(augment.getTargetPath(),
                 firstNodeParent);
         if (!potentialTargetNode.isPresent()) {
             return false;
+        } else if (potentialTargetNode.get() instanceof UnknownSchemaNodeBuilder) {
+            LOG.warn("Error in augment parsing: unsupported augment target: {}", potentialTargetNode.get());
+            return true;
         }
         SchemaNodeBuilder targetNode = potentialTargetNode.get();
         fillAugmentTarget(augment, targetNode);
@@ -685,8 +660,8 @@ public final class BuilderUtils {
         return true;
     }
 
-    public static IdentitySchemaNodeBuilder findBaseIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
-            final ModuleBuilder module, final String baseString, final int line) {
+    public static IdentitySchemaNodeBuilder findBaseIdentity(final ModuleBuilder module, final String baseString,
+            final int line) {
 
         // FIXME: optimize indexOf() away?
         if (baseString.indexOf(':') != -1) {
@@ -698,7 +673,7 @@ public final class BuilderUtils {
                 throw new YangParseException(module.getName(), line, "Failed to parse identityref base: " + baseString);
             }
 
-            ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, prefix, line);
+            ModuleBuilder dependentModule = getModuleByPrefix(module, prefix);
             if (dependentModule == null) {
                 return null;
             }
@@ -733,7 +708,6 @@ public final class BuilderUtils {
         while (!(parent instanceof ModuleBuilder)) {
             parent = parent.getParent();
         }
-        Preconditions.checkState(parent instanceof ModuleBuilder);
         ModuleBuilder parentModule = (ModuleBuilder) parent;
         if (parentModule.isSubmodule()) {
             parentModule = parentModule.getParent();
@@ -742,12 +716,11 @@ public final class BuilderUtils {
     }
 
     public static Set<DataSchemaNodeBuilder> wrapChildNodes(final String moduleName, final int line,
-            final Set<DataSchemaNode> nodes, final SchemaPath parentPath, final URI ns, final Date rev,
-            final String pref) {
-        Set<DataSchemaNodeBuilder> result = new HashSet<>();
+            final Collection<DataSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
+        Set<DataSchemaNodeBuilder> result = new LinkedHashSet<>(nodes.size());
 
         for (DataSchemaNode node : nodes) {
-            QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+            QName qname = QName.create(parentQName, node.getQName().getLocalName());
             DataSchemaNodeBuilder wrapped = wrapChildNode(moduleName, line, node, parentPath, qname);
             result.add(wrapped);
         }
@@ -780,11 +753,10 @@ public final class BuilderUtils {
     }
 
     public static Set<GroupingBuilder> wrapGroupings(final String moduleName, final int line,
-            final Set<GroupingDefinition> nodes, final SchemaPath parentPath, final URI ns, final Date rev,
-            final String pref) {
+            final Set<GroupingDefinition> nodes, final SchemaPath parentPath, final QName parentQName) {
         Set<GroupingBuilder> result = new HashSet<>();
         for (GroupingDefinition node : nodes) {
-            QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+            QName qname = QName.create(parentQName, node.getQName().getLocalName());
             SchemaPath schemaPath = parentPath.createChild(qname);
             result.add(new GroupingBuilderImpl(moduleName, line, qname, schemaPath, node));
         }
@@ -792,12 +764,11 @@ public final class BuilderUtils {
     }
 
     public static Set<TypeDefinitionBuilder> wrapTypedefs(final String moduleName, final int line,
-            final DataNodeContainer dataNode, final SchemaPath parentPath, final URI ns, final Date rev,
-            final String pref) {
+            final DataNodeContainer dataNode, final SchemaPath parentPath, final QName parentQName) {
         Set<TypeDefinition<?>> nodes = dataNode.getTypeDefinitions();
         Set<TypeDefinitionBuilder> result = new HashSet<>();
         for (TypeDefinition<?> node : nodes) {
-            QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+            QName qname = QName.create(parentQName, node.getQName().getLocalName());
             SchemaPath schemaPath = parentPath.createChild(qname);
             result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
         }
@@ -805,11 +776,10 @@ public final class BuilderUtils {
     }
 
     public static List<UnknownSchemaNodeBuilderImpl> wrapUnknownNodes(final String moduleName, final int line,
-            final List<UnknownSchemaNode> nodes, final SchemaPath parentPath, final URI ns, final Date rev,
-            final String pref) {
+            final List<UnknownSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
         List<UnknownSchemaNodeBuilderImpl> result = new ArrayList<>();
         for (UnknownSchemaNode node : nodes) {
-            QName qname = new QName(ns, rev, pref, node.getQName().getLocalName());
+            QName qname = QName.create(parentQName, node.getQName().getLocalName());
             SchemaPath schemaPath = parentPath.createChild(qname);
             result.add(new UnknownSchemaNodeBuilderImpl(moduleName, line, qname, schemaPath, node));
         }
@@ -831,4 +801,81 @@ public final class BuilderUtils {
         }
     }
 
+    public static ModuleBuilder getModuleByPrefix(final ModuleBuilder module, final String prefix) {
+        if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) {
+            return module;
+        } else {
+            return module.getImportedModule(prefix);
+        }
+    }
+
+    public static ModuleBuilder findModule(final QName qname, final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
+        TreeMap<Date, ModuleBuilder> map = modules.get(qname.getNamespace());
+        if (map == null) {
+            return null;
+        }
+        if (qname.getRevision() == null) {
+            return map.lastEntry().getValue();
+        }
+        return map.get(qname.getRevision());
+    }
+
+    public static Map<String, TreeMap<Date, URI>> createYangNamespaceContext(
+            final Collection<? extends ParseTree> modules, final Optional<SchemaContext> context) {
+        Map<String, TreeMap<Date, URI>> map = new HashMap<>();
+        for (ParseTree module : modules) {
+            for (int i = 0; i < module.getChildCount(); i++) {
+                ParseTree moduleTree = module.getChild(i);
+                if (moduleTree instanceof Module_stmtContext) {
+                    Module_stmtContext moduleCtx = (Module_stmtContext) moduleTree;
+                    final String moduleName = ParserListenerUtils.stringFromNode(moduleCtx);
+                    Date rev = null;
+                    URI namespace = null;
+                    for (int j = 0; j < moduleCtx.getChildCount(); j++) {
+                        ParseTree moduleCtxChildTree = moduleCtx.getChild(j);
+                        if (moduleCtxChildTree instanceof Revision_stmtsContext) {
+                            String revisionDateStr = YangModelDependencyInfo
+                                    .getLatestRevision((Revision_stmtsContext) moduleCtxChildTree);
+                            if (revisionDateStr == null) {
+                                rev = new Date(0);
+                            } else {
+                                rev = QName.parseRevision(revisionDateStr);
+                            }
+                        }
+                        if (moduleCtxChildTree instanceof Module_header_stmtsContext) {
+                            Module_header_stmtsContext headerCtx = (Module_header_stmtsContext) moduleCtxChildTree;
+                            for (int k = 0; k < headerCtx.getChildCount(); k++) {
+                                ParseTree ctx = headerCtx.getChild(k);
+                                if (ctx instanceof Namespace_stmtContext) {
+                                    final String namespaceStr = ParserListenerUtils.stringFromNode(ctx);
+                                    namespace = URI.create(namespaceStr);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    TreeMap<Date, URI> revToNs = map.get(moduleName);
+                    if (revToNs == null) {
+                        revToNs = new TreeMap<>();
+                        revToNs.put(rev, namespace);
+                        map.put(moduleName, revToNs);
+                    }
+                    revToNs.put(rev, namespace);
+                }
+            }
+        }
+        if (context.isPresent()) {
+            for (Module module : context.get().getModules()) {
+                TreeMap<Date, URI> revToNs = map.get(module.getName());
+                if (revToNs == null) {
+                    revToNs = new TreeMap<>();
+                    revToNs.put(module.getRevision(), module.getNamespace());
+                    map.put(module.getName(), revToNs);
+                }
+                revToNs.put(module.getRevision(), module.getNamespace());
+            }
+        }
+        return map;
+    }
+
 }