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 com.google.common.io.ByteStreams;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.net.URI;
import java.util.ArrayList;
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.Map.Entry;
+import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
-import org.apache.commons.io.IOUtils;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Belongs_to_stmtContext;
+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.antlrv4.code.gen.YangParser.Submodule_header_stmtsContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Submodule_stmtContext;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * @deprecated Pre-Beryllium implementation, scheduled for removal.
+ */
+@Deprecated
public final class BuilderUtils {
private static final Logger LOG = LoggerFactory.getLogger(BuilderUtils.class);
- 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";
+ private static final String CHILD_NOT_FOUND_IN_NODE_STR = "Child {} not found in node {}";
private BuilderUtils() {
}
});
}
- /**
- * Create new SchemaPath from given path and qname.
- *
- * @param schemaPath
- * base path
- * @param qname
- * one or more qnames added to base path
- * @return new SchemaPath from given path and qname
- *
- * @deprecated Use {@link SchemaPath#createChild(QName...)} instead.
- */
- @Deprecated
- public static SchemaPath createSchemaPath(final SchemaPath schemaPath, final QName... qname) {
- return schemaPath.createChild(qname);
- }
-
/**
* Find dependent module based on given prefix
*
* current line in yang model
* @return module builder if found, null otherwise
*/
- public static ModuleBuilder findModuleFromBuilders(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
+ public static ModuleBuilder findModuleFromBuilders(final Map<String, NavigableMap<Date, ModuleBuilder>> modules,
final ModuleBuilder module, final String prefix, final int line) {
ModuleBuilder dependentModule;
Date dependentModuleRevision;
String dependentModuleName = dependentModuleImport.getModuleName();
dependentModuleRevision = dependentModuleImport.getRevision();
- TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
+ NavigableMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
if (moduleBuildersByRevision == null) {
return null;
}
return dependentModule;
}
+ public static ModuleBuilder findModuleFromBuilders(final ModuleImport imp, final Iterable<ModuleBuilder> modules) {
+ String name = imp.getModuleName();
+ Date revision = imp.getRevision();
+ NavigableMap<Date, ModuleBuilder> map = new TreeMap<>();
+ for (ModuleBuilder module : modules) {
+ if (module != null && 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.
*
*/
public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
final String prefix, final int line) {
- TreeMap<Date, Module> modulesByRevision = new TreeMap<>();
+ NavigableMap<Date, Module> modulesByRevision = new TreeMap<>();
ModuleImport dependentModuleImport = currentModule.getImport(prefix);
if (dependentModuleImport == null) {
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.isEmpty() && xpathString.charAt(0) == '/';
-
- final List<QName> path = new ArrayList<>();
- for (String pathElement : SLASH_SPLITTER.split(xpathString)) {
- final Iterator<String> it = COLON_SPLITTER.split(pathElement).iterator();
- final String s = it.next();
-
- final QName name;
- if (it.hasNext()) {
- name = QName.create(QNameModule.create(null, null), s, it.next());
- } else {
- name = QName.create(QNameModule.create(null, null), s);
- }
- path.add(name);
- }
- return SchemaPath.create(path, absolute);
- }
-
/**
* Add all augment's child nodes to given target.
*
/**
* Set addedByUses flag to true for node and all its child nodes.
*
- * @param node
+ * @param node grouping member node
*/
public static void setNodeAddedByUses(final GroupingMember node) {
node.setAddedByUses(true);
}
}
- public static DataSchemaNodeBuilder findSchemaNode(final List<QName> path, final SchemaNodeBuilder parentNode) {
- DataSchemaNodeBuilder node = null;
+ /**
+ * Find builder of schema node under parent builder (including under
+ * AugmentationSchemaBuilder).
+ *
+ * @param path
+ * - path of target schema node builder
+ * @param parent
+ * - base data node container builder under which the target
+ * schema node builder should be found
+ * @return builder of schema node
+ */
+ public static SchemaNodeBuilder findTargetNode(final Iterable<QName> path,
+ final DataNodeContainerBuilder parent) {
+
+ Preconditions.checkNotNull(parent);
+ Preconditions.checkNotNull(path);
+
+ SchemaNodeBuilder foundNode = null;
+
+ final Iterator<QName> pathIterator = path.iterator();
+ if (pathIterator.hasNext()) {
+ String name = pathIterator.next().getLocalName();
+ foundNode = parent.getDataChildByName(name);
+ if (foundNode == null) {
+ foundNode = findUnknownNode(name, parent);
+ }
+ }
+
+ if (pathIterator.hasNext() && foundNode != null) {
+ return findSchemaNode(Iterables.skip(path, 1), foundNode);
+ } else {
+ return foundNode;
+ }
+ }
+
+ 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)) {
+ if (INPUT.equals(name)) {
node = ((RpcDefinitionBuilder) parent).getInput();
- } else if ("output".equals(name)) {
+ } 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;
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.
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;
}
return castOptional(SchemaNodeBuilder.class, findCaseInChoice((ChoiceBuilder) parent, child));
} else if (parent instanceof RpcDefinitionBuilder) {
return castOptional(SchemaNodeBuilder.class, findContainerInRpc((RpcDefinitionBuilder) parent, child));
-
} else {
- LOG.trace("Child {} not found in node {}", child, parent);
+ LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent);
return Optional.absent();
}
}
* Class to be checked
* @param optional
* Original value
- * @return
+ * @return Optional object with type argument casted as cls
*/
private static <T> Optional<T> castOptional(final Class<T> cls, final Optional<?> optional) {
if (optional.isPresent()) {
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
* @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);
+ LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent);
return Optional.absent();
}
return Optional.of(caze);
}
}
- LOG.trace("Child {} not found in node {}", child, parent);
+ LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent);
return Optional.absent();
}
return Optional.of(childNode);
}
}
- LOG.trace("Child {} not found in node {}", child, parent);
+ LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, parent);
return Optional.absent();
}
Set<NotificationBuilder> notifications = module.getAddedNotifications();
for (NotificationBuilder notification : notifications) {
if (notification.getQName().equals(child)) {
- return Optional.<SchemaNodeBuilder> of(notification);
+ return Optional.of(notification);
}
}
Set<RpcDefinitionBuilder> rpcs = module.getAddedRpcs();
for (RpcDefinitionBuilder rpc : rpcs) {
if (rpc.getQName().equals(child)) {
- return Optional.<SchemaNodeBuilder> of(rpc);
+ return Optional.of(rpc);
}
}
LOG.trace("Child {} not found in data namespace of module {}", child, module);
private static Optional<SchemaNodeBuilder> getDataChildByQName(final DataNodeContainerBuilder builder, final QName child) {
for (DataSchemaNodeBuilder childNode : builder.getChildNodeBuilders()) {
if (childNode.getQName().equals(child)) {
- return Optional.<SchemaNodeBuilder> of(childNode);
+ return Optional.of(childNode);
}
}
- LOG.trace("Child {} not found in node {}", child, builder);
+ LOG.trace(CHILD_NOT_FOUND_IN_NODE_STR, child, builder);
return Optional.absent();
}
* Find augment target node and perform augmentation.
*
* @param augment
+ * augment builder to process
* @param firstNodeParent
* parent of first node in path
- * @param path
- * path to augment target
* @return true if augmentation process succeed, false otherwise
*/
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);
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) {
/**
* Get module in which this node is defined.
*
- * @param node
+ * @param node node
* @return builder of module where this node is defined
*/
public static ModuleBuilder getParentModule(final Builder node) {
}
public static Set<DataSchemaNodeBuilder> wrapChildNodes(final String moduleName, final int line,
- final Set<DataSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
- Set<DataSchemaNodeBuilder> result = new LinkedHashSet<>();
+ final Collection<DataSchemaNode> nodes, final SchemaPath parentPath, final QName parentQName) {
+ Set<DataSchemaNodeBuilder> result = new LinkedHashSet<>(nodes.size());
for (DataSchemaNode node : nodes) {
QName qname = QName.create(parentQName, node.getQName().getLocalName());
final SchemaPath schemaPath = parentPath.createChild(qname);
if (node instanceof AnyXmlSchemaNode) {
- return new AnyXmlBuilder(moduleName, line, qname, schemaPath, ((AnyXmlSchemaNode) node));
- } else if (node instanceof ChoiceNode) {
- return new ChoiceBuilder(moduleName, line, qname, schemaPath, ((ChoiceNode) node));
+ return new AnyXmlBuilder(moduleName, line, qname, schemaPath, (AnyXmlSchemaNode) node);
+ } else if (node instanceof ChoiceSchemaNode) {
+ return new ChoiceBuilder(moduleName, line, qname, schemaPath, (ChoiceSchemaNode) node);
} else if (node instanceof ContainerSchemaNode) {
- return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ContainerSchemaNode) node));
+ return new ContainerSchemaNodeBuilder(moduleName, line, qname, schemaPath, (ContainerSchemaNode) node);
} else if (node instanceof LeafSchemaNode) {
- return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafSchemaNode) node));
+ return new LeafSchemaNodeBuilder(moduleName, line, qname, schemaPath, (LeafSchemaNode) node);
} else if (node instanceof LeafListSchemaNode) {
- return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((LeafListSchemaNode) node));
+ return new LeafListSchemaNodeBuilder(moduleName, line, qname, schemaPath, (LeafListSchemaNode) node);
} else if (node instanceof ListSchemaNode) {
- return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, ((ListSchemaNode) node));
+ return new ListSchemaNodeBuilder(moduleName, line, qname, schemaPath, (ListSchemaNode) node);
} else if (node instanceof ChoiceCaseNode) {
- return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, ((ChoiceCaseNode) node));
+ return new ChoiceCaseBuilder(moduleName, line, qname, schemaPath, (ChoiceCaseNode) node);
} else {
throw new YangParseException(moduleName, line, "Failed to copy node: Unknown type of DataSchemaNode: "
+ node);
for (TypeDefinition<?> node : nodes) {
QName qname = QName.create(parentQName, node.getQName().getLocalName());
SchemaPath schemaPath = parentPath.createChild(qname);
- result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, ((ExtendedType) node)));
+ result.add(new TypeDefinitionBuilderImpl(moduleName, line, qname, schemaPath, (ExtendedType) node));
}
return result;
}
private static final class ByteSourceImpl extends ByteSource {
private final String toString;
- private final ByteArrayOutputStream output = new ByteArrayOutputStream();
+ private final byte[] data;
private ByteSourceImpl(final InputStream input) throws IOException {
toString = input.toString();
- IOUtils.copy(input, output);
+ data = ByteStreams.toByteArray(input);
}
@Override
public InputStream openStream() throws IOException {
- return new NamedByteArrayInputStream(output.toByteArray(), toString);
+ return new NamedByteArrayInputStream(data, toString);
}
}
}
}
+ public static ModuleBuilder findModule(final QName qname, final Map<URI, NavigableMap<Date, ModuleBuilder>> modules) {
+ NavigableMap<Date, ModuleBuilder> map = modules.get(qname.getNamespace());
+ if (map == null) {
+ return null;
+ }
+ if (qname.getRevision() == null) {
+ return map.lastEntry().getValue();
+ }
+
+ final Entry<Date, ModuleBuilder> lastEntry = map.lastEntry();
+ if (qname.getRevision().compareTo(lastEntry.getKey()) > 0) {
+ /*
+ * We are trying to find more recent revision of module than is in
+ * the map. Most probably the yang models are not referenced
+ * correctly and the revision of a base module or submodule has not
+ * been updated along with revision of a referenced module or
+ * submodule. However, we should return the most recent entry in the
+ * map, otherwise the null pointer exception occurs (see Bug3799).
+ */
+ LOG.warn(String
+ .format("Attempt to find more recent revision of module than is available. "
+ + "The requested revision is [%s], but the most recent available revision of module is [%s]."
+ + " Most probably some of Yang models do not have updated revision or they are not "
+ + "referenced correctly.",
+ qname.getRevision(), lastEntry.getKey()));
+ return lastEntry.getValue();
+ }
+
+ return map.get(qname.getRevision());
+ }
+
+ public static Map<String, NavigableMap<Date, URI>> createYangNamespaceContext(
+ final Collection<? extends ParseTree> modules, final Optional<SchemaContext> context) {
+ Map<String, NavigableMap<Date, URI>> namespaceContext = new HashMap<>();
+ Set<Submodule_stmtContext> submodules = new HashSet<>();
+ // first read ParseTree collection and separate modules and submodules
+ for (ParseTree module : modules) {
+ for (int i = 0; i < module.getChildCount(); i++) {
+ ParseTree moduleTree = module.getChild(i);
+ if (moduleTree instanceof Submodule_stmtContext) {
+ // put submodule context to separate collection
+ submodules.add((Submodule_stmtContext) moduleTree);
+ } else if (moduleTree instanceof Module_stmtContext) {
+ // get name, revision and namespace from module
+ 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;
+ }
+ }
+ }
+ }
+ // update namespaceContext
+ NavigableMap<Date, URI> revToNs = namespaceContext.get(moduleName);
+ if (revToNs == null) {
+ revToNs = new TreeMap<>();
+ revToNs.put(rev, namespace);
+ namespaceContext.put(moduleName, revToNs);
+ }
+ revToNs.put(rev, namespace);
+ }
+ }
+ }
+ // after all ParseTree-s are parsed update namespaceContext with modules
+ // from SchemaContext
+ if (context.isPresent()) {
+ for (Module module : context.get().getModules()) {
+ NavigableMap<Date, URI> revToNs = namespaceContext.get(module.getName());
+ if (revToNs == null) {
+ revToNs = new TreeMap<>();
+ revToNs.put(module.getRevision(), module.getNamespace());
+ namespaceContext.put(module.getName(), revToNs);
+ }
+ revToNs.put(module.getRevision(), module.getNamespace());
+ }
+ }
+ // when all modules are processed, traverse submodules and update
+ // namespaceContext with mapping for submodules
+ for (Submodule_stmtContext submodule : submodules) {
+ final String moduleName = ParserListenerUtils.stringFromNode(submodule);
+ for (int i = 0; i < submodule.getChildCount(); i++) {
+ ParseTree subHeaderCtx = submodule.getChild(i);
+ if (subHeaderCtx instanceof Submodule_header_stmtsContext) {
+ for (int j = 0; j < subHeaderCtx.getChildCount(); j++) {
+ ParseTree belongsCtx = subHeaderCtx.getChild(j);
+ if (belongsCtx instanceof Belongs_to_stmtContext) {
+ final String belongsTo = ParserListenerUtils.stringFromNode(belongsCtx);
+ NavigableMap<Date, URI> ns = namespaceContext.get(belongsTo);
+ if (ns == null) {
+ throw new YangParseException(moduleName, submodule.getStart().getLine(), String.format(
+ "Unresolved belongs-to statement: %s", belongsTo));
+ }
+ // submodule get namespace and revision from module
+ NavigableMap<Date, URI> subNs = new TreeMap<>();
+ subNs.put(ns.firstKey(), ns.firstEntry().getValue());
+ namespaceContext.put(moduleName, subNs);
+ }
+ }
+ }
+ }
+ }
+ return namespaceContext;
+ }
+
}