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;
19 import java.util.stream.Collectors;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
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 {
55 private static final CommonLeafs.Revision EMPTY_REVISION = new CommonLeafs.Revision("");
57 static final String DEFAULT_MODULE_SET_NAME = "ODL_modules";
58 static final String DEFAULT_SCHEMA_NAME = "ODL_schema";
60 private YangLibraryContentBuilderUtil() {
65 * Builds ietf-yang-library content based on model context.
67 * @param context effective model context
68 * @param contentId YangLibrary content ID
69 * @param urlProvider schema source URL provider
70 * @return content as an {@link YangLibrary}
73 static YangLibrary buildYangLibrary(final EffectiveModelContext context, final String contentId,
74 final YangLibrarySchemaSourceUrlProvider urlProvider) {
75 final var deviationsMap = getDeviationsMap(context);
76 return new YangLibraryBuilder()
77 .setModuleSet(BindingMap.of(new ModuleSetBuilder()
78 .setName(DEFAULT_MODULE_SET_NAME)
79 .setModule(context.getModules().stream()
80 .map(module -> buildModule(module, deviationsMap, urlProvider))
81 .collect(BindingMap.toMap())
84 .setSchema(BindingMap.of(new SchemaBuilder()
85 .setName(DEFAULT_SCHEMA_NAME)
86 .setModuleSet(Set.of(DEFAULT_MODULE_SET_NAME))
88 .setDatastore(BindingMap.of(new DatastoreBuilder()
89 .setName(Operational.VALUE)
90 .setSchema(DEFAULT_SCHEMA_NAME)
92 .setContentId(contentId)
96 private static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library.rev190104
97 .module.set.parameters.@NonNull Module buildModule(final @NonNull Module module,
98 final @NonNull Map<QNameModule, Set<Module>> deviationsMap,
99 final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider) {
100 return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
101 .rev190104.module.set.parameters.ModuleBuilder()
102 .setName(buildModuleKeyName(module))
103 .setRevision(buildRevision(module))
104 .setNamespace(new Uri(module.getNamespace().toString()))
105 .setFeature(buildFeatures(module))
106 .setDeviation(buildDeviations(module, deviationsMap))
107 .setLocation(buildSchemaSourceUrls(module, urlProvider))
108 .setSubmodule(module.getSubmodules().stream()
109 .map(subModule -> new SubmoduleBuilder()
110 .setName(buildModuleKeyName(subModule))
111 .setRevision(buildRevision(subModule))
112 .setLocation(buildSchemaSourceUrls(subModule, urlProvider))
114 .collect(BindingMap.toMap()))
119 * Builds ietf-yang-library legacy content based on model context.
121 * @param context effective model context
122 * @param moduleSetId the ID of the constructed module set
123 * @param urlProvider schema source URL provider
124 * @return content as a {@link ModulesState}
125 * @deprecated due to model update via RFC 8525, the functionality serves backward compatibility.
128 static ModulesState buildModuleState(final @NonNull EffectiveModelContext context,
129 final @NonNull String moduleSetId, final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider) {
130 final var deviationsMap = getDeviationsMap(context);
131 return new ModulesStateBuilder()
132 .setModule(context.getModules().stream()
133 .map(module -> buildLegacyModule(module, deviationsMap, urlProvider))
134 .collect(BindingMap.toMap()))
135 .setModuleSetId(moduleSetId)
140 private static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
141 .rev190104.module.list.@NonNull Module buildLegacyModule(final @NonNull Module module,
142 final @NonNull Map<QNameModule, Set<Module>> deviationsMap,
143 final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider) {
145 return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
146 .rev190104.module.list.ModuleBuilder()
147 .setName(buildModuleKeyName(module))
148 .setRevision(buildLegacyRevision(module))
149 .setNamespace(new Uri(module.getNamespace().toString()))
150 .setFeature(buildFeatures(module))
151 .setSchema(buildSchemaSourceUrl(module, urlProvider))
152 .setConformanceType(hasDeviations(module) ? Implement : Import)
153 .setDeviation(buildLegacyDeviations(module, deviationsMap))
154 .setSubmodule(module.getSubmodules().stream()
155 .map(subModule -> new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.library
156 .rev190104.module.list.module.SubmoduleBuilder()
157 .setName(buildModuleKeyName(subModule))
158 .setRevision(buildLegacyRevision(subModule))
159 .setSchema(buildSchemaSourceUrl(subModule, urlProvider))
161 .collect(BindingMap.toMap()))
165 private static RevisionIdentifier buildRevision(final ModuleLike module) {
166 final var revision = module.getQNameModule().revision();
167 return revision != null ? new RevisionIdentifier(revision.toString()) : null;
171 private static CommonLeafs.Revision buildLegacyRevision(final ModuleLike module) {
172 final var revision = module.getQNameModule().revision();
173 return revision != null ? new CommonLeafs.Revision(new RevisionIdentifier(revision.toString()))
177 private static YangIdentifier buildModuleKeyName(final ModuleLike module) {
178 final var revision = module.getQNameModule().revision();
179 return revision == null ? new YangIdentifier(module.getName()) :
180 new YangIdentifier(module.getName() + "_" + revision);
184 private static @Nullable Uri buildSchemaSourceUrl(final @NonNull ModuleLike module,
185 final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider) {
186 final var uris = buildSchemaSourceUrls(module, urlProvider);
187 return uris == null ? null : uris.iterator().next();
190 private static @Nullable Set<Uri> buildSchemaSourceUrls(final @NonNull ModuleLike module,
191 final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider) {
192 final var uris = urlProvider.getSchemaSourceUrl(DEFAULT_MODULE_SET_NAME, module.getName(),
193 module.getRevision().orElse(null));
194 return uris.isEmpty() ? null : uris;
197 private static @Nullable Set<YangIdentifier> buildFeatures(final ModuleLike module) {
198 final var moduleFeatures = module.getFeatures();
199 if (moduleFeatures == null || moduleFeatures.isEmpty()) {
202 final var namespace = module.getQNameModule();
203 final var features = module.getFeatures().stream()
204 .map(FeatureDefinition::getQName)
205 // ensure the features belong to same module
206 .filter(featureName -> namespace.equals(featureName.getModule()))
207 .map(featureName -> new YangIdentifier(featureName.getLocalName()))
208 .collect(Collectors.toUnmodifiableSet());
209 return features.isEmpty() ? null : features;
212 private static boolean hasDeviations(final Module module) {
213 return module.getDeviations() != null && !module.getDeviations().isEmpty();
216 private static @Nullable Set<YangIdentifier> buildDeviations(final Module module,
217 final Map<QNameModule, Set<Module>> deviationsMap) {
218 final var deviationModules = deviationsMap.get(module.getQNameModule());
219 return deviationModules == null ? null : deviationModules.stream()
220 .map(devModule -> new YangIdentifier(buildModuleKeyName(devModule)))
221 .collect(ImmutableSet.toImmutableSet());
225 private static @Nullable Map<DeviationKey, Deviation> buildLegacyDeviations(final Module module,
226 final Map<QNameModule, Set<Module>> deviationsMap) {
227 final var deviationModules = deviationsMap.get(module.getQNameModule());
228 return deviationModules == null ? null : deviationModules.stream()
229 .map(devModule -> new DeviationBuilder()
230 .setName(buildModuleKeyName(devModule))
231 .setRevision(buildLegacyRevision(devModule))
233 .collect(BindingMap.toMap());
236 private static @NonNull Map<QNameModule, Set<Module>> getDeviationsMap(final EffectiveModelContext context) {
237 final var result = new HashMap<QNameModule, Set<Module>>();
238 for (final var module : context.getModules()) {
239 if (module.getDeviations() == null || module.getDeviations().isEmpty()) {
242 for (final var deviation : module.getDeviations()) {
243 final var targetQname = deviation.getTargetPath().lastNodeIdentifier().getModule();
244 result.computeIfAbsent(targetQname, key -> new HashSet<>()).add(module);
247 return ImmutableMap.copyOf(result);