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 given builder. 091 * 092 * @param xmppErrorBuilder 093 * @deprecated Use {@link #XMPPErrorException(Stanza, StanzaError)} instead. 094 */ 095 @Deprecated 096 public XMPPErrorException(StanzaError.Builder xmppErrorBuilder) { 097 this(null, xmppErrorBuilder.build()); 098 } 099 100 /** 101 * Creates a new XMPPErrorException with the XMPPError that was the root case of the exception. 102 * 103 * @param stanza stanza that contained the exception. 104 * @param error the root cause of the exception. 105 */ 106 public XMPPErrorException(Stanza stanza, StanzaError error) { 107 this(stanza, error, null); 108 } 109 110 /** 111 * Creates a new XMPPErrorException with the XMPPError that was the root case of the exception. 112 * 113 * @param request the request which triggered the error. 114 * @param stanza stanza that contained the exception. 115 * @param error the root cause of the exception. 116 * @since 4.3.0 117 */ 118 public XMPPErrorException(Stanza stanza, StanzaError error, Stanza request) { 119 super(); 120 this.error = error; 121 this.stanza = stanza; 122 this.request = request; 123 } 124 125 /** 126 * Returns the XMPPError associated with this exception, or <tt>null</tt> if there isn't 127 * one. 128 * 129 * @return the XMPPError associated with this exception. 130 * @deprecated use {@link #getStanzaError()} instead. 131 */ 132 @Deprecated 133 // TODO Remove in Smack 4.4. 134 public StanzaError getXMPPError() { 135 return error; 136 } 137 138 /** 139 * Returns the stanza error extension element associated with this exception. 140 * 141 * @return the stanza error extension element associated with this exception. 142 */ 143 public StanzaError getStanzaError() { 144 return error; 145 } 146 147 /** 148 * Get the request which triggered the error response causing this exception. 149 * 150 * @return the request or {@code null}. 151 * @since 4.3.0 152 */ 153 public Stanza getRequest() { 154 return request; 155 } 156 157 @Override 158 public String getMessage() { 159 StringBuilder sb = new StringBuilder(); 160 161 if (stanza != null) { 162 Jid from = stanza.getFrom(); 163 if (from != null) { 164 sb.append("XMPP error reply received from " + from + ": "); 165 } 166 } 167 168 sb.append(error); 169 170 if (request != null) { 171 sb.append(" as result of the following request: "); 172 sb.append(request); 173 } 174 175 return sb.toString(); 176 } 177 178 public static void ifHasErrorThenThrow(Stanza packet) throws XMPPErrorException { 179 ifHasErrorThenThrow(packet, null); 180 } 181 182 public static void ifHasErrorThenThrow(Stanza packet, Stanza request) throws XMPPErrorException { 183 StanzaError xmppError = packet.getError(); 184 if (xmppError != null) { 185 throw new XMPPErrorException(packet, xmppError, request); 186 } 187 } 188 } 189 190 public static class FailedNonzaException extends XMPPException { 191 192 /** 193 * 194 */ 195 private static final long serialVersionUID = 1L; 196 197 private final StanzaError.Condition condition; 198 199 private final Nonza nonza; 200 201 public FailedNonzaException(Nonza nonza, StanzaError.Condition condition) { 202 this.condition = condition; 203 this.nonza = nonza; 204 } 205 206 public StanzaError.Condition getCondition() { 207 return condition; 208 } 209 210 public Nonza getNonza() { 211 return nonza; 212 } 213 } 214 215 public static class StreamErrorException extends XMPPException { 216 /** 217 * 218 */ 219 private static final long serialVersionUID = 3400556867134848886L; 220 private final StreamError streamError; 221 222 /** 223 * Creates a new XMPPException with the stream error that was the root case of the 224 * exception. When a stream error is received from the server then the underlying connection 225 * will be closed by the server. 226 * 227 * @param streamError the root cause of the exception. 228 */ 229 public StreamErrorException(StreamError streamError) { 230 super(streamError.getCondition().toString() 231 + " You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions\n" 232 + streamError.toString()); 233 this.streamError = streamError; 234 } 235 236 /** 237 * Returns the StreamError associated with this exception. The underlying TCP connection is 238 * closed by the server after sending the stream error to the client. 239 * 240 * @return the StreamError associated with this exception. 241 */ 242 public StreamError getStreamError() { 243 return streamError; 244 } 245 246 } 247}