001/** 002 * 003 * Copyright 2014-2020 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.jivesoftware.smack; 018 019import java.security.cert.CertificateException; 020import java.util.Collections; 021import java.util.List; 022 023import org.jivesoftware.smack.c2s.XmppClientToServerTransport.LookupConnectionEndpointsFailed; 024import org.jivesoftware.smack.filter.StanzaFilter; 025import org.jivesoftware.smack.util.StringUtils; 026import org.jivesoftware.smack.util.rce.RemoteConnectionEndpoint; 027import org.jivesoftware.smack.util.rce.RemoteConnectionEndpointLookupFailure; 028import org.jivesoftware.smack.util.rce.RemoteConnectionException; 029 030import org.jxmpp.jid.Jid; 031 032/** 033 * Smack uses SmackExceptions for errors that are not defined by any XMPP specification. 034 * 035 * @author Florian Schmaus 036 */ 037public abstract class SmackException extends Exception { 038 039 /** 040 * 041 */ 042 private static final long serialVersionUID = 1844674365368214458L; 043 044 /** 045 * Creates a new SmackException with the Throwable that was the root cause of the exception. 046 * 047 * @param wrappedThrowable the root cause of the exception. 048 */ 049 protected SmackException(Throwable wrappedThrowable) { 050 super(wrappedThrowable); 051 } 052 053 protected SmackException(String message) { 054 super(message); 055 } 056 057 protected SmackException(String message, Throwable wrappedThrowable) { 058 super(message, wrappedThrowable); 059 } 060 061 protected SmackException() { 062 } 063 064 /** 065 * Exception thrown always when there was no response to an request within the stanza reply timeout of the used 066 * connection instance. You can modify (e.g. increase) the stanza reply timeout with 067 * {@link XMPPConnection#setReplyTimeout(long)}. 068 */ 069 public static final class NoResponseException extends SmackException { 070 /** 071 * 072 */ 073 private static final long serialVersionUID = -6523363748984543636L; 074 075 private final StanzaFilter filter; 076 077 private NoResponseException(String message) { 078 this(message, null); 079 } 080 081 private NoResponseException(String message, StanzaFilter filter) { 082 super(message); 083 this.filter = filter; 084 } 085 086 /** 087 * Get the filter that was used to collect the response. 088 * 089 * @return the used filter or <code>null</code>. 090 */ 091 public StanzaFilter getFilter() { 092 return filter; 093 } 094 095 public static NoResponseException newWith(XMPPConnection connection, String waitingFor) { 096 final StringBuilder sb = getWaitingFor(connection); 097 sb.append(" While waiting for ").append(waitingFor); 098 sb.append(" [").append(connection).append(']'); 099 return new NoResponseException(sb.toString()); 100 } 101 102 public static NoResponseException newWith(long timeout, 103 StanzaCollector collector, boolean stanzaCollectorCancelled) { 104 return newWith(timeout, collector.getStanzaFilter(), stanzaCollectorCancelled); 105 } 106 107 public static NoResponseException newWith(XMPPConnection connection, StanzaFilter filter) { 108 return newWith(connection.getReplyTimeout(), filter, false); 109 } 110 111 public static NoResponseException newWith(long timeout, StanzaFilter filter, boolean stanzaCollectorCancelled) { 112 final StringBuilder sb = getWaitingFor(timeout); 113 if (stanzaCollectorCancelled) { 114 sb.append(" StanzaCollector has been cancelled."); 115 } 116 sb.append(" Waited for response using: "); 117 if (filter != null) { 118 sb.append(filter.toString()); 119 } 120 else { 121 sb.append("No filter used or filter was 'null'"); 122 } 123 sb.append('.'); 124 return new NoResponseException(sb.toString(), filter); 125 } 126 127 private static StringBuilder getWaitingFor(XMPPConnection connection) { 128 return getWaitingFor(connection.getReplyTimeout()); 129 } 130 131 private static StringBuilder getWaitingFor(final long replyTimeout) { 132 final StringBuilder sb = new StringBuilder(256); 133 sb.append("No response received within reply timeout. Timeout was " 134 + replyTimeout + "ms (~" 135 + replyTimeout / 1000 + "s)."); 136 return sb; 137 } 138 } 139 140 public static class NotLoggedInException extends SmackException { 141 142 /** 143 * 144 */ 145 private static final long serialVersionUID = 3216216839100019278L; 146 147 public NotLoggedInException() { 148 super("Client is not logged in"); 149 } 150 } 151 152 public static class AlreadyLoggedInException extends SmackException { 153 154 /** 155 * 156 */ 157 private static final long serialVersionUID = 5011416918049935231L; 158 159 public AlreadyLoggedInException() { 160 super("Client is already logged in"); 161 } 162 } 163 164 public static class AlreadyConnectedException extends SmackException { 165 166 /** 167 * 168 */ 169 private static final long serialVersionUID = 5011416918049135231L; 170 171 public AlreadyConnectedException() { 172 super("Client is already connected"); 173 } 174 } 175 176 public static class NotConnectedException extends SmackException { 177 178 /** 179 * 180 */ 181 private static final long serialVersionUID = 9197980400776001173L; 182 183 public NotConnectedException() { 184 this(null); 185 } 186 187 public NotConnectedException(String optionalHint) { 188 super("Client is not, or no longer, connected." 189 + (optionalHint != null ? ' ' + optionalHint : "")); 190 } 191 192 public NotConnectedException(XMPPConnection connection, String details) { 193 super("The connection " + connection.toString() + " is no longer connected. " 194 + details); 195 } 196 197 public NotConnectedException(XMPPConnection connection, StanzaFilter stanzaFilter) { 198 super("The connection " + connection 199 + " is no longer connected while waiting for response with " + stanzaFilter); 200 } 201 202 public NotConnectedException(XMPPConnection connection, StanzaFilter stanzaFilter, 203 Exception connectionException) { 204 super("The connection " + connection + " is no longer connected while waiting for response with " 205 + stanzaFilter + " because of " + connectionException, connectionException); 206 } 207 } 208 209 public static class OutgoingQueueFullException extends SmackException { 210 211 private static final long serialVersionUID = 1L; 212 213 } 214 215 public static class IllegalStateChangeException extends SmackException { 216 217 /** 218 * 219 */ 220 private static final long serialVersionUID = -1766023961577168927L; 221 222 public IllegalStateChangeException() { 223 } 224 } 225 226 public abstract static class SecurityRequiredException extends SmackException { 227 228 /** 229 * 230 */ 231 private static final long serialVersionUID = 384291845029773545L; 232 233 public SecurityRequiredException(String message) { 234 super(message); 235 } 236 } 237 238 public static class SecurityRequiredByClientException extends SecurityRequiredException { 239 /** 240 * 241 */ 242 private static final long serialVersionUID = 2395325821201543159L; 243 244 public SecurityRequiredByClientException() { 245 super("SSL/TLS required by client but not supported by server"); 246 } 247 } 248 249 public static class SecurityRequiredByServerException extends SecurityRequiredException { 250 /** 251 * 252 */ 253 private static final long serialVersionUID = 8268148813117631819L; 254 255 public SecurityRequiredByServerException() { 256 super("SSL/TLS required by server but disabled in client"); 257 } 258 } 259 260 public static class SecurityNotPossibleException extends SmackException { 261 262 /** 263 * 264 */ 265 private static final long serialVersionUID = -6836090872690331336L; 266 267 public SecurityNotPossibleException(String message) { 268 super(message); 269 } 270 } 271 272 public abstract static class ConnectionException extends SmackException { 273 274 private static final long serialVersionUID = 1L; 275 276 protected ConnectionException(Throwable wrappedThrowable) { 277 super(wrappedThrowable); 278 } 279 280 protected ConnectionException(String message) { 281 super(message); 282 } 283 284 } 285 286 public static final class GenericConnectionException extends ConnectionException { 287 288 private static final long serialVersionUID = 1L; 289 290 /** 291 * Deprecated, do not use. 292 * 293 * @param wrappedThrowable the wrapped throwable. 294 */ 295 @Deprecated 296 public GenericConnectionException(Throwable wrappedThrowable) { 297 super(wrappedThrowable); 298 } 299 } 300 301 /** 302 * This exception is thrown if Smack is unable to connect to all hosts of a given XMPP 303 * service. The connection exceptions can be retrieved with 304 * {@link EndpointConnectionException#getConnectionExceptions()}, which will have the exception causing the 305 * connection failure set and retrievable with {@link RemoteConnectionException#getException()}. 306 */ 307 public static final class EndpointConnectionException extends ConnectionException { 308 309 /** 310 * 311 */ 312 private static final long serialVersionUID = 1; 313 314 private final List<RemoteConnectionEndpointLookupFailure> lookupFailures; 315 private final List<? extends RemoteConnectionException<?>> connectionExceptions; 316 317 private EndpointConnectionException(String message, List<RemoteConnectionEndpointLookupFailure> lookupFailures, 318 List<? extends RemoteConnectionException<?>> connectionExceptions) { 319 super(message); 320 // At least one list must contain an entry. 321 assert !lookupFailures.isEmpty() || !connectionExceptions.isEmpty(); 322 this.lookupFailures = lookupFailures; 323 this.connectionExceptions = connectionExceptions; 324 } 325 326 public static EndpointConnectionException from(List<RemoteConnectionEndpointLookupFailure> lookupFailures, 327 List<? extends RemoteConnectionException<?>> connectionExceptions) { 328 StringBuilder sb = new StringBuilder(256); 329 330 if (!lookupFailures.isEmpty()) { 331 sb.append("Could not lookup the following endpoints: "); 332 StringUtils.appendTo(lookupFailures, sb); 333 } 334 335 if (!connectionExceptions.isEmpty()) { 336 sb.append("The following addresses failed: "); 337 StringUtils.appendTo(connectionExceptions, sb, rce -> sb.append(rce.getErrorMessage())); 338 } 339 340 return new EndpointConnectionException(sb.toString(), lookupFailures, connectionExceptions); 341 } 342 343 public List<RemoteConnectionEndpointLookupFailure> getLookupFailures() { 344 return lookupFailures; 345 } 346 347 public List<? extends RemoteConnectionException<? extends RemoteConnectionEndpoint>> getConnectionExceptions() { 348 return connectionExceptions; 349 } 350 } 351 352 public static final class NoEndpointsDiscoveredException extends ConnectionException { 353 354 private static final long serialVersionUID = 1L; 355 356 private final List<LookupConnectionEndpointsFailed> lookupFailures; 357 358 private NoEndpointsDiscoveredException(String message, List<LookupConnectionEndpointsFailed> lookupFailures) { 359 super(message); 360 this.lookupFailures = Collections.unmodifiableList(lookupFailures); 361 } 362 363 public List<LookupConnectionEndpointsFailed> getLookupFailures() { 364 return lookupFailures; 365 } 366 367 public static NoEndpointsDiscoveredException from(List<LookupConnectionEndpointsFailed> lookupFailures) { 368 StringBuilder sb = new StringBuilder(); 369 370 if (lookupFailures.isEmpty()) { 371 sb.append("No endpoint lookup finished within the timeout"); 372 } else { 373 sb.append("No endpoints could be discovered due the following lookup failures: "); 374 StringUtils.appendTo(lookupFailures, sb); 375 } 376 377 return new NoEndpointsDiscoveredException(sb.toString(), lookupFailures); 378 } 379 } 380 381 public static class FeatureNotSupportedException extends SmackException { 382 383 /** 384 * 385 */ 386 private static final long serialVersionUID = 4713404802621452016L; 387 388 private final String feature; 389 private final Jid jid; 390 391 public FeatureNotSupportedException(String feature) { 392 this(feature, null); 393 } 394 395 public FeatureNotSupportedException(String feature, Jid jid) { 396 super(feature + " not supported" + (jid == null ? "" : " by '" + jid + "'")); 397 this.jid = jid; 398 this.feature = feature; 399 } 400 401 /** 402 * Get the feature which is not supported. 403 * 404 * @return the feature which is not supported 405 */ 406 public String getFeature() { 407 return feature; 408 } 409 410 /** 411 * Get JID which does not support the feature. The JID can be null in cases when there are 412 * multiple JIDs queried for this feature. 413 * 414 * @return the JID which does not support the feature, or null 415 */ 416 public Jid getJid() { 417 return jid; 418 } 419 } 420 421 public static class ResourceBindingNotOfferedException extends SmackException { 422 423 /** 424 * 425 */ 426 private static final long serialVersionUID = 2346934138253437571L; 427 428 public ResourceBindingNotOfferedException() { 429 super("Resource binding was not offered by server"); 430 } 431 } 432 433 /** 434 * A Smack exception wrapping another exception. Note that usage of this class is consider bad practice. This class 435 * will eventually be marked deprecated and removed. 436 */ 437 public static class SmackWrappedException extends SmackException { 438 439 /** 440 * 441 */ 442 private static final long serialVersionUID = 1L; 443 444 public SmackWrappedException(Exception exception) { 445 super(exception); 446 } 447 448 public SmackWrappedException(String message, Exception exception) { 449 super(message, exception); 450 } 451 } 452 453 /** 454 * A Smack exception wrapping a text message. Note that usage of this class is consider bad practice. This class 455 * will eventually be marked deprecated and removed. 456 */ 457 public static class SmackMessageException extends SmackException { 458 459 /** 460 * 461 */ 462 private static final long serialVersionUID = 1L; 463 464 public SmackMessageException(String message) { 465 super(message); 466 } 467 } 468 469 public static class SmackSaslException extends SmackException { 470 471 /** 472 * 473 */ 474 private static final long serialVersionUID = 1L; 475 476 public SmackSaslException(Exception exception) { 477 super(exception); 478 } 479 480 public SmackSaslException(String message) { 481 super(message); 482 } 483 484 public SmackSaslException(String message, Exception exception) { 485 super(message, exception); 486 } 487 } 488 489 public static class SmackCertificateException extends SmackException { 490 491 private static final long serialVersionUID = 1L; 492 493 private final CertificateException certificateException; 494 495 public SmackCertificateException(CertificateException certificateException) { 496 this.certificateException = certificateException; 497 } 498 499 public CertificateException getCertificateException() { 500 return certificateException; 501 } 502 } 503}