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 return module.getQNameModule().getRevision().map(rev -> new RevisionIdentifier(rev.toString())).orElse(null);
164 private static CommonLeafs.Revision buildLegacyRevision(final ModuleLike module) {
165 return module.getQNameModule().getRevision()
166 .map(rev -> new CommonLeafs.Revision(new RevisionIdentifier(rev.toString()))).orElse(EMPTY_REVISION);
169 private static YangIdentifier buildModuleKeyName(final ModuleLike module) {
170 return new YangIdentifier(module.getName()
171 + module.getQNameModule().getRevision().map(revision -> "_" + revision).orElse(""));
174 private static @NonNull Optional<Uri> buildSchemaSourceUrl(final @NonNull ModuleLike module,
175 final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
176 return urlProvider == null ? Optional.empty() :
177 urlProvider.getSchemaSourceUrl(DEFAULT_MODULE_SET_NAME, module.getName(),
178 module.getRevision().orElse(null));
181 private static Optional<Set<YangIdentifier>> buildFeatures(final ModuleLike module) {
182 if (module.getFeatures() == null || module.getFeatures().isEmpty()) {
183 return Optional.empty();
185 final var namespace = module.getQNameModule();
186 final var features = module.getFeatures().stream()
187 .map(FeatureDefinition::getQName)
188 // ensure the features belong to same module
189 .filter(featureName -> namespace.equals(featureName.getModule()))
190 .map(featureName -> new YangIdentifier(featureName.getLocalName()))
191 .collect(Collectors.toUnmodifiableSet());
192 return features.isEmpty() ? Optional.empty() : Optional.of(features);
195 private static boolean hasDeviations(final Module module) {
196 return module.getDeviations() != null && !module.getDeviations().isEmpty();
199 private static Optional<Set<YangIdentifier>> buildDeviations(final Module module,
200 final Map<QNameModule, Set<Module>> deviationsMap) {
201 final var deviationModules = deviationsMap.get(module.getQNameModule());
202 if (deviationModules == null) {
203 return Optional.empty();
205 return Optional.of(deviationModules.stream()
206 .map(devModule -> new YangIdentifier(buildModuleKeyName(devModule)))
207 .collect(ImmutableSet.toImmutableSet()));
210 private static Optional<Map<DeviationKey, Deviation>> buildLegacyDeviations(final Module module,
211 final Map<QNameModule, Set<Module>> deviationsMap) {
212 final var deviationModules = deviationsMap.get(module.getQNameModule());
213 if (deviationModules == null) {
214 return Optional.empty();
216 return Optional.of(deviationModules.stream()
217 .map(devModule -> new DeviationBuilder()
218 .setName(buildModuleKeyName(devModule))
219 .setRevision(buildLegacyRevision(devModule))
221 .collect(BindingMap.toMap()));
224 private static @NonNull Map<QNameModule, Set<Module>> getDeviationsMap(final EffectiveModelContext context) {
225 final var result = new HashMap<QNameModule, Set<Module>>();
226 for (final var module : context.getModules()) {
227 if (module.getDeviations() == null || module.getDeviations().isEmpty()) {
230 for (final var deviation : module.getDeviations()) {
231 final var targetQname = deviation.getTargetPath().lastNodeIdentifier().getModule();
232 result.computeIfAbsent(targetQname, key -> new HashSet<>()).add(module);
235 return ImmutableMap.copyOf(result);