Fixup YangLibraryContentBuilderUtil javadoc
[netconf.git] / apps / yanglib-mdsal-writer / src / main / java / org / opendaylight / netconf / yanglib / writer / YangLibraryContentBuilderUtil.java
1 /*
2  * Copyright (c) 2023 PANTHEON.tech s.r.o. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netconf.yanglib.writer;
9
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;
12
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableSet;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Map;
18 import java.util.Set;
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;
45
46 /**
47  * Utility class responsible for building ietf-yang-library content.
48  */
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     @Deprecated
55     private static final CommonLeafs.Revision EMPTY_REVISION = new CommonLeafs.Revision("");
56
57     static final String DEFAULT_MODULE_SET_NAME = "ODL_modules";
58     static final String DEFAULT_SCHEMA_NAME = "ODL_schema";
59
60     private YangLibraryContentBuilderUtil() {
61         // utility class
62     }
63
64     /**
65      * Builds ietf-yang-library content based on model context.
66      *
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}
71      */
72     @NonNullByDefault
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())
82                 )
83                 .build()))
84             .setSchema(BindingMap.of(new SchemaBuilder()
85                 .setName(DEFAULT_SCHEMA_NAME)
86                 .setModuleSet(Set.of(DEFAULT_MODULE_SET_NAME))
87                 .build()))
88             .setDatastore(BindingMap.of(new DatastoreBuilder()
89                 .setName(Operational.VALUE)
90                 .setSchema(DEFAULT_SCHEMA_NAME)
91                 .build()))
92             .setContentId(contentId)
93             .build();
94     }
95
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))
113                     .build())
114                 .collect(BindingMap.toMap()))
115             .build();
116     }
117
118     /**
119      * Builds ietf-yang-library legacy content based on model context.
120      *
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.
126      */
127     @Deprecated
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)
136             .build();
137     }
138
139     @Deprecated
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) {
144
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))
160                     .build())
161                 .collect(BindingMap.toMap()))
162             .build();
163     }
164
165     private static RevisionIdentifier buildRevision(final ModuleLike module) {
166         final var revision = module.getQNameModule().revision();
167         return revision != null ? new RevisionIdentifier(revision.toString()) : null;
168     }
169
170     @Deprecated
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()))
174             : EMPTY_REVISION;
175     }
176
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);
181     }
182
183     @Deprecated
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();
188     }
189
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;
195     }
196
197     private static @Nullable Set<YangIdentifier> buildFeatures(final ModuleLike module) {
198         final var moduleFeatures = module.getFeatures();
199         if (moduleFeatures == null || moduleFeatures.isEmpty()) {
200             return null;
201         }
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;
210     }
211
212     private static boolean hasDeviations(final Module module) {
213         return module.getDeviations() != null && !module.getDeviations().isEmpty();
214     }
215
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());
222     }
223
224     @Deprecated
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))
232                 .build())
233             .collect(BindingMap.toMap());
234     }
235
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()) {
240                 continue;
241             }
242             for (final var deviation : module.getDeviations()) {
243                 final var targetQname = deviation.getTargetPath().lastNodeIdentifier().getModule();
244                 result.computeIfAbsent(targetQname, key -> new HashSet<>()).add(module);
245             }
246         }
247         return ImmutableMap.copyOf(result);
248     }
249 }