2 * Copyright (c) 2013 Cisco Systems, Inc. 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.common;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.MoreObjects;
13 import com.google.common.collect.Interner;
14 import com.google.common.collect.Interners;
15 import java.io.DataInput;
16 import java.io.DataOutput;
17 import java.io.IOException;
18 import java.io.ObjectInputStream;
19 import java.io.ObjectOutputStream;
20 import java.io.ObjectStreamException;
21 import java.io.Serializable;
22 import java.util.Objects;
23 import java.util.Optional;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.opendaylight.yangtools.concepts.Identifier;
27 import org.opendaylight.yangtools.concepts.Immutable;
28 import org.opendaylight.yangtools.concepts.WritableObject;
31 * A {@link XMLNamespace} bound to a particular model {@link Revision}. This is the primary way of identifying a YANG
32 * module namespace within an effective model world. The reason for this is that we support coexistence of multiple
33 * module revisions and hence cannot use plain module name or namespace to address them.
35 public final class QNameModule implements Comparable<QNameModule>, Immutable, Serializable, Identifier, WritableObject {
36 private static final Interner<QNameModule> INTERNER = Interners.newWeakInterner();
38 private static final long serialVersionUID = 3L;
40 private final @NonNull XMLNamespace namespace;
41 private final @NonNull RevisionUnion revUnion;
43 private transient int hash = 0;
45 private QNameModule(final XMLNamespace namespace, final RevisionUnion revUnion) {
46 this.namespace = requireNonNull(namespace);
47 this.revUnion = requireNonNull(revUnion);
51 * Create a new QName module instance with specified {@link XMLNamespace} and no revision.
53 * @param namespace Module namespace
54 * @return A new, potentially shared, QNameModule instance
55 * @throws NullPointerException if any argument is {@code null}
57 public static @NonNull QNameModule of(final XMLNamespace namespace) {
58 return of(namespace, RevisionUnion.none());
62 * Create a new QName module instance with specified {@link XMLNamespace} and {@link RevisionUnion}.
64 * @param namespace Module namespace
65 * @param revUnion Module revision union
66 * @return A new, potentially shared, QNameModule instance
67 * @throws NullPointerException if any argument is {@code null}
69 public static @NonNull QNameModule of(final XMLNamespace namespace, final RevisionUnion revUnion) {
70 return new QNameModule(namespace, revUnion);
74 * Create a new QName module instance with specified {@link XMLNamespace} and {@link Revision}.
76 * @param namespace Module namespace
77 * @param revision Module revision
78 * @return A new, potentially shared, QNameModule instance
79 * @throws NullPointerException if any argument is {@code null}
81 public static @NonNull QNameModule of(final XMLNamespace namespace, final Revision revision) {
82 return new QNameModule(namespace, revision);
86 * Create a new QName module instance with specified namespace string and no revision.
88 * @param namespace Module namespace
89 * @return A new, potentially shared, QNameModule instance
90 * @throws NullPointerException if any argument is {@code null}
92 public static @NonNull QNameModule of(final String namespace) {
93 return of(XMLNamespace.of(namespace));
97 * Create a new QName module instance with specified namespace string and {@link RevisionUnion} string.
99 * @param namespace Module namespace
100 * @param unionString Module revision string or an empty string
101 * @return A new, potentially shared, QNameModule instance
102 * @throws NullPointerException if any argument is {@code null}
104 public static @NonNull QNameModule of(final String namespace, final String unionString) {
105 return of(XMLNamespace.of(namespace), RevisionUnion.of(unionString));
109 * Create a new QName module instance with specified {@link XMLNamespace} and an optional {@link Revision}.
111 * @param namespace Module namespace
112 * @param revision Module revision
113 * @return A new, potentially shared, QNameModule instance
114 * @throws NullPointerException if any argument is {@code null}
116 public static @NonNull QNameModule ofRevision(final XMLNamespace namespace, final @Nullable Revision revision) {
117 return of(namespace, revision != null ? revision : RevisionUnion.none());
121 * Create a new QName module instance with specified {@link XMLNamespace} and an optional {@link Revision}.
123 * @param namespace Module namespace
124 * @param revision Module revision string
125 * @return A new, potentially shared, QNameModule instance
126 * @throws NullPointerException if {@code namespace} is {@code null}
128 public static @NonNull QNameModule ofRevision(final String namespace, final @Nullable String revision) {
129 return of(XMLNamespace.of(namespace), revision != null ? Revision.of(revision) : RevisionUnion.none());
133 * Create a new QName module instance with specified namespace/revision.
135 * @param namespace Module namespace
136 * @param revision Module revision
137 * @return A new, potentially shared, QNameModule instance
138 * @throws NullPointerException if any argument is {@code null}
139 * @deprecated Use {@link #ofRevision(XMLNamespace, Revision)} instead
141 @Deprecated(since = "13.0.1", forRemoval = true)
142 public static @NonNull QNameModule create(final XMLNamespace namespace, final Optional<Revision> revision) {
143 return ofRevision(namespace, revision.orElse(null));
147 * Create a new QName module instance with specified namespace and no revision.
149 * @param namespace Module namespace
150 * @return A new, potentially shared, QNameModule instance
151 * @throws NullPointerException if {@code namespace} is null
152 * @deprecated Use {@link #of(XMLNamespace)} instead
154 @Deprecated(since = "13.0.1", forRemoval = true)
155 public static @NonNull QNameModule create(final XMLNamespace namespace) {
156 return of(namespace);
160 * Create a new QName module instance with specified namespace/revision.
162 * @param namespace Module namespace
163 * @param revision Module revision
164 * @return A new, potentially shared, QNameModule instance
165 * @throws NullPointerException if any argument is {@code null}
166 * @deprecated Use {@link #ofRevision(XMLNamespace, Revision)} instead
168 @Deprecated(since = "13.0.1", forRemoval = true)
169 public static @NonNull QNameModule create(final XMLNamespace namespace, final @Nullable Revision revision) {
170 return ofRevision(namespace, revision);
174 * Read a QNameModule from a DataInput. The format is expected to match the output format of
175 * {@link #writeTo(DataOutput)}.
177 * @param in DataInput to read
178 * @return A QNameModule instance
179 * @throws IOException if I/O error occurs
181 public static @NonNull QNameModule readFrom(final DataInput in) throws IOException {
182 return new QNameModule(XMLNamespace.readFrom(in), RevisionUnion.readFrom(in));
186 * Returns the namespace of the module which is specified as argument of YANG Module {@code namespace} keyword.
188 * @return XMLNamespace of the namespace of the module
190 public @NonNull XMLNamespace namespace() {
195 * Returns the namespace of the module which is specified as argument of YANG Module {@code namespace} keyword.
197 * @return XMLNamespace of the namespace of the module
198 * @deprecated Use {@link #namespace()} instead.
200 @Deprecated(since = "13.0.1", forRemoval = true)
201 public @NonNull XMLNamespace getNamespace() {
206 * Returns the revision date for the module.
208 * @return date of the module revision which is specified as argument of YANG Module {@code revision} keyword
210 public @NonNull RevisionUnion revisionUnion() {
215 * Returns the revision date for the module.
217 * @return date of the module revision which is specified as argument of YANG Module {@code revision} keyword
219 public @Nullable Revision revision() {
220 return revUnion.revision();
224 * Returns the revision date for the module.
226 * @return date of the module revision which is specified as argument of YANG Module {@code revision} keyword
228 public @NonNull Optional<Revision> findRevision() {
229 return revUnion.findRevision();
233 * Returns the revision date for the module.
235 * @return date of the module revision which is specified as argument of YANG Module {@code revision} keyword
236 * @deprecated Use {@link #findRevision()} or {@link #revision()} instead.
238 @Deprecated(since = "13.0.1", forRemoval = true)
239 public @NonNull Optional<Revision> getRevision() {
240 return findRevision();
244 * Return an interned reference to a equivalent QNameModule.
246 * @return Interned reference, or this object if it was interned.
248 public @NonNull QNameModule intern() {
249 return INTERNER.intern(this);
253 @SuppressWarnings("checkstyle:parameterName")
254 public int compareTo(final QNameModule o) {
256 return (cmp = namespace.compareTo(o.namespace)) != 0 ? cmp : revUnion.compareTo(o.revUnion);
260 * Returns a QNameModule with the same namespace, but with no revision. If this QNameModule does not have a
261 * revision, this object is returned.
263 * @return a QNameModule with the same namespace, but with no revision.
265 public @NonNull QNameModule withoutRevision() {
266 return revUnion instanceof NotRevision ? this : of(namespace);
270 public void writeTo(final DataOutput out) throws IOException {
271 out.writeUTF(namespace.toString());
272 out.writeUTF(revUnion.unionString());
276 public int hashCode() {
278 hash = Objects.hash(namespace, revUnion);
284 public boolean equals(final Object obj) {
285 return this == obj || obj instanceof QNameModule other && revUnion.equals(other.revUnion)
286 && namespace.equals(other.namespace);
290 public @NonNull String toString() {
291 return MoreObjects.toStringHelper(QNameModule.class).omitNullValues()
292 .add("ns", namespace)
293 .add("rev", revUnion.revision())
298 Object writeReplace() {
299 return new NSv1(this);
303 private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
308 private void readObjectNoData() throws ObjectStreamException {
313 private void writeObject(final ObjectOutputStream stream) throws IOException {