1/**
2 * $RCSfile$
3 * $Revision$
4 * $Date$
5 *
6 * Copyright 2003-2007 Jive Software.
7 *
8 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package org.jivesoftware.smack;
22
23import org.jivesoftware.smack.packet.StreamError;
24import org.jivesoftware.smack.packet.XMPPError;
25
26import java.io.PrintStream;
27import java.io.PrintWriter;
28
29/**
30 * A generic exception that is thrown when an error occurs performing an
31 * XMPP operation. XMPP servers can respond to error conditions with an error code
32 * and textual description of the problem, which are encapsulated in the XMPPError
33 * class. When appropriate, an XMPPError instance is attached instances of this exception.<p>
34 *
35 * When a stream error occured, the server will send a stream error to the client before
36 * closing the connection. Stream errors are unrecoverable errors. When a stream error
37 * is sent to the client an XMPPException will be thrown containing the StreamError sent
38 * by the server.
39 *
40 * @see XMPPError
41 * @author Matt Tucker
42 */
43public class XMPPException extends Exception {
44
45    private StreamError streamError = null;
46    private XMPPError error = null;
47    private Throwable wrappedThrowable = null;
48
49    /**
50     * Creates a new XMPPException.
51     */
52    public XMPPException() {
53        super();
54    }
55
56    /**
57     * Creates a new XMPPException with a description of the exception.
58     *
59     * @param message description of the exception.
60     */
61    public XMPPException(String message) {
62        super(message);
63    }
64
65    /**
66     * Creates a new XMPPException with the Throwable that was the root cause of the
67     * exception.
68     *
69     * @param wrappedThrowable the root cause of the exception.
70     */
71    public XMPPException(Throwable wrappedThrowable) {
72        super();
73        this.wrappedThrowable = wrappedThrowable;
74    }
75
76    /**
77     * Cretaes a new XMPPException with the stream error that was the root case of the
78     * exception. When a stream error is received from the server then the underlying
79     * TCP connection will be closed by the server.
80     *
81     * @param streamError the root cause of the exception.
82     */
83    public XMPPException(StreamError streamError) {
84        super();
85        this.streamError = streamError;
86    }
87
88    /**
89     * Cretaes a new XMPPException with the XMPPError that was the root case of the
90     * exception.
91     *
92     * @param error the root cause of the exception.
93     */
94    public XMPPException(XMPPError error) {
95        super();
96        this.error = error;
97    }
98
99    /**
100     * Creates a new XMPPException with a description of the exception and the
101     * Throwable that was the root cause of the exception.
102     *
103     * @param message a description of the exception.
104     * @param wrappedThrowable the root cause of the exception.
105     */
106    public XMPPException(String message, Throwable wrappedThrowable) {
107        super(message);
108        this.wrappedThrowable = wrappedThrowable;
109    }
110
111    /**
112     * Creates a new XMPPException with a description of the exception, an XMPPError,
113     * and the Throwable that was the root cause of the exception.
114     *
115     * @param message a description of the exception.
116     * @param error the root cause of the exception.
117     * @param wrappedThrowable the root cause of the exception.
118     */
119    public XMPPException(String message, XMPPError error, Throwable wrappedThrowable) {
120        super(message);
121        this.error = error;
122        this.wrappedThrowable = wrappedThrowable;
123    }
124
125    /**
126     * Creates a new XMPPException with a description of the exception and the
127     * XMPPException that was the root cause of the exception.
128     *
129     * @param message a description of the exception.
130     * @param error the root cause of the exception.
131     */
132    public XMPPException(String message, XMPPError error) {
133        super(message);
134        this.error = error;
135    }
136
137    /**
138     * Returns the XMPPError asscociated with this exception, or <tt>null</tt> if there
139     * isn't one.
140     *
141     * @return the XMPPError asscociated with this exception.
142     */
143    public XMPPError getXMPPError() {
144        return error;
145    }
146
147    /**
148     * Returns the StreamError asscociated with this exception, or <tt>null</tt> if there
149     * isn't one. The underlying TCP connection is closed by the server after sending the
150     * stream error to the client.
151     *
152     * @return the StreamError asscociated with this exception.
153     */
154    public StreamError getStreamError() {
155        return streamError;
156    }
157
158    /**
159     * Returns the Throwable asscociated with this exception, or <tt>null</tt> if there
160     * isn't one.
161     *
162     * @return the Throwable asscociated with this exception.
163     */
164    public Throwable getWrappedThrowable() {
165        return wrappedThrowable;
166    }
167
168    public void printStackTrace() {
169        printStackTrace(System.err);
170    }
171
172    public void printStackTrace(PrintStream out) {
173        super.printStackTrace(out);
174        if (wrappedThrowable != null) {
175            out.println("Nested Exception: ");
176            wrappedThrowable.printStackTrace(out);
177        }
178    }
179
180    public void printStackTrace(PrintWriter out) {
181        super.printStackTrace(out);
182        if (wrappedThrowable != null) {
183            out.println("Nested Exception: ");
184            wrappedThrowable.printStackTrace(out);
185        }
186    }
187
188    public String getMessage() {
189        String msg = super.getMessage();
190        // If the message was not set, but there is an XMPPError, return the
191        // XMPPError as the message.
192        if (msg == null && error != null) {
193            return error.toString();
194        }
195        else if (msg == null && streamError != null) {
196            return streamError.toString();
197        }
198        return msg;
199    }
200
201    public String toString() {
202        StringBuilder buf = new StringBuilder();
203        String message = super.getMessage();
204        if (message != null) {
205            buf.append(message).append(": ");
206        }
207        if (error != null) {
208            buf.append(error);
209        }
210        if (streamError != null) {
211            buf.append(streamError);
212        }
213        if (wrappedThrowable != null) {
214            buf.append("\n  -- caused by: ").append(wrappedThrowable);
215        }
216
217        return buf.toString();
218    }
219}