SmackException.java

  1. /**
  2.  *
  3.  * Copyright 2014-2020 Florian Schmaus
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smack;

  18. import java.security.cert.CertificateException;
  19. import java.util.Collections;
  20. import java.util.List;

  21. import org.jivesoftware.smack.c2s.XmppClientToServerTransport.LookupConnectionEndpointsFailed;
  22. import org.jivesoftware.smack.filter.StanzaFilter;
  23. import org.jivesoftware.smack.util.StringUtils;
  24. import org.jivesoftware.smack.util.rce.RemoteConnectionEndpoint;
  25. import org.jivesoftware.smack.util.rce.RemoteConnectionEndpointLookupFailure;
  26. import org.jivesoftware.smack.util.rce.RemoteConnectionException;

  27. import org.jxmpp.jid.Jid;

  28. /**
  29.  * Smack uses SmackExceptions for errors that are not defined by any XMPP specification.
  30.  *
  31.  * @author Florian Schmaus
  32.  */
  33. public abstract class SmackException extends Exception {

  34.     /**
  35.      *
  36.      */
  37.     private static final long serialVersionUID = 1844674365368214458L;

  38.     /**
  39.      * Creates a new SmackException with the Throwable that was the root cause of the exception.
  40.      *
  41.      * @param wrappedThrowable the root cause of the exception.
  42.      */
  43.     protected SmackException(Throwable wrappedThrowable) {
  44.         super(wrappedThrowable);
  45.     }

  46.     protected SmackException(String message) {
  47.         super(message);
  48.     }

  49.     protected SmackException(String message, Throwable wrappedThrowable) {
  50.         super(message, wrappedThrowable);
  51.     }

  52.     protected SmackException() {
  53.     }

  54.     /**
  55.      * Exception thrown always when there was no response to an request within the stanza reply timeout of the used
  56.      * connection instance. You can modify (e.g. increase) the stanza reply timeout with
  57.      * {@link XMPPConnection#setReplyTimeout(long)}.
  58.      */
  59.     public static final class NoResponseException extends SmackException {
  60.         /**
  61.          *
  62.          */
  63.         private static final long serialVersionUID = -6523363748984543636L;

  64.         private final StanzaFilter filter;

  65.         private NoResponseException(String message) {
  66.             this(message, null);
  67.         }

  68.         private NoResponseException(String message, StanzaFilter filter) {
  69.             super(message);
  70.             this.filter = filter;
  71.         }

  72.         /**
  73.          * Get the filter that was used to collect the response.
  74.          *
  75.          * @return the used filter or <code>null</code>.
  76.          */
  77.         public StanzaFilter getFilter() {
  78.             return filter;
  79.         }

  80.         public static NoResponseException newWith(XMPPConnection connection, String waitingFor) {
  81.             final StringBuilder sb = getWaitingFor(connection);
  82.             sb.append(" While waiting for ").append(waitingFor);
  83.             sb.append(" [").append(connection).append(']');
  84.             return new NoResponseException(sb.toString());
  85.         }

  86.         public static NoResponseException newWith(long timeout,
  87.                         StanzaCollector collector, boolean stanzaCollectorCancelled) {
  88.             return newWith(timeout, collector.getStanzaFilter(), stanzaCollectorCancelled);
  89.         }

  90.         public static NoResponseException newWith(XMPPConnection connection, StanzaFilter filter) {
  91.             return newWith(connection.getReplyTimeout(), filter, false);
  92.         }

  93.         public static NoResponseException newWith(long timeout, StanzaFilter filter, boolean stanzaCollectorCancelled) {
  94.             final StringBuilder sb = getWaitingFor(timeout);
  95.             if (stanzaCollectorCancelled) {
  96.                 sb.append(" StanzaCollector has been cancelled.");
  97.             }
  98.             sb.append(" Waited for response using: ");
  99.             if (filter != null) {
  100.                 sb.append(filter.toString());
  101.             }
  102.             else {
  103.                 sb.append("No filter used or filter was 'null'");
  104.             }
  105.             sb.append('.');
  106.             return new NoResponseException(sb.toString(), filter);
  107.         }

  108.         private static StringBuilder getWaitingFor(XMPPConnection connection) {
  109.             return getWaitingFor(connection.getReplyTimeout());
  110.         }

  111.         private static StringBuilder getWaitingFor(final long replyTimeout) {
  112.             final StringBuilder sb = new StringBuilder(256);
  113.             sb.append("No response received within reply timeout. Timeout was "
  114.                             + replyTimeout + "ms (~"
  115.                             + replyTimeout / 1000 + "s).");
  116.             return sb;
  117.         }
  118.     }

  119.     public static class NotLoggedInException extends SmackException {

  120.         /**
  121.          *
  122.          */
  123.         private static final long serialVersionUID = 3216216839100019278L;

  124.         public NotLoggedInException() {
  125.             super("Client is not logged in");
  126.         }
  127.     }

  128.     public static class AlreadyLoggedInException extends SmackException {

  129.         /**
  130.          *
  131.          */
  132.         private static final long serialVersionUID = 5011416918049935231L;

  133.         public AlreadyLoggedInException() {
  134.             super("Client is already logged in");
  135.         }
  136.     }

  137.     public static class AlreadyConnectedException extends SmackException {

  138.         /**
  139.          *
  140.          */
  141.         private static final long serialVersionUID = 5011416918049135231L;

  142.         public AlreadyConnectedException() {
  143.             super("Client is already connected");
  144.         }
  145.     }

  146.     public static class NotConnectedException extends SmackException {

  147.         /**
  148.          *
  149.          */
  150.         private static final long serialVersionUID = 9197980400776001173L;

  151.         public NotConnectedException() {
  152.             this(null);
  153.         }

  154.         public NotConnectedException(String optionalHint) {
  155.             super("Client is not, or no longer, connected."
  156.                             + (optionalHint != null ? ' ' + optionalHint : ""));
  157.         }

  158.         public NotConnectedException(XMPPConnection connection, String details) {
  159.             super("The connection " + connection.toString() + " is no longer connected. "
  160.                             + details);
  161.         }

  162.         public NotConnectedException(XMPPConnection connection, StanzaFilter stanzaFilter) {
  163.             super("The connection " + connection
  164.                             + " is no longer connected while waiting for response with " + stanzaFilter);
  165.         }

  166.         public NotConnectedException(XMPPConnection connection, StanzaFilter stanzaFilter,
  167.                         Exception connectionException) {
  168.             super("The connection " + connection + " is no longer connected while waiting for response with "
  169.                             + stanzaFilter + " because of " + connectionException, connectionException);
  170.         }
  171.     }

  172.     public static class OutgoingQueueFullException extends SmackException {

  173.         private static final long serialVersionUID = 1L;

  174.     }

  175.     public static class IllegalStateChangeException extends SmackException {

  176.         /**
  177.          *
  178.          */
  179.         private static final long serialVersionUID = -1766023961577168927L;

  180.         public IllegalStateChangeException() {
  181.         }
  182.     }

  183.     public abstract static class SecurityRequiredException extends SmackException {

  184.         /**
  185.          *
  186.          */
  187.         private static final long serialVersionUID = 384291845029773545L;

  188.         public SecurityRequiredException(String message) {
  189.             super(message);
  190.         }
  191.     }

  192.     public static class SecurityRequiredByClientException extends SecurityRequiredException {
  193.         /**
  194.          *
  195.          */
  196.         private static final long serialVersionUID = 2395325821201543159L;

  197.         public SecurityRequiredByClientException() {
  198.             super("SSL/TLS required by client but not supported by server");
  199.         }
  200.     }

  201.     public static class SecurityRequiredByServerException extends SecurityRequiredException {
  202.         /**
  203.          *
  204.          */
  205.         private static final long serialVersionUID = 8268148813117631819L;

  206.         public SecurityRequiredByServerException() {
  207.             super("SSL/TLS required by server but disabled in client");
  208.         }
  209.     }

  210.     public static class SecurityNotPossibleException extends SmackException {

  211.         /**
  212.          *
  213.          */
  214.         private static final long serialVersionUID = -6836090872690331336L;

  215.         public SecurityNotPossibleException(String message) {
  216.             super(message);
  217.         }
  218.     }

  219.     public abstract static class ConnectionException extends SmackException {

  220.         private static final long serialVersionUID = 1L;

  221.         protected ConnectionException(Throwable wrappedThrowable) {
  222.             super(wrappedThrowable);
  223.         }

  224.         protected ConnectionException(String message) {
  225.             super(message);
  226.         }

  227.     }

  228.     public static final class GenericConnectionException extends ConnectionException {

  229.         private static final long serialVersionUID = 1L;

  230.         /**
  231.          * Deprecated, do not use.
  232.          *
  233.          * @param wrappedThrowable the wrapped throwable.
  234.          */
  235.         @Deprecated
  236.         public GenericConnectionException(Throwable wrappedThrowable) {
  237.             super(wrappedThrowable);
  238.         }
  239.     }

  240.     /**
  241.      * This exception is thrown if Smack is unable to connect to all hosts of a given XMPP
  242.      * service. The connection exceptions can be retrieved with
  243.      * {@link EndpointConnectionException#getConnectionExceptions()}, which will have the exception causing the
  244.      * connection failure set and retrievable with {@link RemoteConnectionException#getException()}.
  245.      */
  246.     public static final class EndpointConnectionException extends ConnectionException {

  247.         /**
  248.          *
  249.          */
  250.         private static final long serialVersionUID = 1;

  251.         private final List<RemoteConnectionEndpointLookupFailure> lookupFailures;
  252.         private final List<? extends RemoteConnectionException<?>> connectionExceptions;

  253.         private EndpointConnectionException(String message, List<RemoteConnectionEndpointLookupFailure> lookupFailures,
  254.                         List<? extends RemoteConnectionException<?>> connectionExceptions) {
  255.             super(message);
  256.             // At least one list must contain an entry.
  257.             assert !lookupFailures.isEmpty() || !connectionExceptions.isEmpty();
  258.             this.lookupFailures = lookupFailures;
  259.             this.connectionExceptions = connectionExceptions;
  260.         }

  261.         public static EndpointConnectionException from(List<RemoteConnectionEndpointLookupFailure> lookupFailures,
  262.                         List<? extends RemoteConnectionException<?>> connectionExceptions) {
  263.             StringBuilder sb = new StringBuilder(256);

  264.             if (!lookupFailures.isEmpty()) {
  265.                 sb.append("Could not lookup the following endpoints: ");
  266.                 StringUtils.appendTo(lookupFailures, sb);
  267.             }

  268.             if (!connectionExceptions.isEmpty()) {
  269.                 sb.append("The following addresses failed: ");
  270.                 StringUtils.appendTo(connectionExceptions, sb, rce -> sb.append(rce.getErrorMessage()));
  271.             }

  272.             return new EndpointConnectionException(sb.toString(), lookupFailures, connectionExceptions);
  273.         }

  274.         public List<RemoteConnectionEndpointLookupFailure> getLookupFailures() {
  275.             return lookupFailures;
  276.         }

  277.         public List<? extends RemoteConnectionException<? extends RemoteConnectionEndpoint>> getConnectionExceptions() {
  278.             return connectionExceptions;
  279.         }
  280.     }

  281.     public static final class NoEndpointsDiscoveredException extends ConnectionException {

  282.         private static final long serialVersionUID = 1L;

  283.         private final List<LookupConnectionEndpointsFailed> lookupFailures;

  284.         private NoEndpointsDiscoveredException(String message, List<LookupConnectionEndpointsFailed> lookupFailures) {
  285.             super(message);
  286.             this.lookupFailures = Collections.unmodifiableList(lookupFailures);
  287.         }

  288.         public List<LookupConnectionEndpointsFailed> getLookupFailures() {
  289.             return lookupFailures;
  290.         }

  291.         public static NoEndpointsDiscoveredException from(List<LookupConnectionEndpointsFailed> lookupFailures) {
  292.             StringBuilder sb = new StringBuilder();

  293.             if (lookupFailures.isEmpty()) {
  294.                 sb.append("No endpoint lookup finished within the timeout");
  295.             } else {
  296.                 sb.append("No endpoints could be discovered due the following lookup failures: ");
  297.                 StringUtils.appendTo(lookupFailures, sb);
  298.             }

  299.             return new NoEndpointsDiscoveredException(sb.toString(), lookupFailures);
  300.         }
  301.     }

  302.     public static class FeatureNotSupportedException extends SmackException {

  303.         /**
  304.          *
  305.          */
  306.         private static final long serialVersionUID = 4713404802621452016L;

  307.         private final String feature;
  308.         private final Jid jid;

  309.         public FeatureNotSupportedException(String feature) {
  310.             this(feature, null);
  311.         }

  312.         public FeatureNotSupportedException(String feature, Jid jid) {
  313.             super(feature + " not supported" + (jid == null ? "" : " by '" + jid + "'"));
  314.             this.jid = jid;
  315.             this.feature = feature;
  316.         }

  317.         /**
  318.          * Get the feature which is not supported.
  319.          *
  320.          * @return the feature which is not supported
  321.          */
  322.         public String getFeature() {
  323.             return feature;
  324.         }

  325.         /**
  326.          * Get JID which does not support the feature. The JID can be null in cases when there are
  327.          * multiple JIDs queried for this feature.
  328.          *
  329.          * @return the JID which does not support the feature, or null
  330.          */
  331.         public Jid getJid() {
  332.             return jid;
  333.         }
  334.     }

  335.     public static class ResourceBindingNotOfferedException extends SmackException {

  336.         /**
  337.          *
  338.          */
  339.         private static final long serialVersionUID = 2346934138253437571L;

  340.         public ResourceBindingNotOfferedException() {
  341.             super("Resource binding was not offered by server");
  342.         }
  343.     }

  344.     /**
  345.      * A Smack exception wrapping another exception. Note that usage of this class is consider bad practice. This class
  346.      * will eventually be marked deprecated and removed.
  347.      */
  348.     public static class SmackWrappedException extends SmackException {

  349.         /**
  350.          *
  351.          */
  352.         private static final long serialVersionUID = 1L;

  353.         public SmackWrappedException(Exception exception) {
  354.             super(exception);
  355.         }

  356.         public SmackWrappedException(String message, Exception exception) {
  357.             super(message, exception);
  358.         }
  359.     }

  360.     /**
  361.      * A Smack exception wrapping a text message. Note that usage of this class is consider bad practice. This class
  362.      * will eventually be marked deprecated and removed.
  363.      */
  364.     public static class SmackMessageException extends SmackException {

  365.         /**
  366.          *
  367.          */
  368.         private static final long serialVersionUID = 1L;

  369.         public SmackMessageException(String message) {
  370.             super(message);
  371.         }
  372.     }

  373.     public static class SmackSaslException extends SmackException {

  374.         /**
  375.          *
  376.          */
  377.         private static final long serialVersionUID = 1L;

  378.         public SmackSaslException(Exception exception) {
  379.             super(exception);
  380.         }

  381.         public SmackSaslException(String message) {
  382.             super(message);
  383.         }

  384.         public SmackSaslException(String message, Exception exception) {
  385.             super(message, exception);
  386.         }
  387.     }

  388.     public static class SmackCertificateException extends SmackException {

  389.         private static final long serialVersionUID = 1L;

  390.         private final CertificateException certificateException;

  391.         public SmackCertificateException(CertificateException certificateException) {
  392.             this.certificateException = certificateException;
  393.         }

  394.         public CertificateException getCertificateException() {
  395.             return certificateException;
  396.         }
  397.     }
  398. }