From: Robert Varga Date: Fri, 2 Oct 2015 22:43:19 +0000 (+0200) Subject: Use a proper NamespaceContext for XPaths X-Git-Tag: release/beryllium~215 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=ae9af9e65c08648c6308184ce3c8c8273e2b5c25;p=yangtools.git Use a proper NamespaceContext for XPaths Parsing an XPath which contains namespace prefixes requires a NamespaceContext. Create a StmtContext-backed implementation and pass it to XPath before we attempt to parse an XPath string. Change-Id: Ib28cac2525ffcb6b8e3026e19e431cb9dc86c14b Signed-off-by: Robert Varga --- diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java index dd73f6c484..0dbd2c3ee3 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/ImportStatementDefinition.java @@ -15,13 +15,13 @@ import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement; +import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement; import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement; import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement; import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleIdentifierImpl; @@ -34,12 +34,10 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prereq import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier; -import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ImportEffectiveStatementImpl; public class ImportStatementDefinition - extends - AbstractStatementSupport> { + extends AbstractStatementSupport> { public ImportStatementDefinition() { super(Rfc6020Mapping.IMPORT); @@ -64,44 +62,38 @@ public class ImportStatementDefinition @Override public void onLinkageDeclared( - final Mutable> stmt) - throws SourceException { + final Mutable> stmt) { final ModuleIdentifier impIdentifier = getImportedModuleIdentifier(stmt); - ModelActionBuilder importAction = stmt - .newInferenceAction(SOURCE_LINKAGE); - final Prerequisite> imported; - final Prerequisite> linkageTarget; - imported = importAction.requiresCtx(stmt, ModuleNamespace.class, - impIdentifier, SOURCE_LINKAGE); - linkageTarget = importAction.mutatesCtx(stmt.getRoot(), SOURCE_LINKAGE); + final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE); + final Prerequisite> imported = importAction.requiresCtx(stmt, ModuleNamespace.class, + impIdentifier, SOURCE_LINKAGE); + final Prerequisite> linkageTarget = importAction.mutatesCtx(stmt.getRoot(), SOURCE_LINKAGE); importAction.apply(new InferenceAction() { - @Override public void apply() throws InferenceException { StmtContext importedModule = null; ModuleIdentifier importedModuleIdentifier = null; if (impIdentifier.getRevision() == SimpleDateFormatUtil.DEFAULT_DATE_IMP) { Entry>> recentModuleEntry = findRecentModule( - impIdentifier, - stmt.getAllFromNamespace(ModuleNamespace.class)); + impIdentifier, stmt.getAllFromNamespace(ModuleNamespace.class)); if (recentModuleEntry != null) { importedModuleIdentifier = recentModuleEntry.getKey(); importedModule = recentModuleEntry.getValue(); } } - if(importedModule == null || importedModuleIdentifier == null) { + if (importedModule == null || importedModuleIdentifier == null) { importedModule = imported.get(); importedModuleIdentifier = impIdentifier; } - linkageTarget.get().addToNs(ImportedModuleContext.class, - importedModuleIdentifier, importedModule); - String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), - PrefixStatement.class); - stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, - importedModuleIdentifier); + linkageTarget.get().addToNs(ImportedModuleContext.class, importedModuleIdentifier, importedModule); + String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class); + stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, importedModuleIdentifier); + + final URI modNs = firstAttributeOf(importedModule.declaredSubstatements(), NamespaceStatement.class); + stmt.addToNs(URIStringToImpPrefix.class, modNs.toString(), impPrefix); } private Entry>> findRecentModule( @@ -111,17 +103,9 @@ public class ImportStatementDefinition ModuleIdentifier recentModuleIdentifier = impIdentifier; Entry>> recentModuleEntry = null; - Set>>> moduleEntrySet = allModules - .entrySet(); - for (Entry>> moduleEntry : moduleEntrySet) { - if (moduleEntry.getKey().getName() - .equals(impIdentifier.getName()) - && moduleEntry - .getKey() - .getRevision() - .compareTo( - recentModuleIdentifier - .getRevision()) > 0) { + for (Entry>> moduleEntry : allModules.entrySet()) { + if (moduleEntry.getKey().getName().equals(impIdentifier.getName()) + && moduleEntry.getKey().getRevision().compareTo(recentModuleIdentifier.getRevision()) > 0) { recentModuleIdentifier = moduleEntry.getKey(); recentModuleEntry = moduleEntry; } @@ -131,29 +115,22 @@ public class ImportStatementDefinition } @Override - public void prerequisiteFailed( - final Collection> failed) - throws InferenceException { + public void prerequisiteFailed(final Collection> failed) { if (failed.contains(imported)) { - throw new InferenceException(String.format( - "Imported module [%s] was not found.", - impIdentifier), stmt.getStatementSourceReference()); + throw new InferenceException(String.format("Imported module [%s] was not found.", impIdentifier), + stmt.getStatementSourceReference()); } } }); } - private static ModuleIdentifier getImportedModuleIdentifier( - final Mutable stmt) throws SourceException { - - String moduleName = stmt.getStatementArgument(); - Date revision = firstAttributeOf(stmt.declaredSubstatements(), - RevisionDateStatement.class); + private static ModuleIdentifier getImportedModuleIdentifier(final Mutable stmt) { + Date revision = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class); if (revision == null) { revision = SimpleDateFormatUtil.DEFAULT_DATE_IMP; } - return new ModuleIdentifierImpl(moduleName, Optional. absent(), + return new ModuleIdentifierImpl(stmt.getStatementArgument(), Optional. absent(), Optional. of(revision)); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/StmtNamespaceContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/StmtNamespaceContext.java new file mode 100644 index 0000000000..8a54ec2553 --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/StmtNamespaceContext.java @@ -0,0 +1,74 @@ +/* + * 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 + */ +package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; + +import com.google.common.base.Preconditions; +import com.google.common.base.Verify; +import com.google.common.collect.Iterators; +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; + +/** + * A {@link NamespaceContext} implementation based on the set of imports and local module namespace. + * + * TODO: this is a useful utility, so should probably move to yang.parser.spi.meta. + */ +final class StmtNamespaceContext implements NamespaceContext { + private final StmtContext ctx; + private String localNamespaceURI; + + private StmtNamespaceContext(final StmtContext ctx) { + this.ctx = Preconditions.checkNotNull(ctx); + } + + public static NamespaceContext create(final StmtContext ctx) { + return new StmtNamespaceContext(ctx); + } + + private String localNamespaceURI() { + if (localNamespaceURI == null) { + localNamespaceURI = Verify.verifyNotNull( + ctx.getPublicDefinition().getStatementName().getNamespace().toString(), + "Local namespace URI not found in %s", ctx); + } + return localNamespaceURI; + } + + @Override + public String getNamespaceURI(final String prefix) { + // API-mandated by NamespaceContext + Preconditions.checkArgument(prefix != null); + + if (prefix.isEmpty()) { + return localNamespaceURI(); + } + + final QNameModule module = Utils.getModuleQNameByPrefix(ctx, prefix); + return module == null ? null : module.getNamespace().toString(); + } + + @Override + public String getPrefix(final String namespaceURI) { + // API-mandated by NamespaceContext + Preconditions.checkArgument(namespaceURI != null); + + if (localNamespaceURI().equals(namespaceURI)) { + return ""; + } + return ctx.getFromNamespace(URIStringToImpPrefix.class, namespaceURI); + } + + @Override + public Iterator getPrefixes(final String namespaceURI) { + // Ensures underlying map remains constant + return Iterators.unmodifiableIterator( + ctx.getAllFromNamespace(URIStringToImpPrefix.class).values().iterator()); + } +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java new file mode 100644 index 0000000000..35a958b55b --- /dev/null +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/URIStringToImpPrefix.java @@ -0,0 +1,18 @@ +/* + * 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 + */ +package org.opendaylight.yangtools.yang.parser.stmt.rfc6020; + +import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; + +/** + * Implementation-internal cache for looking up URI -> import prefix. URIs are taken in as Strings to save ourselves + * some quality parsing time. + */ +interface URIStringToImpPrefix extends IdentifierNamespace { + +} diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java index 32ab655db7..806857fabf 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/Utils.java @@ -122,6 +122,7 @@ public final class Utils { static RevisionAwareXPath parseXPath(final StmtContext ctx, final String path) { final XPath xPath = XPATH_FACTORY.get().newXPath(); + xPath.setNamespaceContext(StmtNamespaceContext.create(ctx)); final String trimmed = trimSingleLastSlashFromXPath(path); try { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java index 6dd2595d3e..e424c9a235 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangInferencePipeline.java @@ -73,6 +73,7 @@ public final class YangInferencePipeline { .addSupport(sourceLocal(IncludedModuleContext.class)) .addSupport(sourceLocal(IncludedSubmoduleNameToIdentifier.class)) .addSupport(sourceLocal(ImpPrefixToModuleIdentifier.class)) + .addSupport(sourceLocal(URIStringToImpPrefix.class)) .addSupport(sourceLocal(BelongsToModuleContext.class)) .addSupport(sourceLocal(QNameToStatementDefinition.class)) .addSupport(sourceLocal(BelongsToPrefixToModuleName.class)).build();