From d69a6a9b2ec6b13c2c83d01c05219ccea880e56c Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 29 Jun 2020 23:24:15 +0200 Subject: [PATCH] Disconnect StmtNamespaceContext from statement Retaining a reference to any StmtContext is not good, as we end up retaining the entire build context from each parsed XPath. Make sure we maintain a simple disconnected YangNamespaceContext implementation at each root. JIRA: YANGTOOLS-1116 Change-Id: Ic327647b758c83b94bde05a740c51384f70c4d03 Signed-off-by: Robert Varga --- .../namespace/StmtNamespaceContext.java | 75 +++++++++++++++++++ .../YangNamespaceContextNamespace.java | 36 +++++++++ .../rfc7950/reactor/RFC7950Reactors.java | 2 + .../rfc7950/stmt/StmtNamespaceContext.java | 47 ------------ .../parser/rfc7950/stmt/XPathSupport.java | 4 +- 5 files changed, 116 insertions(+), 48 deletions(-) create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/StmtNamespaceContext.java create mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/YangNamespaceContextNamespace.java delete mode 100644 yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/StmtNamespaceContext.java diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/StmtNamespaceContext.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/StmtNamespaceContext.java new file mode 100644 index 0000000000..38bd6c144a --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/StmtNamespaceContext.java @@ -0,0 +1,75 @@ +/* + * 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.rfc7950.namespace; + +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableMap; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import javax.xml.namespace.NamespaceContext; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.YangNamespaceContext; +import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleName; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx; +import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName; +import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName; + +/** + * A {@link NamespaceContext} implementation based on the set of imports and local module namespace. + */ +// TODO: this is a useful utility, so it may be useful to expose it either in this package, or yang.parser.spi.source +final class StmtNamespaceContext implements YangNamespaceContext { + private static final long serialVersionUID = 1L; + + private final ImmutableBiMap moduleToPrefix; + private final ImmutableMap prefixToModule; + + StmtNamespaceContext(final StmtContext ctx) { + // QNameModule -> prefix mappings + final Map qnameToPrefix = ctx.getAllFromNamespace(ModuleQNameToPrefix.class); + this.moduleToPrefix = qnameToPrefix == null ? ImmutableBiMap.of() : ImmutableBiMap.copyOf(qnameToPrefix); + + // Additional mappings + final Map> imports = ctx.getAllFromNamespace(ImportPrefixToModuleCtx.class); + if (imports != null) { + final Map additional = new HashMap<>(); + for (Entry> entry : imports.entrySet()) { + if (!moduleToPrefix.containsValue(entry.getKey())) { + QNameModule qnameModule = ctx.getFromNamespace(ModuleCtxToModuleQName.class, entry.getValue()); + if (qnameModule == null && ctx.producesDeclared(SubmoduleStatement.class)) { + final String moduleName = ctx.getFromNamespace(BelongsToPrefixToModuleName.class, + entry.getKey()); + qnameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class, moduleName); + } + + if (qnameModule != null) { + additional.put(entry.getKey(), qnameModule); + } + } + } + this.prefixToModule = ImmutableMap.copyOf(additional); + } else { + this.prefixToModule = ImmutableMap.of(); + } + } + + @Override + public Optional findPrefixForNamespace(final QNameModule namespace) { + return Optional.ofNullable(moduleToPrefix.get(namespace)); + } + + @Override + public Optional findNamespaceForPrefix(final String prefix) { + final QNameModule normal = moduleToPrefix.inverse().get(prefix); + return normal != null ? Optional.of(normal) : Optional.ofNullable(prefixToModule.get(prefix)); + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/YangNamespaceContextNamespace.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/YangNamespaceContextNamespace.java new file mode 100644 index 0000000000..4334479d55 --- /dev/null +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/namespace/YangNamespaceContextNamespace.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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.rfc7950.namespace; + +import static com.google.common.base.Verify.verify; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.yangtools.yang.common.Empty; +import org.opendaylight.yangtools.yang.common.YangNamespaceContext; +import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; +import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; +import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; + +@Beta +public interface YangNamespaceContextNamespace extends IdentifierNamespace { + NamespaceBehaviour BEHAVIOUR = + NamespaceBehaviour.rootStatementLocal(YangNamespaceContextNamespace.class); + + static @NonNull YangNamespaceContext computeIfAbsent(final StmtContext ctx) { + final StmtContext root = ctx.getRoot(); + YangNamespaceContext ret = root.getFromNamespace(YangNamespaceContextNamespace.class, Empty.getInstance()); + if (ret == null) { + verify(ctx instanceof Mutable, "Cannot populate namespace context to %s", ctx); + ret = new StmtNamespaceContext(ctx); + ((Mutable)ctx).addToNs(YangNamespaceContextNamespace.class, Empty.getInstance(), ret); + } + return ret; + } +} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/RFC7950Reactors.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/RFC7950Reactors.java index 5a61ebef02..0f3afed61c 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/RFC7950Reactors.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/reactor/RFC7950Reactors.java @@ -19,6 +19,7 @@ import org.opendaylight.yangtools.yang.parser.openconfig.stmt.OpenConfigVersionS import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ChildSchemaNodeNamespace; import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ModuleQNameToPrefix; import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.URIStringToImportPrefix; +import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.YangNamespaceContextNamespace; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.XPathSupport; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.action.ActionStatementSupport; import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.anydata.AnydataStatementSupport; @@ -391,6 +392,7 @@ public final class RFC7950Reactors { .addSupport(FeatureStatementSupport.getInstance()) .addSupport(PositionStatementSupport.getInstance()) .addSupport(ValueStatementSupport.getInstance()) + .addSupport(YangNamespaceContextNamespace.BEHAVIOUR) .build(); } } diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/StmtNamespaceContext.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/StmtNamespaceContext.java deleted file mode 100644 index bdff19e551..0000000000 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/StmtNamespaceContext.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.rfc7950.stmt; - -import static java.util.Objects.requireNonNull; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import java.util.Optional; -import javax.xml.namespace.NamespaceContext; -import org.opendaylight.yangtools.yang.common.QNameModule; -import org.opendaylight.yangtools.yang.common.YangNamespaceContext; -import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.ModuleQNameToPrefix; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; -import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; - -/** - * A {@link NamespaceContext} implementation based on the set of imports and local module namespace. - */ -// TODO: this is a useful utility, so it may be useful to expose it either in this package, or yang.parser.spi.source, -// but that requires dealing with serialization below. -final class StmtNamespaceContext implements YangNamespaceContext { - private static final long serialVersionUID = 1L; - - // FIXME: deal with serialization by serializing the underlying namespace Map - @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "Not passed to serialization") - private final StmtContext ctx; - - StmtNamespaceContext(final StmtContext ctx) { - this.ctx = requireNonNull(ctx); - } - - @Override - public Optional findPrefixForNamespace(final QNameModule namespace) { - return Optional.ofNullable(ctx.getFromNamespace(ModuleQNameToPrefix.class, namespace)); - } - - @Override - public Optional findNamespaceForPrefix(final String prefix) { - // TODO: perform caching? - return Optional.ofNullable(StmtContextUtils.getModuleQNameByPrefix(ctx, prefix)); - } -} diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/XPathSupport.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/XPathSupport.java index a5bc3f462e..6043d0e86d 100644 --- a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/XPathSupport.java +++ b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/XPathSupport.java @@ -14,6 +14,7 @@ import javax.xml.xpath.XPathExpressionException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath; import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl; +import org.opendaylight.yangtools.yang.parser.rfc7950.namespace.YangNamespaceContextNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression.QualifiedBound; import org.opendaylight.yangtools.yang.xpath.api.YangXPathParser; @@ -34,7 +35,8 @@ public final class XPathSupport { public RevisionAwareXPath parseXPath(final StmtContext ctx, final String xpath) { final boolean isAbsolute = ArgumentUtils.isAbsoluteXPath(xpath); - final YangXPathParser.QualifiedBound parser = factory.newParser(new StmtNamespaceContext(ctx)); + final YangXPathParser.QualifiedBound parser = factory.newParser( + YangNamespaceContextNamespace.computeIfAbsent(ctx)); final QualifiedBound parsed; try { parsed = parser.parseExpression(xpath); -- 2.36.6