Use pattern matching on instanceof in yang-common
[yangtools.git] / common / yang-common / src / main / java / org / opendaylight / yangtools / yang / common / QNameModule.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. 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.yangtools.yang.common;
9
10 import static java.util.Objects.requireNonNull;
11
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;
19 import java.util.Objects;
20 import java.util.Optional;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.opendaylight.yangtools.concepts.Identifier;
24 import org.opendaylight.yangtools.concepts.Immutable;
25 import org.opendaylight.yangtools.concepts.WritableObject;
26
27 /**
28  * A {@link XMLNamespace} bound to a particular model {@link Revision}. This is the primary way of identifying a YANG
29  * module namespace within an effective model world. The reason for this is that we support coexistence of multiple
30  * module revisions and hence cannot use plain module name or namespace to address them.
31  */
32 public final class QNameModule implements Comparable<QNameModule>, Immutable, Serializable, Identifier, WritableObject {
33     private static final Interner<QNameModule> INTERNER = Interners.newWeakInterner();
34     private static final long serialVersionUID = 3L;
35
36     private final @NonNull XMLNamespace namespace;
37     private final @Nullable Revision revision;
38
39     private transient int hash = 0;
40
41     private QNameModule(final XMLNamespace namespace, final @Nullable Revision revision) {
42         this.namespace = requireNonNull(namespace);
43         this.revision = revision;
44     }
45
46     /**
47      * Return an interned reference to a equivalent QNameModule.
48      *
49      * @return Interned reference, or this object if it was interned.
50      */
51     public @NonNull QNameModule intern() {
52         return INTERNER.intern(this);
53     }
54
55     /**
56      * Create a new QName module instance with specified namespace/revision.
57      *
58      * @param namespace Module namespace
59      * @param revision Module revision
60      * @return A new, potentially shared, QNameModule instance
61      * @throws NullPointerException if any argument is null
62      */
63     public static @NonNull QNameModule create(final XMLNamespace namespace, final Optional<Revision> revision) {
64         return new QNameModule(namespace, revision.orElse(null));
65     }
66
67     /**
68      * Create a new QName module instance with specified namespace and no revision.
69      *
70      * @param namespace Module namespace
71      * @return A new, potentially shared, QNameModule instance
72      * @throws NullPointerException if {@code namespace} is null
73      */
74     public static @NonNull QNameModule create(final XMLNamespace namespace) {
75         return new QNameModule(namespace, null);
76     }
77
78     /**
79      * Create a new QName module instance with specified namespace/revision.
80      *
81      * @param namespace Module namespace
82      * @param revision Module revision
83      * @return A new, potentially shared, QNameModule instance
84      * @throws NullPointerException if any argument is null
85      */
86     public static @NonNull QNameModule create(final XMLNamespace namespace, final @Nullable Revision revision) {
87         return new QNameModule(namespace, revision);
88     }
89
90     /**
91      * Read a QNameModule from a DataInput. The format is expected to match the output format
92      * of {@link #writeTo(DataOutput)}.
93      *
94      * @param in DataInput to read
95      * @return A QNameModule instance
96      * @throws IOException if I/O error occurs
97      */
98     public static @NonNull QNameModule readFrom(final DataInput in) throws IOException {
99         final String namespace = in.readUTF();
100         final String revision = in.readUTF();
101         return new QNameModule(XMLNamespace.of(namespace), revision.isEmpty() ? null : Revision.of(revision));
102     }
103
104     /**
105      * Returns the namespace of the module which is specified as argument of YANG Module {@code namespace} keyword.
106      *
107      * @return XMLNamespace of the namespace of the module
108      */
109     public @NonNull XMLNamespace getNamespace() {
110         return namespace;
111     }
112
113     /**
114      * Returns the revision date for the module.
115      *
116      * @return date of the module revision which is specified as argument of YANG Module {@code revision} keyword
117      */
118     public @NonNull Optional<Revision> getRevision() {
119         return Optional.ofNullable(revision);
120     }
121
122     @Override
123     @SuppressWarnings("checkstyle:parameterName")
124     public int compareTo(final QNameModule o) {
125         int cmp = namespace.compareTo(o.namespace);
126         if (cmp != 0) {
127             return cmp;
128         }
129         return Revision.compare(revision, o.revision);
130     }
131
132     /**
133      * Returns a QNameModule with the same namespace, but with no revision. If this QNameModule does not have
134      * a revision, this object is returned.
135      *
136      * @return a QNameModule with the same namespace, but with no revision.
137      */
138     public @NonNull QNameModule withoutRevision() {
139         return revision == null ? this : new QNameModule(namespace, null);
140     }
141
142     @Override
143     public void writeTo(final DataOutput out) throws IOException {
144         out.writeUTF(namespace.toString());
145         out.writeUTF(revision == null ? "" : revision.toString());
146     }
147
148     @Override
149     public int hashCode() {
150         if (hash == 0) {
151             hash = Objects.hash(namespace, revision);
152         }
153         return hash;
154     }
155
156     @Override
157     public boolean equals(final Object obj) {
158         return this == obj || obj instanceof QNameModule other
159             && Objects.equals(revision, other.revision) && namespace.equals(other.namespace);
160     }
161
162     @Override
163     public @NonNull String toString() {
164         return MoreObjects.toStringHelper(QNameModule.class).omitNullValues()
165             .add("ns", namespace)
166             .add("rev", revision)
167             .toString();
168     }
169
170     Object writeReplace() {
171         return new NSv1(this);
172     }
173 }