From a8b6aec2bf3770000f25d9d91ca797d41c1d9d52 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Wed, 27 Feb 2019 12:17:48 +0100 Subject: [PATCH] Add ModuleNameNamespaceContext This adds a utility YangNamespaceContext, which maps QNameModules to their corresponding module name as contained in a SchemaContext. Change-Id: I3be6316d0e7c1f9f98439e3bca3b9b0d385f63bb Signed-off-by: Robert Varga --- .../common/BiMapYangNamespaceContext.java | 34 +++++--- .../common/BiMapYangNamespaceContextTest.java | 12 +-- .../util/ModuleNameNamespaceContext.java | 83 +++++++++++++++++++ 3 files changed, 113 insertions(+), 16 deletions(-) create mode 100644 yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/ModuleNameNamespaceContext.java diff --git a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContext.java b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContext.java index 96edd486be..9cc9e0e2e6 100644 --- a/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContext.java +++ b/yang/yang-common/src/main/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContext.java @@ -24,9 +24,9 @@ import java.util.Optional; import org.opendaylight.yangtools.concepts.WritableObject; /** - * A BiMap-based implementation of {@link YangNamespaceContext}. This implementation requires the default namespace - * to be present. + * A BiMap-based implementation of {@link YangNamespaceContext}. * + * @author Robert Varga */ @Beta public final class BiMapYangNamespaceContext implements YangNamespaceContext, WritableObject { @@ -35,16 +35,23 @@ public final class BiMapYangNamespaceContext implements YangNamespaceContext, Wr private final ImmutableBiMap mapping; private final QNameModule defaultNamespace; - public BiMapYangNamespaceContext(final QNameModule defaultNamespace, final BiMap mapping) { - this.defaultNamespace = requireNonNull(defaultNamespace); - checkArgument(mapping.containsValue(defaultNamespace), "Mapping %s does not contain default namespace %s", - mapping, defaultNamespace); + public BiMapYangNamespaceContext(final BiMap mapping) { + this(mapping, null); + } + + public BiMapYangNamespaceContext(final BiMap mapping, + final QNameModule defaultNamespace) { + this.defaultNamespace = defaultNamespace; this.mapping = ImmutableBiMap.copyOf(mapping); + if (defaultNamespace != null) { + checkArgument(this.mapping.containsValue(defaultNamespace), + "Mapping %s does not contain default namespace %s", this.mapping, defaultNamespace); + } } @Override public Optional getDefaultNamespace() { - return Optional.of(defaultNamespace); + return Optional.ofNullable(defaultNamespace); } @Override @@ -59,7 +66,13 @@ public final class BiMapYangNamespaceContext implements YangNamespaceContext, Wr @Override public void writeTo(final DataOutput out) throws IOException { - defaultNamespace.writeTo(out); + if (defaultNamespace != null) { + out.writeBoolean(true); + defaultNamespace.writeTo(out); + } else { + out.writeBoolean(false); + } + out.writeInt(mapping.size()); for (Entry entry : mapping.entrySet()) { out.writeUTF(entry.getKey()); @@ -68,7 +81,8 @@ public final class BiMapYangNamespaceContext implements YangNamespaceContext, Wr } public static BiMapYangNamespaceContext readFrom(final DataInput in) throws IOException { - final QNameModule defaultNamespace = QNameModule.readFrom(in); + final boolean haveDefault = in.readBoolean(); + final QNameModule defaultNamespace = haveDefault ? QNameModule.readFrom(in) : null; final int size = in.readInt(); final Builder builder = ImmutableBiMap.builder(); for (int i = 0; i < size; ++i) { @@ -77,7 +91,7 @@ public final class BiMapYangNamespaceContext implements YangNamespaceContext, Wr builder.put(prefix, namespace); } - return new BiMapYangNamespaceContext(defaultNamespace, builder.build()); + return new BiMapYangNamespaceContext(builder.build(), defaultNamespace); } @Override diff --git a/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContextTest.java b/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContextTest.java index a4a697d324..0a15d92b5c 100644 --- a/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContextTest.java +++ b/yang/yang-common/src/test/java/org/opendaylight/yangtools/yang/common/BiMapYangNamespaceContextTest.java @@ -26,12 +26,12 @@ public class BiMapYangNamespaceContextTest { private static final QNameModule BAR = QNameModule.create(URI.create("bar")); private static final QNameModule BAZ = QNameModule.create(URI.create("baz")); - private final BiMapYangNamespaceContext context = new BiMapYangNamespaceContext(FOO, - ImmutableBiMap.of("foo", FOO, "bar", BAR)); + private final BiMapYangNamespaceContext context = new BiMapYangNamespaceContext( + ImmutableBiMap.of("foo", FOO, "bar", BAR), FOO); @Test(expected = IllegalArgumentException.class) public void testUnmappedDefault() { - new BiMapYangNamespaceContext(FOO, ImmutableBiMap.of()); + new BiMapYangNamespaceContext(ImmutableBiMap.of(), FOO); } @Test @@ -42,10 +42,10 @@ public class BiMapYangNamespaceContextTest { @Test public void testEquals() { assertTrue(context.equals(context)); - assertTrue(context.equals(new BiMapYangNamespaceContext(FOO, ImmutableBiMap.of("foo", FOO, "bar", BAR)))); + assertTrue(context.equals(new BiMapYangNamespaceContext(ImmutableBiMap.of("foo", FOO, "bar", BAR), FOO))); assertFalse(context.equals(null)); - assertFalse(context.equals(new BiMapYangNamespaceContext(FOO, ImmutableBiMap.of("foo", FOO)))); - assertFalse(context.equals(new BiMapYangNamespaceContext(BAR, ImmutableBiMap.of("bar", BAR)))); + assertFalse(context.equals(new BiMapYangNamespaceContext(ImmutableBiMap.of("foo", FOO), FOO))); + assertFalse(context.equals(new BiMapYangNamespaceContext(ImmutableBiMap.of("bar", BAR), BAR))); } @Test diff --git a/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/ModuleNameNamespaceContext.java b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/ModuleNameNamespaceContext.java new file mode 100644 index 0000000000..7336b342fa --- /dev/null +++ b/yang/yang-model-util/src/main/java/org/opendaylight/yangtools/yang/model/util/ModuleNameNamespaceContext.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019 Pantheon Technologies, s.r.o. 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.model.util; + +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.collect.ImmutableBiMap.Builder; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.Optional; +import java.util.stream.Collectors; +import org.opendaylight.yangtools.yang.common.BiMapYangNamespaceContext; +import org.opendaylight.yangtools.yang.common.QNameModule; +import org.opendaylight.yangtools.yang.common.YangNamespaceContext; +import org.opendaylight.yangtools.yang.model.api.Module; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider; + +/** + * Utility {@link YangNamespaceContext} backed by a SchemaContext, resolving namespaces to their module names. This + * is useful for implementing namespace resolution according to + * RFC7951 Section 4. + * + *

+ * When multiple revisions of a particular namespace are present in the backing SchemaContext, this ambiguity is + * resolved by using the latest revision available. + * + * @author Robert Varga + */ +@Beta +public final class ModuleNameNamespaceContext implements YangNamespaceContext, SchemaContextProvider { + private static final long serialVersionUID = 1L; + + @SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "Handled through writeReplace()") + private final SchemaContext schemaContext; + + public ModuleNameNamespaceContext(final SchemaContext schemaContext) { + this.schemaContext = requireNonNull(schemaContext); + } + + /** + * Convert this object to an equivalent {@link BiMapYangNamespaceContext}. + * + * @return A BiMapYangNamespaceContext. + */ + public BiMapYangNamespaceContext toBiMap() { + final Builder builder = ImmutableBiMap.builder(); + for (String name : schemaContext.getModules().stream().map(Module::getName).collect(Collectors.toSet())) { + builder.put(name, findNamespaceForPrefix(name).get()); + } + return new BiMapYangNamespaceContext(builder.build()); + } + + @Override + public SchemaContext getSchemaContext() { + return schemaContext; + } + + @Override + public Optional getDefaultNamespace() { + throw new IllegalStateException("No default namespace is available"); + } + + @Override + public Optional findNamespaceForPrefix(final String prefix) { + return schemaContext.findModules(prefix).stream().findFirst().map(Module::getQNameModule); + } + + @Override + public Optional findPrefixForNamespace(final QNameModule namespace) { + return schemaContext.findModule(namespace).map(Module::getName); + } + + private Object writeReplace() { + return toBiMap(); + } +} -- 2.36.6