2 * Copyright (c) 2023 PANTHEON.tech s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.yanglib.writer;
10 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module.ConformanceType.Implement;
11 import static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.Module.ConformanceType.Import;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableSet;
15 import java.util.HashMap;
16 import java.util.HashSet;
18 import java.util.Optional;
20 import java.util.stream.Collectors;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.datastores.rev180214.Operational;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesState;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.ModulesStateBuilder;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.RevisionIdentifier;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibrary;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.YangLibraryBuilder;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.CommonLeafs;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.Deviation;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.DeviationBuilder;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.list.module.DeviationKey;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.module.set.parameters.module.SubmoduleBuilder;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.DatastoreBuilder;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.ModuleSetBuilder;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104.yang.library.parameters.SchemaBuilder;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier;
39 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
40 import org.opendaylight.yangtools.yang.common.QNameModule;
41 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
42 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
43 import org.opendaylight.yangtools.yang.model.api.Module;
44 import org.opendaylight.yangtools.yang.model.api.ModuleLike;
47 * Utility class responsible for building ietf-yang-library content.
49 // TODO: current artifact is part of integration with YangLibrarySupport from MDSAL project,
50 // it expected to be removed as extra once YangLibrarySupport is fully supporting required functionality.
51 // https://jira.opendaylight.org/browse/MDSAL-833
52 // https://jira.opendaylight.org/browse/MDSAL-835
53 final class YangLibraryContentBuilderUtil {
54 private static final CommonLeafs.Revision EMPTY_REVISION = new CommonLeafs.Revision("");
56 static final String DEFAULT_MODULE_SET_NAME = "ODL_modules";
57 static final String DEFAULT_SCHEMA_NAME = "ODL_schema";
59 private YangLibraryContentBuilderUtil() {
64 * Builds ietf-yang-library content based on model context.
66 * @param context effective model context
67 * @param urlProvider optional schema source URL provider
68 * @return content as YangLibrary object
70 static YangLibrary buildYangLibrary(final @NonNull EffectiveModelContext context,
71 final @NonNull String contentId, final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
72 final var deviationsMap = getDeviationsMap(context);
73 return new YangLibraryBuilder()
74 .setModuleSet(BindingMap.of(new ModuleSetBuilder()
75 .setName(DEFAULT_MODULE_SET_NAME)
76 .setModule(context.getModules().stream()
77 .map(module -> buildModule(module, deviationsMap, urlProvider))
78 .collect(BindingMap.toMap())
81 .setSchema(BindingMap.of(new SchemaBuilder()
82 .setName(DEFAULT_SCHEMA_NAME)
83 .setModuleSet(Set.of(DEFAULT_MODULE_SET_NAME))
85 .setDatastore(BindingMap.of(new DatastoreBuilder()
86 .setName(Operational.VALUE)
87 .setSchema(DEFAULT_SCHEMA_NAME)
89 .setContentId(contentId)
93 private static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
94 .module.set.parameters.@NonNull Module buildModule(final @NonNull Module module,
95 final @NonNull Map<QNameModule, Set<Module>> deviationsMap,
96 final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
97 return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
98 .rev190104.module.set.parameters.ModuleBuilder()
99 .setName(buildModuleKeyName(module))
100 .setRevision(buildRevision(module))
101 .setNamespace(new Uri(module.getNamespace().toString()))
102 .setFeature(buildFeatures(module).orElse(null))
103 .setDeviation(buildDeviations(module, deviationsMap).orElse(null))
104 .setLocation(buildSchemaSourceUrl(module, urlProvider).map(Set::of).orElse(null))
105 .setSubmodule(module.getSubmodules().stream()
106 .map(subModule -> new SubmoduleBuilder()
107 .setName(buildModuleKeyName(subModule))
108 .setRevision(buildRevision(subModule))
109 .setLocation(buildSchemaSourceUrl(subModule, urlProvider).map(Set::of).orElse(null))
111 .collect(BindingMap.toMap()))
116 * Builds ietf-yang-library legacy content based on model context.
118 * @param context effective model context
119 * @param urlProvider optional schema source URL provider
120 * @return content as ModulesState object
121 * @deprecated due to model update via RFC 8525, the functionality serves backward compatibility.
124 static ModulesState buildModuleState(final @NonNull EffectiveModelContext context,
125 final @NonNull String moduleSetId, final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
126 final var deviationsMap = getDeviationsMap(context);
127 return new ModulesStateBuilder()
128 .setModule(context.getModules().stream()
129 .map(module -> buildLegacyModule(module, deviationsMap, urlProvider))
130 .collect(BindingMap.toMap()))
131 .setModuleSetId(moduleSetId)
135 private static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
136 .rev190104.module.list.@NonNull Module buildLegacyModule(final @NonNull Module module,
137 final @NonNull Map<QNameModule, Set<Module>> deviationsMap,
138 final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
140 return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
141 .rev190104.module.list.ModuleBuilder()
142 .setName(buildModuleKeyName(module))
143 .setRevision(buildLegacyRevision(module))
144 .setNamespace(new Uri(module.getNamespace().toString()))
145 .setFeature(buildFeatures(module).orElse(null))
146 .setSchema(buildSchemaSourceUrl(module, urlProvider).orElse(null))
147 .setConformanceType(hasDeviations(module) ? Implement : Import)
148 .setDeviation(buildLegacyDeviations(module, deviationsMap).orElse(null))
149 .setSubmodule(module.getSubmodules().stream()
150 .map(subModule -> new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
151 .rev190104.module.list.module.SubmoduleBuilder()
152 .setName(buildModuleKeyName(subModule))
153 .setRevision(buildLegacyRevision(subModule))
154 .setSchema(buildSchemaSourceUrl(subModule, urlProvider).orElse(null))
156 .collect(BindingMap.toMap()))
160 private static RevisionIdentifier buildRevision(final ModuleLike module) {
161 final var revision = module.getQNameModule().revision();
162 return revision != null ? new RevisionIdentifier(revision.toString()) : null;
165 private static CommonLeafs.Revision buildLegacyRevision(final ModuleLike module) {
166 final var revision = module.getQNameModule().revision();
167 return revision != null ? new CommonLeafs.Revision(new RevisionIdentifier(revision.toString()))
171 private static YangIdentifier buildModuleKeyName(final ModuleLike module) {
172 final var revision = module.getQNameModule().revision();
173 return revision == null ? new YangIdentifier(module.getName()) :
174 new YangIdentifier(module.getName() + "_" + revision);
177 private static @NonNull Optional<Uri> buildSchemaSourceUrl(final @NonNull ModuleLike module,
178 final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
179 return urlProvider == null ? Optional.empty() :
180 urlProvider.getSchemaSourceUrl(DEFAULT_MODULE_SET_NAME, module.getName(),
181 module.getRevision().orElse(null));
184 private static Optional<Set<YangIdentifier>> buildFeatures(final ModuleLike module) {
185 if (module.getFeatures() == null || module.getFeatures().isEmpty()) {
186 return Optional.empty();
188 final var namespace = module.getQNameModule();
189 final var features = module.getFeatures().stream()
190 .map(FeatureDefinition::getQName)
191 // ensure the features belong to same module
192 .filter(featureName -> namespace.equals(featureName.getModule()))
193 .map(featureName -> new YangIdentifier(featureName.getLocalName()))
194 .collect(Collectors.toUnmodifiableSet());
195 return features.isEmpty() ? Optional.empty() : Optional.of(features);
198 private static boolean hasDeviations(final Module module) {
199 return module.getDeviations() != null && !module.getDeviations().isEmpty();
202 private static Optional<Set<YangIdentifier>> buildDeviations(final Module module,
203 final Map<QNameModule, Set<Module>> deviationsMap) {
204 final var deviationModules = deviationsMap.get(module.getQNameModule());
205 if (deviationModules == null) {
206 return Optional.empty();
208 return Optional.of(deviationModules.stream()
209 .map(devModule -> new YangIdentifier(buildModuleKeyName(devModule)))
210 .collect(ImmutableSet.toImmutableSet()));
213 private static Optional<Map<DeviationKey, Deviation>> buildLegacyDeviations(final Module module,
214 final Map<QNameModule, Set<Module>> deviationsMap) {
215 final var deviationModules = deviationsMap.get(module.getQNameModule());
216 if (deviationModules == null) {
217 return Optional.empty();
219 return Optional.of(deviationModules.stream()
220 .map(devModule -> new DeviationBuilder()
221 .setName(buildModuleKeyName(devModule))
222 .setRevision(buildLegacyRevision(devModule))
224 .collect(BindingMap.toMap()));
227 private static @NonNull Map<QNameModule, Set<Module>> getDeviationsMap(final EffectiveModelContext context) {
228 final var result = new HashMap<QNameModule, Set<Module>>();
229 for (final var module : context.getModules()) {
230 if (module.getDeviations() == null || module.getDeviations().isEmpty()) {
233 for (final var deviation : module.getDeviations()) {
234 final var targetQname = deviation.getTargetPath().lastNodeIdentifier().getModule();
235 result.computeIfAbsent(targetQname, key -> new HashSet<>()).add(module);
238 return ImmutableMap.copyOf(result);