+ 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;
+ }
+