2 * Copyright (c) 2024 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.yangtools.yang.model.spi.source;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.ImmutableSet;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.ArrayList;
15 import java.util.Comparator;
16 import org.eclipse.jdt.annotation.NonNullByDefault;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.yangtools.yang.common.Revision;
19 import org.opendaylight.yangtools.yang.common.UnresolvedQName.Unqualified;
20 import org.opendaylight.yangtools.yang.common.XMLNamespace;
21 import org.opendaylight.yangtools.yang.common.YangVersion;
22 import org.opendaylight.yangtools.yang.model.api.source.SourceDependency.BelongsTo;
23 import org.opendaylight.yangtools.yang.model.api.source.SourceDependency.Import;
24 import org.opendaylight.yangtools.yang.model.api.source.SourceDependency.Include;
25 import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
26 import org.opendaylight.yangtools.yang.model.api.source.SourceRepresentation;
27 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionStatement;
30 import org.opendaylight.yangtools.yang.model.api.stmt.RootDeclaredStatement;
31 import org.opendaylight.yangtools.yang.model.api.stmt.YangVersionStatement;
34 * Linkage information about a particular {@link SourceRepresentation}. It has two specializations
36 * <li>{@link SourceInfo.Module} pertaining to {@link SourceRepresentation} which have {@code module} as its root
38 * <li>{@link SourceInfo.Submodule} pertaining to {@link SourceRepresentation} which have {@code submodule} as its
43 * This interface captures the basic metadata needed for interpretation and linkage of the source, as represented by the
44 * following ABNF constructs placed at the start of a YANG file:
46 * <li>{@code module-header-stmts} or {@code submodule-header-stmts}</li>
47 * <li>{@code linkage-stmts}</li>
48 * <li>{@code revision-stmts}<li>
52 public sealed interface SourceInfo permits SourceInfo.Module, SourceInfo.Submodule {
54 * Return the {@link SourceIdentifier} of this source, as expressed by {@link RootDeclaredStatement#argument()}
55 * contract coupled with the first entry in {@link #revisions()}.
57 * @return name of this source.
59 SourceIdentifier sourceId();
62 * Return {@link YangVersion} of the source. If no {@link YangVersionStatement} is present, this method will return
63 * {@link YangVersion#VERSION_1}.
65 * @return {@link YangVersion} of the source
67 YangVersion yangVersion();
70 * The set of all {@link RevisionDateStatement} mentioned in {@link RevisionStatement}s. The returned set is ordered
71 * in reverse order, i.e. newest revision is encountered first.
73 * @return all revisions known by this source
75 ImmutableSet<Revision> revisions();
78 * Return all {@link Import} dependencies.
80 * @return all import dependencies
82 ImmutableSet<Import> imports();
85 * Return all {@link Include} dependencies.
87 * @return all include dependencies
89 ImmutableSet<Include> includes();
92 * A {@link SourceInfo} about a {@link ModuleStatement}-backed source.
95 SourceIdentifier sourceId,
96 YangVersion yangVersion,
97 XMLNamespace namespace,
99 ImmutableSet<Revision> revisions,
100 ImmutableSet<Import> imports,
101 ImmutableSet<Include> includes) implements SourceInfo {
103 requireNonNull(sourceId);
104 requireNonNull(yangVersion);
105 requireNonNull(namespace);
106 requireNonNull(prefix);
107 requireNonNull(revisions);
108 requireNonNull(imports);
109 requireNonNull(includes);
112 public static Builder builder() {
113 return new Builder();
116 public static final class Builder extends SourceInfo.Builder<Builder, Module> {
117 @SuppressFBWarnings(value = "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
118 justification = "https://github.com/spotbugs/spotbugs/issues/743")
119 private @Nullable XMLNamespace namespace;
120 @SuppressFBWarnings(value = "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
121 justification = "https://github.com/spotbugs/spotbugs/issues/743")
122 private @Nullable Unqualified prefix;
128 public Builder setNamespace(final XMLNamespace namespace) {
129 this.namespace = requireNonNull(namespace);
133 public Builder setPrefix(final Unqualified prefix) {
134 this.prefix = requireNonNull(prefix);
139 Module buildInstance(final SourceIdentifier sourceId, final YangVersion yangVersion,
140 final ImmutableSet<Revision> revisions, final ImmutableSet<Import> imports,
141 final ImmutableSet<Include> includes) {
142 return new Module(sourceId, yangVersion, requireNonNull(namespace), requireNonNull(prefix), revisions,
149 * A {@link SourceInfo} about a {@code submodule}.
152 SourceIdentifier sourceId,
153 YangVersion yangVersion,
155 ImmutableSet<Revision> revisions,
156 ImmutableSet<Import> imports,
157 ImmutableSet<Include> includes) implements SourceInfo {
159 requireNonNull(sourceId);
160 requireNonNull(yangVersion);
161 requireNonNull(belongsTo);
162 requireNonNull(revisions);
163 requireNonNull(imports);
164 requireNonNull(imports);
165 requireNonNull(includes);
168 public static Builder builder() {
169 return new Builder();
172 public static final class Builder extends SourceInfo.Builder<Builder, Submodule> {
173 @SuppressFBWarnings(value = "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
174 justification = "https://github.com/spotbugs/spotbugs/issues/743")
175 private @Nullable BelongsTo belongsTo;
181 public Builder setBelongsTo(final BelongsTo belongsTo) {
182 this.belongsTo = requireNonNull(belongsTo);
187 Submodule buildInstance(final SourceIdentifier sourceId, final YangVersion yangVersion,
188 final ImmutableSet<Revision> revisions, final ImmutableSet<Import> imports,
189 final ImmutableSet<Include> includes) {
190 return new Submodule(sourceId, yangVersion, requireNonNull(belongsTo), revisions, imports, includes);
195 abstract sealed class Builder<B extends Builder<B, I>, I extends SourceInfo> {
196 private final ImmutableSet.Builder<Import> imports = ImmutableSet.builder();
197 private final ImmutableSet.Builder<Include> includes = ImmutableSet.builder();
198 private final ArrayList<Revision> revisions = new ArrayList<>();
199 private YangVersion yangVersion = YangVersion.VERSION_1;
200 @SuppressFBWarnings(value = "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
201 justification = "https://github.com/spotbugs/spotbugs/issues/743")
202 private @Nullable Unqualified name;
204 public final B setName(final Unqualified newName) {
205 name = requireNonNull(newName);
206 return thisInstance();
209 public final B setYangVersion(final YangVersion newYangVersion) {
210 yangVersion = requireNonNull(newYangVersion);
211 return thisInstance();
214 public final B addImport(final Import importDep) {
215 imports.add(importDep);
216 return thisInstance();
219 public final B addInclude(final Include includeDep) {
220 includes.add(includeDep);
221 return thisInstance();
224 public final B addRevision(final Revision revision) {
225 revisions.add(revision);
226 return thisInstance();
229 public final I build() {
230 final var sorted = revisions.stream()
231 .sorted(Comparator.reverseOrder())
232 .collect(ImmutableSet.toImmutableSet());
234 return buildInstance(
235 new SourceIdentifier(requireNonNull(name), sorted.isEmpty() ? null : sorted.iterator().next()),
236 yangVersion, sorted, imports.build(), includes.build());
239 abstract I buildInstance(SourceIdentifier sourceId, YangVersion yangVersion, ImmutableSet<Revision> revisions,
240 ImmutableSet<Import> imports, ImmutableSet<Include> includes);
242 @SuppressWarnings("unchecked")
243 private B thisInstance() {