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.Serializable;
20 import java.net.URISyntaxException;
21 import java.util.Objects;
22 import java.util.Optional;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.yangtools.concepts.Identifier;
26 import org.opendaylight.yangtools.concepts.Immutable;
27 import org.opendaylight.yangtools.concepts.WritableObject;
29 public final class QNameModule implements Comparable<QNameModule>, Immutable, Serializable, Identifier, WritableObject {
30 private static final Interner<QNameModule> INTERNER = Interners.newWeakInterner();
31 private static final long serialVersionUID = 3L;
33 private final @NonNull URI namespace;
34 private final @Nullable Revision revision;
36 private transient int hash = 0;
38 private QNameModule(final URI namespace, final @Nullable Revision revision) {
39 this.namespace = requireNonNull(namespace);
40 this.revision = revision;
44 * Return an interned reference to a equivalent QNameModule.
46 * @return Interned reference, or this object if it was interned.
48 public @NonNull QNameModule intern() {
49 return INTERNER.intern(this);
53 * Create a new QName module instance with specified namespace/revision.
55 * @param namespace Module namespace
56 * @param revision Module revision
57 * @return A new, potentially shared, QNameModule instance
58 * @throws NullPointerException if any argument is null
60 public static @NonNull QNameModule create(final URI namespace, final Optional<Revision> revision) {
61 return new QNameModule(namespace, revision.orElse(null));
65 * Create a new QName module instance with specified namespace and no revision.
67 * @param namespace Module namespace
68 * @return A new, potentially shared, QNameModule instance
69 * @throws NullPointerException if {@code namespace} is null
71 public static @NonNull QNameModule create(final URI namespace) {
72 return new QNameModule(namespace, null);
76 * Create a new QName module instance with specified namespace/revision.
78 * @param namespace Module namespace
79 * @param revision Module revision
80 * @return A new, potentially shared, QNameModule instance
81 * @throws NullPointerException if any argument is null
83 public static @NonNull QNameModule create(final URI namespace, final @Nullable Revision revision) {
84 return new QNameModule(namespace, revision);
88 * Read a QNameModule from a DataInput. The format is expected to match the output format
89 * of {@link #writeTo(DataOutput)}.
91 * @param in DataInput to read
92 * @return A QNameModule instance
93 * @throws IOException if I/O error occurs
95 public static @NonNull QNameModule readFrom(final DataInput in) throws IOException {
96 final String namespace = in.readUTF();
97 final String revision = in.readUTF();
98 return new QNameModule(URI.create(namespace), revision.isEmpty() ? null : Revision.of(revision));
102 * Returns the namespace of the module which is specified as argument of YANG Module {@code namespace} keyword.
104 * @return URI format of the namespace of the module
106 public @NonNull URI getNamespace() {
111 * Returns the revision date for the module.
113 * @return date of the module revision which is specified as argument of
114 * YANG Module <b><font color="#339900">revison</font></b> keyword
116 public @NonNull Optional<Revision> getRevision() {
117 return Optional.ofNullable(revision);
121 @SuppressWarnings("checkstyle:parameterName")
122 public int compareTo(final QNameModule o) {
123 int cmp = namespace.compareTo(o.namespace);
127 return Revision.compare(revision, o.revision);
131 * Returns a QNameModule with the same namespace, but with no revision. If this QNameModule does not have
132 * a revision, this object is returned.
134 * @return a QNameModule with the same namespace, but with no revision.
136 public @NonNull QNameModule withoutRevision() {
137 return revision == null ? this : new QNameModule(namespace, null);
141 public void writeTo(final DataOutput out) throws IOException {
142 out.writeUTF(namespace.toString());
143 out.writeUTF(revision == null ? "" : revision.toString());
147 public int hashCode() {
149 hash = Objects.hash(namespace, revision);
155 public boolean equals(final Object obj) {
159 if (!(obj instanceof QNameModule)) {
162 final QNameModule other = (QNameModule) obj;
163 return Objects.equals(revision, other.revision) && namespace.equals(other.namespace);
167 * Returns a namespace in form defined by section 5.6.4. of
168 * <a href=https://tools.ietf.org/html/rfc6020">RFC6020</a>, for example
169 * {@code http://example.acme.com/system?revision=2008-04-01}.
171 * @return Namespace in form defined by section 5.6.4. of RFC6020.
172 * @throws URISyntaxException on incorrect namespace definition
175 @NonNull URI getRevisionNamespace() throws URISyntaxException {
176 final String query = revision == null ? "" : "revision=" + revision.toString();
177 return new URI(namespace.getScheme(), namespace.getUserInfo(), namespace.getHost(), namespace.getPort(),
178 namespace.getPath(), query, namespace.getFragment());
182 public @NonNull String toString() {
183 return MoreObjects.toStringHelper(QNameModule.class).omitNullValues().add("ns", namespace)
184 .add("rev", revision).toString();