1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2014-2017 Christian Schudt
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25package rocks.xmpp.addr;
26
27import java.text.Collator;
28import java.util.Arrays;
29
30/**
31 * Abstract Jid implementation for both full and bare JIDs.
32 *
33 * @author Christian Schudt
34 */
35abstract class AbstractJid implements Jid {
36
37 /**
38 * Checks if the JID is a full JID.
39 * <blockquote>
40 * <p>The term "full JID" refers to an XMPP address of the form <localpart@domainpart/resourcepart> (for a particular authorized client or device associated with an account) or of the form <domainpart/resourcepart> (for a particular resource or script associated with a server).</p>
41 * </blockquote>
42 *
43 * @return True, if the JID is a full JID; otherwise false.
44 */
45 @Override
46 public final boolean isFullJid() {
47 return getResource() != null;
48 }
49
50 /**
51 * Checks if the JID is a bare JID.
52 * <blockquote>
53 * <p>The term "bare JID" refers to an XMPP address of the form <localpart@domainpart> (for an account at a server) or of the form <domainpart> (for a server).</p>
54 * </blockquote>
55 *
56 * @return True, if the JID is a bare JID; otherwise false.
57 */
58 @Override
59 public final boolean isBareJid() {
60 return getResource() == null;
61 }
62
63 @Override
64 public final boolean isDomainJid() {
65 return getLocal() == null;
66 }
67
68 @Override
69 public final boolean equals(Object o) {
70 if (o == this) {
71 return true;
72 }
73 if (!(o instanceof Jid)) {
74 return false;
75 }
76 Jid other = (Jid) o;
77
78 return (getLocal() == other.getLocal() || getLocal() != null && getLocal().equals(other.getLocal()))
79 && (getDomain() == other.getDomain() || getDomain() != null && getDomain().equals(other.getDomain()))
80 && (getResource() == other.getResource() || getResource() != null && getResource().equals(other.getResource()));
81 }
82
83 @Override
84 public final int hashCode() {
85 return Arrays.hashCode(new String[]{getLocal(), getDomain(), getResource()});
86 }
87
88 /**
89 * Compares this JID with another JID. First domain parts are compared. If these are equal, local parts are compared
90 * and if these are equal, too, resource parts are compared.
91 *
92 * @param o The other JID.
93 * @return The comparison result.
94 */
95 @Override
96 public final int compareTo(Jid o) {
97
98 if (this == o) {
99 return 0;
100 }
101
102 if (o != null) {
103 final Collator collator = Collator.getInstance();
104 int result;
105 // First compare domain parts.
106 if (getDomain() != null) {
107 result = o.getDomain() != null ? collator.compare(getDomain(), o.getDomain()) : -1;
108 } else {
109 result = o.getDomain() != null ? 1 : 0;
110 }
111 // If the domains are equal, compare local parts.
112 if (result == 0) {
113 if (getLocal() != null) {
114 // If this local part is not null, but the other is null, move this down (1).
115 result = o.getLocal() != null ? collator.compare(getLocal(), o.getLocal()) : 1;
116 } else {
117 // If this local part is null, but the other is not, move this up (-1).
118 result = o.getLocal() != null ? -1 : 0;
119 }
120 }
121 // If the local parts are equal, compare resource parts.
122 if (result == 0) {
123 if (getResource() != null) {
124 // If this resource part is not null, but the other is null, move this down (1).
125 return o.getResource() != null ? collator.compare(getResource(), o.getResource()) : 1;
126 } else {
127 // If this resource part is null, but the other is not, move this up (-1).
128 return o.getResource() != null ? -1 : 0;
129 }
130 }
131 return result;
132 } else {
133 return -1;
134 }
135 }
136
137 @Override
138 public final int length() {
139 return toString().length();
140 }
141
142 @Override
143 public final char charAt(int index) {
144 return toString().charAt(index);
145 }
146
147 @Override
148 public final CharSequence subSequence(int start, int end) {
149 return toString().subSequence(start, end);
150 }
151
152 /**
153 * Returns the JID in its string representation, i.e. [ localpart "@" ] domainpart [ "/" resourcepart ].
154 *
155 * @return The JID.
156 * @see #toEscapedString()
157 */
158 @Override
159 public final String toString() {
160 return toString(getLocal(), getDomain(), getResource());
161 }
162
163 @Override
164 public final String toEscapedString() {
165 return toString(getEscapedLocal(), getDomain(), getResource());
166 }
167
168 static String toString(String local, String domain, String resource) {
169 StringBuilder sb = new StringBuilder();
170 if (local != null) {
171 sb.append(local).append('@');
172 }
173 sb.append(domain);
174 if (resource != null) {
175 sb.append('/').append(resource);
176 }
177 return sb.toString();
178 }
179}