001/**
002 *
003 * Copyright 2003-2007 Jive Software.
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 */
017
018package org.jivesoftware.smack;
019
020import org.jivesoftware.smack.packet.Nonza;
021import org.jivesoftware.smack.packet.Stanza;
022import org.jivesoftware.smack.packet.StanzaError;
023import org.jivesoftware.smack.packet.StreamError;
024
025import org.jxmpp.jid.Jid;
026
027/**
028 * A generic exception that is thrown when an error occurs performing an
029 * XMPP operation. XMPP servers can respond to error conditions with an error code
030 * and textual description of the problem, which are encapsulated in the XMPPError
031 * class. When appropriate, an XMPPError instance is attached instances of this exception.<p>
032 *
033 * When a stream error occurred, the server will send a stream error to the client before
034 * closing the connection. Stream errors are unrecoverable errors. When a stream error
035 * is sent to the client an XMPPException will be thrown containing the StreamError sent
036 * by the server.
037 *
038 * @see StanzaError
039 * @author Matt Tucker
040 */
041public abstract class XMPPException extends Exception {
042    private static final long serialVersionUID = 6881651633890968625L;
043
044
045    /**
046     * Creates a new XMPPException.
047     */
048    protected XMPPException() {
049        super();
050    }
051
052    /**
053     * Creates a new XMPPException with a description of the exception.
054     *
055     * @param message description of the exception.
056     */
057    protected XMPPException(String message) {
058        super(message);
059    }
060
061    /**
062     * Creates a new XMPPException with a description of the exception and the
063     * Throwable that was the root cause of the exception.
064     *
065     * @param message a description of the exception.
066     * @param wrappedThrowable the root cause of the exception.
067     */
068    protected XMPPException(String message, Throwable wrappedThrowable) {
069        super(message, wrappedThrowable);
070    }
071
072    /**
073     * An exception caused by an XMPP error stanza response on the protocol level. You can examine the underlying
074     * {@link StanzaError} by calling {@link #getStanzaError()}.
075     */
076    public static class XMPPErrorException extends XMPPException {
077        /**
078         *
079         */
080        private static final long serialVersionUID = 212790389529249604L;
081        private final StanzaError error;
082        private final Stanza stanza;
083
084        /**
085         * The request which resulted in the XMPP protocol error response. May be {@code null}.
086         */
087        private final Stanza request;
088
089        /**
090         * Creates a new XMPPErrorException with the XMPPError that was the root case of the exception.
091         *
092         * @param stanza stanza that contained the exception.
093         * @param error the root cause of the exception.
094         */
095        public XMPPErrorException(Stanza stanza, StanzaError error) {
096            this(stanza, error, null);
097        }
098
099        /**
100         * Creates a new XMPPErrorException with the XMPPError that was the root case of the exception.
101         *
102         * @param request the request which triggered the error.
103         * @param stanza stanza that contained the exception.
104         * @param error the root cause of the exception.
105         * @since 4.3.0
106         */
107        public XMPPErrorException(Stanza stanza, StanzaError error, Stanza request) {
108            super();
109            this.error = error;
110            this.stanza = stanza;
111            this.request = request;
112        }
113
114        /**
115         * Returns the stanza error extension element associated with this exception.
116         *
117         * @return the stanza error extension element associated with this exception.
118         */
119        public StanzaError getStanzaError() {
120            return error;
121        }
122
123        /**
124         * Gets the stanza associated with this exception.
125         *
126         * @return the stanza from which this exception was created or {@code null} if the exception is not from a
127         * stanza.
128         */
129        public Stanza getStanza() {
130            return stanza;
131        }
132
133        /**
134         * Get the request which triggered the error response causing this exception.
135         *
136         * @return the request or {@code null}.
137         * @since 4.3.0
138         */
139        public Stanza getRequest() {
140            return request;
141        }
142
143        @Override
144        public String getMessage() {
145            StringBuilder sb = new StringBuilder();
146
147            if (stanza != null) {
148                Jid from = stanza.getFrom();
149                if (from != null) {
150                    sb.append("XMPP error reply received from " + from + ": ");
151                }
152            }
153
154            sb.append(error);
155
156            if (request != null) {
157                sb.append(" as result of the following request: ");
158                sb.append(request);
159            }
160
161            return sb.toString();
162        }
163
164        public static void ifHasErrorThenThrow(Stanza packet) throws XMPPErrorException {
165            ifHasErrorThenThrow(packet, null);
166        }
167
168        public static void ifHasErrorThenThrow(Stanza packet, Stanza request) throws XMPPErrorException {
169            StanzaError xmppError = packet.getError();
170            if (xmppError != null) {
171                throw new XMPPErrorException(packet, xmppError, request);
172            }
173        }
174    }
175
176    public static class FailedNonzaException extends XMPPException {
177
178        /**
179         *
180         */
181        private static final long serialVersionUID = 1L;
182
183        private final StanzaError.Condition condition;
184
185        private final Nonza nonza;
186
187        public FailedNonzaException(Nonza failedNonza) {
188            this(failedNonza, null);
189        }
190
191        public FailedNonzaException(Nonza nonza, StanzaError.Condition condition) {
192            this.condition = condition;
193            this.nonza = nonza;
194        }
195
196        public StanzaError.Condition getCondition() {
197            return condition;
198        }
199
200        public Nonza getNonza() {
201            return nonza;
202        }
203    }
204
205    public static class StreamErrorException extends XMPPException {
206        /**
207         *
208         */
209        private static final long serialVersionUID = 3400556867134848886L;
210        private final StreamError streamError;
211
212        /**
213         * Creates a new XMPPException with the stream error that was the root case of the
214         * exception. When a stream error is received from the server then the underlying connection
215         * will be closed by the server.
216         *
217         * @param streamError the root cause of the exception.
218         */
219        public StreamErrorException(StreamError streamError) {
220            super(streamError.getCondition().toString()
221                  + " You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions\n"
222                  + streamError.toString());
223            this.streamError = streamError;
224        }
225
226        /**
227         * Returns the StreamError associated with this exception. The underlying TCP connection is
228         * closed by the server after sending the stream error to the client.
229         *
230         * @return the StreamError associated with this exception.
231         */
232        public StreamError getStreamError() {
233            return streamError;
234        }
235
236    }
237}