001/** 002 * 003 * Copyright © 2014-2024 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 boolean isStrictParentOf(Jid jid) { 185 EntityFullJid fullJid = jid.asEntityFullJidIfPossible(); 186 if (fullJid != null) { 187 return isStrictParentOf(fullJid); 188 } 189 EntityBareJid bareJid = jid.asEntityBareJidIfPossible(); 190 if (bareJid != null) { 191 return isStrictParentOf(bareJid); 192 } 193 DomainFullJid domainFullJid = jid.asDomainFullJidIfPossible(); 194 if (domainFullJid != null) { 195 return isStrictParentOf(domainFullJid); 196 } 197 198 return isStrictParentOf(jid.asDomainBareJid()); 199 } 200 201 @Override 202 public final int hashCode() { 203 return toString().hashCode(); 204 } 205 206 @Override 207 public final boolean equals(Object other) { 208 if (other == null) { 209 return false; 210 } 211 if (this == other) { 212 return true; 213 } 214 if (other instanceof CharSequence) { 215 return equals((CharSequence) other); 216 } 217 return false; 218 } 219 220 @SuppressWarnings("NonOverridingEquals") 221 @Override 222 public final boolean equals(CharSequence charSequence) { 223 if (charSequence == null) { 224 return false; 225 } 226 return equals(charSequence.toString()); 227 } 228 229 @SuppressWarnings("NonOverridingEquals") 230 @Override 231 public final boolean equals(String string) { 232 return toString().equals(string); 233 } 234 235 @Override 236 public final int compareTo(Jid other) { 237 String otherString = other.toString(); 238 String myString = toString(); 239 return myString.compareTo(otherString); 240 } 241 242 /** 243 * The cache holding the internalized value of this part. This needs to be transient so that the 244 * cache is recreated once the data was de-serialized. 245 */ 246 private transient String internalizedCache; 247 248 @Override 249 public final String intern() { 250 if (internalizedCache == null) { 251 cache = internalizedCache = toString().intern(); 252 } 253 return internalizedCache; 254 } 255 256 private transient String urlEncodedCache; 257 258 @Override 259 public final String asUrlEncodedString() { 260 if (urlEncodedCache == null) { 261 String string = toString(); 262 try { 263 urlEncodedCache = URLEncoder.encode(string, "UTF-8"); 264 } catch (UnsupportedEncodingException e) { 265 throw new AssertionError(e); 266 } 267 } 268 return urlEncodedCache; 269 } 270 271 private void throwIse(String message) { 272 String exceptionMessage = "The JID '" + this + "' " + message; 273 throw new IllegalStateException(exceptionMessage); 274 } 275 276 static <O> O requireNonNull(O object, String message) { 277 if (object != null) { 278 return object; 279 } 280 throw new IllegalArgumentException(message); 281 } 282}