001/**
002 *
003 * Copyright © 2014-2017 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jxmpp.jid.impl;
018
019import org.jxmpp.jid.EntityBareJid;
020
021import java.io.UnsupportedEncodingException;
022import java.net.URLEncoder;
023
024import org.jxmpp.jid.DomainBareJid;
025import org.jxmpp.jid.DomainFullJid;
026import org.jxmpp.jid.EntityFullJid;
027import org.jxmpp.jid.Jid;
028import org.jxmpp.jid.EntityJid;
029import org.jxmpp.jid.FullJid;
030import org.jxmpp.jid.parts.Localpart;
031import org.jxmpp.jid.parts.Resourcepart;
032
033public abstract class AbstractJid implements Jid {
034
035        /**
036         *
037         */
038        private static final long serialVersionUID = 1L;
039
040        /**
041         * Cache for the String representation of this JID.
042         */
043        protected String cache;
044
045        @Override
046        public final boolean isEntityJid() {
047                return isEntityBareJid() || isEntityFullJid();
048        }
049
050        @Override
051        public final boolean isEntityBareJid() {
052                return this instanceof EntityBareJid;
053        }
054
055        @Override
056        public final boolean isEntityFullJid() {
057                return this instanceof EntityFullJid;
058        }
059
060        @Override
061        public final boolean isDomainBareJid() {
062                return this instanceof DomainBareJid;
063        }
064
065        @Override
066        public final boolean isDomainFullJid() {
067                return this instanceof DomainFullJid;
068        }
069
070        @Override
071        public abstract boolean hasNoResource();
072
073        @Override
074        public final boolean hasResource() {
075                return this instanceof FullJid;
076        }
077
078        @Override
079        public final boolean hasLocalpart() {
080                return this instanceof EntityJid;
081        }
082
083        @Override
084        public final <T extends Jid> T downcast(Class<T> jidClass) {
085                return jidClass.cast(this);
086        }
087
088        @Override
089        public int length() {
090                return toString().length();
091        }
092
093        @Override
094        public char charAt(int index) {
095                return toString().charAt(index);
096        }
097
098        @Override
099        public CharSequence subSequence(int start, int end) {
100                return toString().subSequence(start, end);
101        }
102
103        @Override
104        public final EntityBareJid asEntityBareJidOrThrow() {
105                EntityBareJid entityBareJid = asEntityBareJidIfPossible();
106                if (entityBareJid == null) throwIse("can not be converted to EntityBareJid");
107                return entityBareJid;
108        }
109
110        @Override
111        public EntityFullJid asEntityFullJidOrThrow() {
112                EntityFullJid entityFullJid = asEntityFullJidIfPossible();
113                if (entityFullJid == null) throwIse("can not be converted to EntityFullJid");
114                return entityFullJid;
115        }
116
117        @Override
118        public EntityJid asEntityJidOrThrow() {
119                EntityJid entityJid = asEntityJidIfPossible();
120                if (entityJid == null) throwIse("can not be converted to EntityJid");
121                return entityJid;
122        }
123
124        @Override
125        public EntityFullJid asFullJidOrThrow() {
126                EntityFullJid entityFullJid = asEntityFullJidIfPossible();
127                if (entityFullJid == null) throwIse("can not be converted to EntityBareJid");
128                return entityFullJid;
129        }
130
131        @Override
132        public DomainFullJid asDomainFullJidOrThrow() {
133                DomainFullJid domainFullJid = asDomainFullJidIfPossible();
134                if (domainFullJid == null) throwIse("can not be converted to DomainFullJid");
135                return domainFullJid;
136        }
137
138        @Override
139        public abstract Resourcepart getResourceOrNull();
140
141        @Override
142        public final Resourcepart getResourceOrEmpty() {
143                Resourcepart resourcepart = getResourceOrNull();
144                if (resourcepart == null) return Resourcepart.EMPTY;
145                return resourcepart;
146        }
147
148        @Override
149        public final Resourcepart getResourceOrThrow() {
150                Resourcepart resourcepart = getResourceOrNull();
151                if (resourcepart == null) throwIse("has no resourcepart");
152                return resourcepart;
153        }
154
155        @Override
156        public abstract Localpart getLocalpartOrNull();
157
158        @Override
159        public final Localpart getLocalpartOrThrow() {
160                Localpart localpart = getLocalpartOrNull();
161                if (localpart == null) throwIse("has no localpart");
162                return localpart;
163        }
164
165        @Override
166        public final boolean isParentOf(Jid jid) {
167                EntityFullJid fullJid = jid.asEntityFullJidIfPossible();
168                if (fullJid != null) {
169                        return isParentOf(fullJid);
170                }
171                EntityBareJid bareJid = jid.asEntityBareJidIfPossible();
172                if (bareJid != null) {
173                        return isParentOf(bareJid);
174                }
175                DomainFullJid domainFullJid = jid.asDomainFullJidIfPossible();
176                if (domainFullJid != null) {
177                        return isParentOf(domainFullJid);
178                }
179
180                return isParentOf(jid.asDomainBareJid());
181        }
182
183        @Override
184        public final int hashCode() {
185                return toString().hashCode();
186        }
187
188        @Override
189        public final boolean equals(Object other) {
190                if (other == null) {
191                        return false;
192                }
193                if (this == other) {
194                        return true;
195                }
196                if (other instanceof CharSequence) {
197                        return equals((CharSequence) other);
198                }
199                return false;
200        }
201
202        @SuppressWarnings("NonOverridingEquals")
203        @Override
204        public final boolean equals(CharSequence charSequence) {
205                if (charSequence == null) {
206                        return false;
207                }
208                return equals(charSequence.toString());
209        }
210
211        @SuppressWarnings("NonOverridingEquals")
212        @Override
213        public final boolean equals(String string) {
214                return toString().equals(string);
215        }
216
217        @Override
218        public final int compareTo(Jid  other) {
219                String otherString = other.toString();
220                String myString = toString();
221                return myString.compareTo(otherString);
222        }
223
224        /**
225         * The cache holding the internalized value of this part. This needs to be transient so that the
226         * cache is recreated once the data was de-serialized.
227         */
228        private transient String internalizedCache;
229
230        @Override
231        public final String intern() {
232                if (internalizedCache == null) {
233                        cache = internalizedCache = toString().intern();
234                }
235                return internalizedCache;
236        }
237
238        private transient String urlEncodedCache;
239
240        @Override
241        public final String asUrlEncodedString() {
242                if (urlEncodedCache == null) {
243                        String string = toString();
244                        try {
245                                urlEncodedCache = URLEncoder.encode(string, "UTF-8");
246                        } catch (UnsupportedEncodingException e) {
247                                throw new AssertionError(e);
248                        }
249                }
250                return urlEncodedCache;
251        }
252
253        private void throwIse(String message) {
254                String exceptionMessage = "The JID '" + this + "' " + message;
255                throw new IllegalStateException(exceptionMessage);
256        }
257
258        static <O extends Object> O requireNonNull(O object, String message) {
259                if (object != null) {
260                        return object;
261                }
262                throw new IllegalArgumentException(message);
263        }
264}