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.StreamError;
023import org.jivesoftware.smack.packet.XMPPError;
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 XMPPError
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    public static class XMPPErrorException extends XMPPException {
073        /**
074         * 
075         */
076        private static final long serialVersionUID = 212790389529249604L;
077        private final XMPPError error;
078        private final Stanza stanza;
079
080        /**
081         * Creates a new XMPPErrorException with the given builder.
082         *
083         * @param xmppErrorBuilder
084         * @deprecated Use {@link #XMPPErrorException(Stanza, XMPPError)} instead.
085         */
086        @Deprecated
087        public XMPPErrorException(XMPPError.Builder xmppErrorBuilder) {
088            this(null, xmppErrorBuilder.build());
089        }
090
091        /**
092         * Creates a new XMPPErrorException with the XMPPError that was the root case of the exception.
093         *
094         * @param stanza stanza that contained the exception.
095         * @param error the root cause of the exception.
096         */
097        public XMPPErrorException(Stanza stanza, XMPPError error) {
098            super();
099            this.error = error;
100            this.stanza = stanza;
101        }
102
103        /**
104         * Returns the XMPPError associated with this exception, or <tt>null</tt> if there isn't
105         * one.
106         * 
107         * @return the XMPPError associated with this exception.
108         */
109        public XMPPError getXMPPError() {
110            return error;
111        }
112
113        @Override
114        public String getMessage() {
115            StringBuilder sb = new StringBuilder();
116
117            if (stanza != null) {
118                Jid from = stanza.getFrom();
119                if (from != null) {
120                    sb.append("XMPP error reply received from " + from + ": ");
121                }
122            }
123
124            sb.append(error);
125
126            return sb.toString();
127        }
128
129        public static void ifHasErrorThenThrow(Stanza packet) throws XMPPErrorException {
130            XMPPError xmppError = packet.getError();
131            if (xmppError != null) {
132                throw new XMPPErrorException(packet, xmppError);
133            }
134        }
135    }
136
137    public static class FailedNonzaException extends XMPPException {
138
139        /**
140         * 
141         */
142        private static final long serialVersionUID = 1L;
143
144        private final XMPPError.Condition condition;
145
146        private final Nonza nonza;
147
148        public FailedNonzaException(Nonza nonza, XMPPError.Condition condition) {
149            this.condition = condition;
150            this.nonza = nonza;
151        }
152
153        public XMPPError.Condition getCondition() {
154            return condition;
155        }
156
157        public Nonza getNonza() {
158            return nonza;
159        }
160    }
161
162    public static class StreamErrorException extends XMPPException {
163        /**
164         * 
165         */
166        private static final long serialVersionUID = 3400556867134848886L;
167        private final StreamError streamError;
168
169        /**
170         * Creates a new XMPPException with the stream error that was the root case of the
171         * exception. When a stream error is received from the server then the underlying connection
172         * will be closed by the server.
173         * 
174         * @param streamError the root cause of the exception.
175         */
176        public StreamErrorException(StreamError streamError) {
177            super(streamError.getCondition().toString()
178                  + " You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions\n"
179                  + streamError.toString());
180            this.streamError = streamError;
181        }
182
183        /**
184         * Returns the StreamError associated with this exception. The underlying TCP connection is
185         * closed by the server after sending the stream error to the client.
186         * 
187         * @return the StreamError associated with this exception.
188         */
189        public StreamError getStreamError() {
190            return streamError;
191        }
192
193    }
194}