From 1497be11d9796ae8b107291bc7b780933fa5d557 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 15 Oct 2020 20:40:35 +0200 Subject: [PATCH] Add support for formatting EffectiveModelContext Introduce a fluent-builder like pattern so we have the option to override various options of the resulting output. JIRA: MDSAL-596 Change-Id: I1929664db4262b0428e078b4712844b4bc2679b9 Signed-off-by: Robert Varga Signed-off-by: Tomas Cere (cherry picked from commit 9771d77935524f7bfb54bcf5169cf600a3b3c71b) --- .../mdsal/yanglib/api/YangLibSupport.java | 12 +- .../yanglib/api/YangLibSupportFactory.java | 3 +- .../api/YangLibraryContentBuilder.java | 55 ++++++++ .../YangLibraryContentBuilderWithLegacy.java | 23 ++++ .../yanglib/spi/ForwardingYangLibSupport.java | 6 + yanglib/mdsal-yanglib-rfc7895/pom.xml | 10 ++ .../rfc7895/Rfc7895ContentBuilder.java | 108 ++++++++++++++++ .../rfc7895/YangModuleLibrarySupport.java | 9 +- .../YangModuleLibrarySupportFactory.java | 9 +- .../rfc7895/YangModuleLibrarySupportTest.java | 88 +++++++++++++ yanglib/mdsal-yanglib-rfc8525/pom.xml | 10 ++ .../yanglib/rfc8525/LegacyContentBuilder.java | 104 +++++++++++++++ .../YangLibraryContentBuilderImpl.java | 119 ++++++++++++++++++ .../yanglib/rfc8525/YangLibrarySupport.java | 9 +- .../rfc8525/YangLibrarySupportFactory.java | 9 +- .../rfc8525/LegacyYangLibraryFormatTest.java | 105 ++++++++++++++++ .../rfc8525/YangLibrarySupportTest.java | 93 ++++++++++++++ 17 files changed, 760 insertions(+), 12 deletions(-) create mode 100644 yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilder.java create mode 100644 yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilderWithLegacy.java create mode 100644 yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/Rfc7895ContentBuilder.java create mode 100644 yanglib/mdsal-yanglib-rfc7895/src/test/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportTest.java create mode 100644 yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyContentBuilder.java create mode 100644 yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibraryContentBuilderImpl.java create mode 100644 yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyYangLibraryFormatTest.java create mode 100644 yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportTest.java diff --git a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupport.java b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupport.java index 29135a2a6e..4a87c7dba3 100644 --- a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupport.java +++ b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupport.java @@ -14,7 +14,7 @@ import org.opendaylight.yangtools.rfc8528.data.api.MountPointIdentifier; import org.opendaylight.yangtools.yang.common.Revision; /** - * Main entrypoint into YANG (Module) Library support instance. + * Main entry point into YANG (Module) Library support instance. */ @Beta @NonNullByDefault @@ -22,7 +22,7 @@ public interface YangLibSupport { /** * Create a MountPointContextFactory, backed by a specific SchemaContextResolver. * - * @param mountId Resulting Mount Point identitifer + * @param mountId Resulting Mount Point identifier * @param resolver SchemaContext resolver * @return A new factory * @throws NullPointerException if any argument is null @@ -37,4 +37,12 @@ public interface YangLibSupport { * @return A revision. */ Revision implementedRevision(); + + /** + * Create a new content builder which is used to serialize yang library content into NormalizedNodes. + * This content builder has further options which can influence the resulting content. + * + * @return A new yang library content builder. + */ + YangLibraryContentBuilder newContentBuilder(); } diff --git a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupportFactory.java b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupportFactory.java index 2998c5689f..2c7e752979 100644 --- a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupportFactory.java +++ b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibSupportFactory.java @@ -8,7 +8,6 @@ package org.opendaylight.mdsal.yanglib.api; import com.google.common.annotations.Beta; -import java.io.IOException; import org.eclipse.jdt.annotation.NonNullByDefault; import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; @@ -20,5 +19,5 @@ import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; @NonNullByDefault public interface YangLibSupportFactory { - YangLibSupport createYangLibSupport(YangParserFactory parserFactory) throws YangParserException, IOException; + YangLibSupport createYangLibSupport(YangParserFactory parserFactory) throws YangParserException; } diff --git a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilder.java b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilder.java new file mode 100644 index 0000000000..cee00c17b6 --- /dev/null +++ b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilder.java @@ -0,0 +1,55 @@ +/* + * 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.mdsal.yanglib.api; + +import com.google.common.annotations.Beta; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.opendaylight.yangtools.yang.data.api.DatastoreIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; + +@Beta +@NonNullByDefault +public interface YangLibraryContentBuilder { + /** + * Set the default EffectiveModelContext used for this content builder. + * + * @param modelContext EffectiveModelContext to use for content generation. + * @return this builder + * @throws NullPointerException if any argument is null + */ + YangLibraryContentBuilder defaultContext(EffectiveModelContext modelContext); + + /** + * Add a secondary datastore(s) which use different EffectiveModelContext than the default provided context. + * This/These datastore/s are used in the output encoding of the YANG library. + * + * @param identifier identifies the datastore in the ouput + * @param context EffectiveModelContext of this datastore + * @return this builder + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if this implementation does not support per-datastore contexts and a conflicting + * context is already present. + */ + YangLibraryContentBuilder addDatastore(DatastoreIdentifier identifier, EffectiveModelContext context); + + /** + * Option to include legacy YANG library content in the resulting output. + * + * @return LegacyYangLibraryContentBuilder which generates output that contains YANG library data in + * both legacy and non-legacy format. + */ + YangLibraryContentBuilderWithLegacy includeLegacy(); + + /** + * Format the contents of the YANG library into NormalizedNodes using the provided EffectiveModelContext. + * + * @return List of NormalizedNodes that contain the YANG library content. + */ + ContainerNode formatYangLibraryContent(); +} diff --git a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilderWithLegacy.java b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilderWithLegacy.java new file mode 100644 index 0000000000..446bd038ec --- /dev/null +++ b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/api/YangLibraryContentBuilderWithLegacy.java @@ -0,0 +1,23 @@ +/* + * 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.mdsal.yanglib.api; + +import com.google.common.annotations.Beta; +import java.util.Optional; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; + +@Beta +public interface YangLibraryContentBuilderWithLegacy extends YangLibraryContentBuilder { + /** + * Format legacy content, if applicable. It is guaranteed to be a sibling of the main content returned by + * {@link #formatYangLibraryContent()}. + * + * @return Legacy content, if applicable. + */ + Optional formatYangLibraryLegacyContent(); +} diff --git a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/spi/ForwardingYangLibSupport.java b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/spi/ForwardingYangLibSupport.java index 8296b7d2b3..e8de12e4a4 100644 --- a/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/spi/ForwardingYangLibSupport.java +++ b/yanglib/mdsal-yanglib-api/src/main/java/org/opendaylight/mdsal/yanglib/spi/ForwardingYangLibSupport.java @@ -12,6 +12,7 @@ import com.google.common.collect.ForwardingObject; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.yanglib.api.SchemaContextResolver; import org.opendaylight.mdsal.yanglib.api.YangLibSupport; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilder; import org.opendaylight.yangtools.rfc8528.data.api.MountPointContextFactory; import org.opendaylight.yangtools.rfc8528.data.api.MountPointIdentifier; import org.opendaylight.yangtools.yang.common.Revision; @@ -29,6 +30,11 @@ public abstract class ForwardingYangLibSupport extends ForwardingObject implemen return delegate().implementedRevision(); } + @Override + public YangLibraryContentBuilder newContentBuilder() { + return delegate().newContentBuilder(); + } + @Override protected abstract @NonNull YangLibSupport delegate(); } diff --git a/yanglib/mdsal-yanglib-rfc7895/pom.xml b/yanglib/mdsal-yanglib-rfc7895/pom.xml index be10516eb3..5f8e410f8b 100644 --- a/yanglib/mdsal-yanglib-rfc7895/pom.xml +++ b/yanglib/mdsal-yanglib-rfc7895/pom.xml @@ -61,11 +61,21 @@ yang-parser-impl test + + org.opendaylight.mdsal + mdsal-binding-runtime-spi + test + org.opendaylight.mdsal mdsal-binding-dom-codec test + + org.opendaylight.mdsal + mdsal-binding-generator-impl + test + diff --git a/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/Rfc7895ContentBuilder.java b/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/Rfc7895ContentBuilder.java new file mode 100644 index 0000000000..ba21926a0a --- /dev/null +++ b/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/Rfc7895ContentBuilder.java @@ -0,0 +1,108 @@ +/* + * 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.mdsal.yanglib.rfc7895; + +import static com.google.common.base.Verify.verifyNotNull; + +import com.google.common.annotations.VisibleForTesting; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilder; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilderWithLegacy; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.ModulesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.ModulesStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.RevisionIdentifier; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.CommonLeafs; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.Module; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.ModuleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.module.Submodule; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.module.SubmoduleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.module.SubmoduleKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.DatastoreIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; + +class Rfc7895ContentBuilder implements YangLibraryContentBuilderWithLegacy { + private static final CommonLeafs.Revision EMPTY_REV = new CommonLeafs.Revision(""); + + private final BindingDataObjectCodecTreeNode legacyCodec; + + private EffectiveModelContext context; + + Rfc7895ContentBuilder(final BindingCodecTree codecTree) { + this.legacyCodec = verifyNotNull(codecTree.getSubtreeCodec(InstanceIdentifier.create(ModulesState.class))); + } + + @Override + public Rfc7895ContentBuilder defaultContext(final EffectiveModelContext modelContext) { + this.context = modelContext; + return this; + } + + @Override + public YangLibraryContentBuilder addDatastore(final DatastoreIdentifier identifier, + final EffectiveModelContext newContext) { + // NOOP does not apply for rfc7895 + return this; + } + + @Override + public YangLibraryContentBuilderWithLegacy includeLegacy() { + // NOOP does not apply for rfc7895 + return this; + } + + @Override + public ContainerNode formatYangLibraryContent() { + return formatModulesState(context); + } + + @VisibleForTesting + ContainerNode formatModulesState(final EffectiveModelContext effectiveModelContext) { + Map vals; + // Two-step process: we first build the content and then use hashCode() to generate module-set-id + final ModulesStateBuilder builder = new ModulesStateBuilder().setModuleSetId("") + .setModule(effectiveModelContext.getModules().stream() + .map(module -> new ModuleBuilder() + .setName(new YangIdentifier(module.getName())) + .setNamespace(new Uri(module.getNamespace().toString())) + .setRevision(convertRevision(module.getRevision())) + .setSubmodule(module.getSubmodules().stream() + .map(submodule -> new SubmoduleBuilder() + .setName(new YangIdentifier(submodule.getName())) + .setRevision(convertRevision(submodule.getRevision())) + .build()) + .collect(Collectors.toUnmodifiableMap(Submodule::key, Function.identity()))) + .setFeature(module.getFeatures().stream() + .map(feat -> new YangIdentifier(feat.getQName().getLocalName())) + .collect(Collectors.toUnmodifiableList())) + .setConformanceType(Module.ConformanceType.Implement) + .build()) + .collect(Collectors.toUnmodifiableMap(Module::key, Function.identity()))); + + return (ContainerNode) legacyCodec.serialize(builder.setModuleSetId(String.valueOf(builder.build().hashCode())) + .build()); + } + + private static CommonLeafs.Revision convertRevision(final Optional revision) { + return revision.map(rev -> new CommonLeafs.Revision(new RevisionIdentifier(rev.toString()))).orElse(EMPTY_REV); + } + + @Override + public Optional formatYangLibraryLegacyContent() { + return Optional.of(formatYangLibraryContent()); + } +} diff --git a/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupport.java b/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupport.java index 758cc829dd..67d17320f4 100644 --- a/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupport.java +++ b/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupport.java @@ -22,6 +22,7 @@ import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory; import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; import org.opendaylight.mdsal.yanglib.api.SchemaContextResolver; import org.opendaylight.mdsal.yanglib.api.YangLibSupport; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.$YangModuleInfoImpl; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.ModulesState; import org.opendaylight.yangtools.rfc8528.data.api.MountPointContextFactory; @@ -44,6 +45,7 @@ public final class YangModuleLibrarySupport implements YangLibSupport { private final BindingDataObjectCodecTreeNode codec; private final EffectiveModelContext context; + private final BindingCodecTree codecTree; @Inject public YangModuleLibrarySupport(final YangParserFactory parserFactory, final BindingRuntimeGenerator generator, @@ -55,7 +57,7 @@ public final class YangModuleLibrarySupport implements YangLibSupport { YangModuleLibrarySupport::createSource)) .addSource(createSource(yangLibModule)) .buildEffectiveModel(); - final BindingCodecTree codecTree = codecFactory.create(DefaultBindingRuntimeContext.create( + codecTree = codecFactory.create(DefaultBindingRuntimeContext.create( generator.generateTypeMapping(context), SimpleStrategy.INSTANCE)); this.codec = verifyNotNull(codecTree.getSubtreeCodec(InstanceIdentifier.create(ModulesState.class))); @@ -72,6 +74,11 @@ public final class YangModuleLibrarySupport implements YangLibSupport { return REVISION; } + @Override + public YangLibraryContentBuilder newContentBuilder() { + return new Rfc7895ContentBuilder(codecTree); + } + private static YangTextSchemaSource createSource(final YangModuleInfo info) { final QName name = info.getName(); return YangTextSchemaSource.delegateForByteSource( diff --git a/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportFactory.java b/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportFactory.java index ac4a8df594..ba5378a27c 100644 --- a/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportFactory.java +++ b/yanglib/mdsal-yanglib-rfc7895/src/main/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportFactory.java @@ -39,9 +39,12 @@ public final class YangModuleLibrarySupportFactory implements YangLibSupportFact } @Override - public YangLibSupport createYangLibSupport(final YangParserFactory parserFactory) - throws YangParserException, IOException { - return new YangModuleLibrarySupport(parserFactory, generator, codecFactory); + public YangLibSupport createYangLibSupport(final YangParserFactory parserFactory) throws YangParserException { + try { + return new YangModuleLibrarySupport(parserFactory, generator, codecFactory); + } catch (IOException e) { + throw new YangParserException("Failed to create YangModuleLibrarySupport", e); + } } private static T load(final Class clazz) { diff --git a/yanglib/mdsal-yanglib-rfc7895/src/test/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportTest.java b/yanglib/mdsal-yanglib-rfc7895/src/test/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportTest.java new file mode 100644 index 0000000000..fae491a610 --- /dev/null +++ b/yanglib/mdsal-yanglib-rfc7895/src/test/java/org/opendaylight/mdsal/yanglib/rfc7895/YangModuleLibrarySupportTest.java @@ -0,0 +1,88 @@ +/* + * 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.mdsal.yanglib.rfc7895; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator; +import org.opendaylight.binding.runtime.spi.BindingRuntimeHelpers; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.impl.DefaultBindingCodecTreeFactory; +import org.opendaylight.mdsal.binding.generator.impl.DefaultBindingRuntimeGenerator; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.ModulesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.RevisionIdentifier; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.CommonLeafs.Revision; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.Module; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.Module.ConformanceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.ModuleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev160621.module.list.ModuleKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.parser.impl.YangParserFactoryImpl; + +public class YangModuleLibrarySupportTest { + + private static final BindingRuntimeGenerator BINDING_RUNTIME_GENERATOR = new DefaultBindingRuntimeGenerator(); + + private static final YangParserFactory YANG_PARSER_FACTORY = new YangParserFactoryImpl(); + + private BindingRuntimeContext runtimeContext; + private BindingCodecTree codecTree; + private YangModuleLibrarySupport yangLib; + + @Before + public void setUp() throws IOException, YangParserException { + runtimeContext = BindingRuntimeHelpers.createRuntimeContext(); + final DefaultBindingCodecTreeFactory codecFactory = new DefaultBindingCodecTreeFactory(); + codecTree = codecFactory.create(runtimeContext); + + yangLib = new YangModuleLibrarySupport(YANG_PARSER_FACTORY, BINDING_RUNTIME_GENERATOR, codecFactory); + } + + @Test + public void testModulesState() { + final BindingDataObjectCodecTreeNode legacyCodec = + codecTree.getSubtreeCodec(InstanceIdentifier.create(ModulesState.class)); + final ModulesState modulesState = legacyCodec.deserialize( + yangLib.newContentBuilder().defaultContext( + runtimeContext.getEffectiveModelContext()).formatYangLibraryContent()); + + assertEquals(3, modulesState.nonnullModule().size()); + assertEquals(createControlModules(), modulesState.getModule()); + } + + private static Map createControlModules() { + return Map.of( + new ModuleKey(new YangIdentifier("ietf-yang-library"), new Revision(new RevisionIdentifier("2016-06-21"))), + createModule("ietf-yang-library", "urn:ietf:params:xml:ns:yang:ietf-yang-library", "2016-06-21"), + new ModuleKey(new YangIdentifier("ietf-inet-types"), new Revision(new RevisionIdentifier("2013-07-15"))), + createModule("ietf-inet-types", "urn:ietf:params:xml:ns:yang:ietf-inet-types", "2013-07-15"), + new ModuleKey(new YangIdentifier("ietf-yang-types"), new Revision(new RevisionIdentifier("2013-07-15"))), + createModule("ietf-yang-types", "urn:ietf:params:xml:ns:yang:ietf-yang-types", "2013-07-15")); + } + + private static Module createModule(final String name, final String namespace, final String revision) { + return new ModuleBuilder() + .setName(new YangIdentifier(name)) + .setNamespace(new Uri(namespace)) + .setRevision(new Revision(new RevisionIdentifier(revision))) + .setConformanceType(ConformanceType.Implement) + .setFeature(Collections.emptyList()) + .build(); + } +} \ No newline at end of file diff --git a/yanglib/mdsal-yanglib-rfc8525/pom.xml b/yanglib/mdsal-yanglib-rfc8525/pom.xml index 97872e51db..026ce496d9 100644 --- a/yanglib/mdsal-yanglib-rfc8525/pom.xml +++ b/yanglib/mdsal-yanglib-rfc8525/pom.xml @@ -61,11 +61,21 @@ yang-parser-impl test + + org.opendaylight.mdsal + mdsal-binding-runtime-spi + test + org.opendaylight.mdsal mdsal-binding-dom-codec test + + org.opendaylight.mdsal + mdsal-binding-generator-impl + test + diff --git a/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyContentBuilder.java b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyContentBuilder.java new file mode 100644 index 0000000000..b0020fc17a --- /dev/null +++ b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyContentBuilder.java @@ -0,0 +1,104 @@ +/* + * 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.mdsal.yanglib.rfc8525; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.VisibleForTesting; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilder; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilderWithLegacy; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesStateBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.CommonLeafs; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.ModuleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.Submodule; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.SubmoduleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.DatastoreIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; + +class LegacyContentBuilder implements YangLibraryContentBuilderWithLegacy { + private static final CommonLeafs.Revision EMPTY_REV = new CommonLeafs.Revision(""); + + private final BindingDataObjectCodecTreeNode legacyCodec; + private final YangLibraryContentBuilderImpl delegate; + + LegacyContentBuilder(final YangLibraryContentBuilderImpl delegate, final BindingCodecTree codecTree) { + this.delegate = requireNonNull(delegate); + this.legacyCodec = verifyNotNull(codecTree.getSubtreeCodec(InstanceIdentifier.create(ModulesState.class))); + } + + @Override + public LegacyContentBuilder defaultContext(final EffectiveModelContext context) { + delegate.defaultContext(context); + return this; + } + + @Override + public YangLibraryContentBuilder addDatastore(final DatastoreIdentifier identifier, + final EffectiveModelContext context) { + return delegate.addDatastore(identifier, context); + } + + @Override + public YangLibraryContentBuilderWithLegacy includeLegacy() { + return this; + } + + @Override + public ContainerNode formatYangLibraryContent() { + return delegate.formatYangLibrary(); + } + + @Override + public Optional formatYangLibraryLegacyContent() { + return Optional.of(formatModulesState(requireNonNull(delegate.getModelContext()))); + } + + @VisibleForTesting + ContainerNode formatModulesState(final EffectiveModelContext context) { + // Two-step process: we first build the content and then use hashCode() to generate module-set-id + final ModulesStateBuilder builder = new ModulesStateBuilder().setModuleSetId("") + .setModule(context.getModules().stream() + .map(module -> new ModuleBuilder() + .setName(new YangIdentifier(module.getName())) + .setNamespace(new Uri(module.getNamespace().toString())) + .setRevision(convertRevision(module.getRevision())) + .setSubmodule(module.getSubmodules().stream() + .map(submodule -> new SubmoduleBuilder() + .setName(new YangIdentifier(submodule.getName())) + .setRevision(convertRevision(submodule.getRevision())) + .build()) + .collect(Collectors.toUnmodifiableMap(Submodule::key, Function.identity()))) + .setFeature(module.getFeatures().stream() + .map(feat -> new YangIdentifier(feat.getQName().getLocalName())) + .collect(Collectors.toUnmodifiableList())) + .setConformanceType(Module.ConformanceType.Implement) + .build()) + .collect(Collectors.toUnmodifiableMap(Module::key, Function.identity()))); + + return (ContainerNode) legacyCodec.serialize(builder.setModuleSetId(String.valueOf(builder.build().hashCode())) + .build()); + } + + private static CommonLeafs.Revision convertRevision(final Optional revision) { + return revision.map(rev -> new CommonLeafs.Revision(new RevisionIdentifier(rev.toString()))).orElse(EMPTY_REV); + } +} diff --git a/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibraryContentBuilderImpl.java b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibraryContentBuilderImpl.java new file mode 100644 index 0000000000..c15a1e6254 --- /dev/null +++ b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibraryContentBuilderImpl.java @@ -0,0 +1,119 @@ +/* + * 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.mdsal.yanglib.rfc8525; + +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.base.Verify.verifyNotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilder; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilderWithLegacy; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibrary; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibraryBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.Module; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.ModuleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.module.Submodule; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.module.SubmoduleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSetBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSetKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.data.api.DatastoreIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; + +class YangLibraryContentBuilderImpl implements YangLibraryContentBuilder { + private static final String MODULE_SET_NAME = "ODL_modules"; + + private final Map datastores = new HashMap<>(); + private final BindingDataObjectCodecTreeNode codec; + private final BindingCodecTree codecTree; + + private EffectiveModelContext modelContext; + + YangLibraryContentBuilderImpl(final BindingCodecTree codecTree) { + this.codecTree = Objects.requireNonNull(codecTree); + this.codec = verifyNotNull(codecTree.getSubtreeCodec(InstanceIdentifier.create(YangLibrary.class))); + } + + @Override + public YangLibraryContentBuilder defaultContext(final EffectiveModelContext context) { + modelContext = context; + return this; + } + + EffectiveModelContext getModelContext() { + return modelContext; + } + + @Override + public YangLibraryContentBuilderWithLegacy includeLegacy() { + return new LegacyContentBuilder(this, codecTree); + } + + @Override + public YangLibraryContentBuilder addDatastore(final DatastoreIdentifier identifier, + final EffectiveModelContext context) { + datastores.put(identifier, context); + return this; + } + + @Override + public ContainerNode formatYangLibraryContent() { + checkState(modelContext != null, "EffectiveModelContext is required to format YangLibrary content"); + return formatYangLibrary(); + } + + @NonNull ContainerNode formatYangLibrary() { + // Two-step process: we first build the content and then use hashCode() to generate module-set-id + final YangLibraryBuilder builder = new YangLibraryBuilder().setContentId(""); + final ModuleSetBuilder moduleSetBuilder = new ModuleSetBuilder() + .setModule(modelContext.getModules().stream() + .map(this::buildModule) + .collect(Collectors.toUnmodifiableMap(Module::key, Function.identity()))) + .setName(MODULE_SET_NAME); + final ModuleSet moduleSet = moduleSetBuilder.build(); + + builder.setModuleSet(Map.of(new ModuleSetKey(moduleSet.getName()), moduleSet)); + return (ContainerNode) codec.serialize(builder.setContentId(String.valueOf(builder.build().hashCode())) + .build()); + } + + private Module buildModule(final org.opendaylight.yangtools.yang.model.api.Module module) { + return new ModuleBuilder() + .setName(new YangIdentifier(module.getName())) + .setNamespace(new Uri(module.getQNameModule().getNamespace().toString())) + .setRevision(convertRevision(module.getRevision())) + .setSubmodule(module.getSubmodules().stream() + .map(submodule -> new SubmoduleBuilder() + .setName(new YangIdentifier(submodule.getName())) + .setRevision(convertRevision(submodule.getRevision())) + .build()) + .collect(Collectors.toUnmodifiableMap(Submodule::key, Function.identity()))) + .setFeature(module.getFeatures().stream() + .map(feat -> new YangIdentifier(feat.getQName().getLocalName())) + .collect(Collectors.toUnmodifiableList())) + .build(); + } + + private static RevisionIdentifier convertRevision(final Optional revision) { + return revision.map(rev -> new RevisionIdentifier(rev.toString())).orElse(null); + } +} diff --git a/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupport.java b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupport.java index 4a8c9c3e31..4bfc68b56b 100644 --- a/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupport.java +++ b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupport.java @@ -23,6 +23,7 @@ import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNo import org.opendaylight.mdsal.binding.dom.codec.api.BindingIdentityCodec; import org.opendaylight.mdsal.yanglib.api.SchemaContextResolver; import org.opendaylight.mdsal.yanglib.api.YangLibSupport; +import org.opendaylight.mdsal.yanglib.api.YangLibraryContentBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.$YangModuleInfoImpl; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibrary; @@ -49,6 +50,7 @@ public final class YangLibrarySupport implements YangLibSupport { private final BindingDataObjectCodecTreeNode legacyCodec; private final BindingIdentityCodec identityCodec; private final EffectiveModelContext context; + private final BindingCodecTree codecTree; @Inject public YangLibrarySupport(final YangParserFactory parserFactory, final BindingRuntimeGenerator generator, @@ -60,7 +62,7 @@ public final class YangLibrarySupport implements YangLibSupport { YangLibrarySupport::createSource)) .addSource(createSource(yangLibModule)) .buildEffectiveModel(); - final BindingCodecTree codecTree = codecFactory.create(DefaultBindingRuntimeContext.create( + codecTree = codecFactory.create(DefaultBindingRuntimeContext.create( generator.generateTypeMapping(context), SimpleStrategy.INSTANCE)); this.identityCodec = codecTree.getIdentityCodec(); @@ -79,6 +81,11 @@ public final class YangLibrarySupport implements YangLibSupport { return REVISION; } + @Override + public YangLibraryContentBuilder newContentBuilder() { + return new YangLibraryContentBuilderImpl(codecTree); + } + private static YangTextSchemaSource createSource(final YangModuleInfo info) { final QName name = info.getName(); return YangTextSchemaSource.delegateForByteSource( diff --git a/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportFactory.java b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportFactory.java index 59aeb22eb1..4bb0ce3ea7 100644 --- a/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportFactory.java +++ b/yanglib/mdsal-yanglib-rfc8525/src/main/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportFactory.java @@ -39,9 +39,12 @@ public final class YangLibrarySupportFactory implements YangLibSupportFactory { } @Override - public YangLibSupport createYangLibSupport(final YangParserFactory parserFactory) - throws YangParserException, IOException { - return new YangLibrarySupport(parserFactory, generator, codecFactory); + public YangLibSupport createYangLibSupport(final YangParserFactory parserFactory) throws YangParserException { + try { + return new YangLibrarySupport(parserFactory, generator, codecFactory); + } catch (IOException e) { + throw new YangParserException("Failed to create YangLibrarySupport", e); + } } private static T load(final Class clazz) { diff --git a/yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyYangLibraryFormatTest.java b/yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyYangLibraryFormatTest.java new file mode 100644 index 0000000000..4d0aa39c23 --- /dev/null +++ b/yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/LegacyYangLibraryFormatTest.java @@ -0,0 +1,105 @@ +/* + * 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.mdsal.yanglib.rfc8525; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator; +import org.opendaylight.binding.runtime.spi.BindingRuntimeHelpers; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.impl.DefaultBindingCodecTreeFactory; +import org.opendaylight.mdsal.binding.generator.impl.DefaultBindingRuntimeGenerator; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.CommonLeafs.Revision; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module.ConformanceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.ModuleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.ModuleKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserException; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.parser.impl.YangParserFactoryImpl; + +public class LegacyYangLibraryFormatTest { + + private static final BindingRuntimeGenerator BINDING_RUNTIME_GENERATOR = new DefaultBindingRuntimeGenerator(); + + private static final YangParserFactory YANG_PARSER_FACTORY = new YangParserFactoryImpl(); + + private BindingRuntimeContext runtimeContext; + private BindingCodecTree codecTree; + private YangLibrarySupport yangLib; + + @Before + public void setUp() throws IOException, YangParserException { + runtimeContext = BindingRuntimeHelpers.createRuntimeContext(); + final DefaultBindingCodecTreeFactory codecFactory = new DefaultBindingCodecTreeFactory(); + yangLib = new YangLibrarySupport(YANG_PARSER_FACTORY, BINDING_RUNTIME_GENERATOR, + codecFactory); + codecTree = codecFactory.create(runtimeContext); + } + + @Test + public void testLegacyFormat() { + final BindingDataObjectCodecTreeNode legacyCodec = + codecTree.getSubtreeCodec(InstanceIdentifier.create(ModulesState.class)); + + final Optional legacyContent = yangLib.newContentBuilder() + .defaultContext(runtimeContext.getEffectiveModelContext()) + .includeLegacy() + .formatYangLibraryLegacyContent(); + + assertTrue(legacyContent.isPresent()); + + final ModulesState modulesState = legacyCodec.deserialize(legacyContent.orElseThrow()); + + assertEquals(4, modulesState.nonnullModule().size()); + assertEquals(createControlModules(), modulesState.getModule()); + } + + private Map createControlModules() { + final Map modules = new HashMap<>(); + modules.put(new ModuleKey(new YangIdentifier("ietf-yang-library"), + new Revision(new RevisionIdentifier("2019-01-04"))), + createModule("ietf-yang-library", "urn:ietf:params:xml:ns:yang:ietf-yang-library", "2019-01-04")); + modules.put(new ModuleKey(new YangIdentifier("ietf-inet-types"), + new Revision(new RevisionIdentifier("2013-07-15"))), + createModule("ietf-inet-types", "urn:ietf:params:xml:ns:yang:ietf-inet-types", "2013-07-15")); + modules.put(new ModuleKey(new YangIdentifier("ietf-datastores"), + new Revision(new RevisionIdentifier("2018-02-14"))), + createModule("ietf-datastores", "urn:ietf:params:xml:ns:yang:ietf-datastores", "2018-02-14")); + modules.put(new ModuleKey(new YangIdentifier("ietf-yang-types"), + new Revision(new RevisionIdentifier("2013-07-15"))), + createModule("ietf-yang-types", "urn:ietf:params:xml:ns:yang:ietf-yang-types", "2013-07-15")); + return modules; + } + + private static Module createModule(final String name, final String namespace, final String revision) { + return new ModuleBuilder() + .setName(new YangIdentifier(name)) + .setNamespace(new Uri(namespace)) + .setRevision(new Revision(new RevisionIdentifier(revision))) + .setConformanceType(ConformanceType.Implement) + .setFeature(Collections.emptyList()) + .build(); + } +} \ No newline at end of file diff --git a/yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportTest.java b/yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportTest.java new file mode 100644 index 0000000000..ab7bea56bf --- /dev/null +++ b/yanglib/mdsal-yanglib-rfc8525/src/test/java/org/opendaylight/mdsal/yanglib/rfc8525/YangLibrarySupportTest.java @@ -0,0 +1,93 @@ +/* + * 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.mdsal.yanglib.rfc8525; + +import static org.junit.Assert.assertEquals; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.binding.runtime.api.BindingRuntimeContext; +import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator; +import org.opendaylight.binding.runtime.spi.BindingRuntimeHelpers; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTree; +import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode; +import org.opendaylight.mdsal.binding.dom.codec.impl.DefaultBindingCodecTreeFactory; +import org.opendaylight.mdsal.binding.generator.impl.DefaultBindingRuntimeGenerator; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibrary; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.Module; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.ModuleBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.ModuleKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSetKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory; +import org.opendaylight.yangtools.yang.parser.impl.YangParserFactoryImpl; + +public class YangLibrarySupportTest { + + private static final BindingRuntimeGenerator BINDING_RUNTIME_GENERATOR = new DefaultBindingRuntimeGenerator(); + + private static final YangParserFactory YANG_PARSER_FACTORY = new YangParserFactoryImpl(); + + private YangLibrarySupport yangLib; + private BindingRuntimeContext runtimeContext; + private BindingCodecTree codecTree; + + @Before + public void setUp() throws Exception { + runtimeContext = BindingRuntimeHelpers.createRuntimeContext(); + final DefaultBindingCodecTreeFactory codecFactory = new DefaultBindingCodecTreeFactory(); + yangLib = new YangLibrarySupport(YANG_PARSER_FACTORY, BINDING_RUNTIME_GENERATOR, + codecFactory); + codecTree = codecFactory.create(runtimeContext); + } + + @Test + public void testFormatSchema() { + final BindingDataObjectCodecTreeNode codec = + codecTree.getSubtreeCodec(InstanceIdentifier.create(YangLibrary.class)); + + final ContainerNode nonLegacyContent = yangLib.newContentBuilder() + .defaultContext(runtimeContext.getEffectiveModelContext()).formatYangLibraryContent(); + final YangLibrary yangLibrary = codec.deserialize(nonLegacyContent); + + assertEquals(1, yangLibrary.nonnullModuleSet().size()); + final ModuleSet moduleSet = yangLibrary.nonnullModuleSet().get(new ModuleSetKey("ODL_modules")); + assertEquals(4, moduleSet.nonnullModule().size()); + assertEquals(moduleSet.getModule(), createControlModules()); + } + + private Map createControlModules() { + final Map modules = new HashMap<>(); + modules.put(new ModuleKey(new YangIdentifier("ietf-yang-library")), + createModule("ietf-yang-library", "urn:ietf:params:xml:ns:yang:ietf-yang-library", "2019-01-04")); + modules.put(new ModuleKey(new YangIdentifier("ietf-inet-types")), + createModule("ietf-inet-types", "urn:ietf:params:xml:ns:yang:ietf-inet-types", "2013-07-15")); + modules.put(new ModuleKey(new YangIdentifier("ietf-datastores")), + createModule("ietf-datastores", "urn:ietf:params:xml:ns:yang:ietf-datastores", "2018-02-14")); + modules.put(new ModuleKey(new YangIdentifier("ietf-yang-types")), + createModule("ietf-yang-types", "urn:ietf:params:xml:ns:yang:ietf-yang-types", "2013-07-15")); + return modules; + } + + private Module createModule(final String name, final String namespace, final String revision) { + return new ModuleBuilder().setName(new YangIdentifier(name)) + .setNamespace(new Uri(namespace)) + .setRevision(new RevisionIdentifier(revision)) + .setFeature(Collections.emptyList()) + .setSubmodule(Collections.emptyMap()) + .build(); + } +} \ No newline at end of file -- 2.36.6