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}