QNameModule/QName should implement Identifier
[yangtools.git] / yang / 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.Serializable;
16 import java.net.URI;
17 import java.net.URISyntaxException;
18 import java.util.Objects;
19 import java.util.Optional;
20 import javax.annotation.Nullable;
21 import org.eclipse.jdt.annotation.NonNull;
22 import org.opendaylight.yangtools.concepts.Identifier;
23 import org.opendaylight.yangtools.concepts.Immutable;
24
25 public final class QNameModule implements Comparable<QNameModule>, Immutable, Serializable, Identifier {
26     private static final Interner<QNameModule> INTERNER = Interners.newWeakInterner();
27     private static final long serialVersionUID = 3L;
28
29     private final @NonNull URI namespace;
30
31     //Nullable
32     private final Revision revision;
33
34     private transient int hash;
35
36     private QNameModule(final @NonNull URI namespace, final Revision revision) {
37         this.namespace = requireNonNull(namespace);
38         this.revision = revision;
39     }
40
41     /**
42      * Return an interned reference to a equivalent QNameModule.
43      *
44      * @return Interned reference, or this object if it was interned.
45      */
46     public QNameModule intern() {
47         return INTERNER.intern(this);
48     }
49
50     /**
51      * Create a new QName module instance with specified namespace/revision.
52      *
53      * @param namespace Module namespace
54      * @param revision Module revision
55      * @return A new, potentially shared, QNameModule instance
56      */
57     public static QNameModule create(final URI namespace, final Optional<Revision> revision) {
58         return new QNameModule(namespace, revision.orElse(null));
59     }
60
61     /**
62      * Create a new QName module instance with specified namespace and norevision.
63      *
64      * @param namespace Module namespace
65      * @return A new, potentially shared, QNameModule instance
66      */
67     public static QNameModule create(final URI namespace) {
68         return new QNameModule(namespace, null);
69     }
70
71     /**
72      * Create a new QName module instance with specified namespace/revision.
73      *
74      * @param namespace Module namespace
75      * @param revision Module revision
76      * @return A new, potentially shared, QNameModule instance
77      */
78     public static QNameModule create(final URI namespace, @Nullable final Revision revision) {
79         return new QNameModule(namespace, revision);
80     }
81
82     /**
83      * Returns the namespace of the module which is specified as argument of
84      * YANG Module <b><font color="#00FF00">namespace</font></b> keyword.
85      *
86      * @return URI format of the namespace of the module
87      */
88     public URI getNamespace() {
89         return namespace;
90     }
91
92     /**
93      * Returns the revision date for the module.
94      *
95      * @return date of the module revision which is specified as argument of
96      *         YANG Module <b><font color="#339900">revison</font></b> keyword
97      */
98     public Optional<Revision> getRevision() {
99         return Optional.ofNullable(revision);
100     }
101
102     @Override
103     @SuppressWarnings("checkstyle:parameterName")
104     public int compareTo(final QNameModule o) {
105         int cmp = namespace.compareTo(o.namespace);
106         if (cmp != 0) {
107             return cmp;
108         }
109         return Revision.compare(revision, o.revision);
110     }
111
112     @Override
113     public int hashCode() {
114         if (hash == 0) {
115             hash = Objects.hash(namespace, revision);
116         }
117         return hash;
118     }
119
120     @Override
121     public boolean equals(final Object obj) {
122         if (this == obj) {
123             return true;
124         }
125         if (!(obj instanceof QNameModule)) {
126             return false;
127         }
128         final QNameModule other = (QNameModule) obj;
129         return Objects.equals(revision, other.revision) && namespace.equals(other.namespace);
130     }
131
132     /**
133      * Returns a namespace in form defined by section 5.6.4. of
134      * <a href=https://tools.ietf.org/html/rfc6020">RFC6020</a>, for example
135      * {@code http://example.acme.com/system?revision=2008-04-01}.
136      *
137      * @return Namespace in form defined by section 5.6.4. of RFC6020.
138      * @throws URISyntaxException on incorrect namespace definition
139      *
140      */
141     URI getRevisionNamespace() throws URISyntaxException {
142         final String query = revision == null ? "" : "revision=" + revision.toString();
143         return new URI(namespace.getScheme(), namespace.getUserInfo(), namespace.getHost(), namespace.getPort(),
144             namespace.getPath(), query, namespace.getFragment());
145     }
146
147     @Override
148     public String toString() {
149         return MoreObjects.toStringHelper(QNameModule.class).omitNullValues().add("ns", namespace)
150             .add("rev", revision).toString();
151     }
152 }