001/**
002 *
003 * Copyright 2014-2015 Florian Schmaus
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 */
017package org.jivesoftware.smack;
018
019import java.util.ArrayList;
020import java.util.List;
021
022import org.jivesoftware.smack.filter.StanzaFilter;
023import org.jivesoftware.smack.util.dns.HostAddress;
024
025/**
026 * Smack uses SmackExceptions for errors that are not defined by any XMPP specification.
027 * 
028 * @author Florian Schmaus
029 */
030public class SmackException extends Exception {
031
032    /**
033     * 
034     */
035    private static final long serialVersionUID = 1844674365368214457L;
036
037    /**
038     * Creates a new SmackException with the Throwable that was the root cause of the exception.
039     * 
040     * @param wrappedThrowable the root cause of the exception.
041     */
042    public SmackException(Throwable wrappedThrowable) {
043        super(wrappedThrowable);
044    }
045
046    public SmackException(String message) {
047        super(message);
048    }
049
050    public SmackException(String message, Throwable wrappedThrowable) {
051        super(message, wrappedThrowable);
052    }
053
054    protected SmackException() {
055    }
056
057    /**
058     * Exception thrown always when there was no response to an request within the stanza(/packet) reply timeout of the used
059     * connection instance. You can modify (e.g. increase) the stanza(/packet) reply timeout with
060     * {@link XMPPConnection#setPacketReplyTimeout(long)}.
061     */
062    public static class NoResponseException extends SmackException {
063        /**
064         * 
065         */
066        private static final long serialVersionUID = -6523363748984543636L;
067
068        private final StanzaFilter filter;
069
070        private NoResponseException(String message, StanzaFilter filter) {
071            super(message);
072            this.filter = filter;
073        }
074
075        /**
076         * Get the filter that was used to collect the response.
077         *
078         * @return the used filter or <code>null</code>.
079         */
080        public StanzaFilter getFilter() {
081            return filter;
082        }
083
084        public static NoResponseException newWith(XMPPConnection connection) {
085            return newWith(connection, (StanzaFilter) null);
086        }
087
088        public static NoResponseException newWith(XMPPConnection connection,
089                        PacketCollector collector) {
090            return newWith(connection, collector.getStanzaFilter());
091        }
092
093        public static NoResponseException newWith(XMPPConnection connection, StanzaFilter filter) {
094            final long replyTimeout = connection.getPacketReplyTimeout();
095            final StringBuilder sb = new StringBuilder(256);
096            sb.append("No response received within reply timeout. Timeout was "
097                            + replyTimeout + "ms (~"
098                            + replyTimeout / 1000 + "s). Used filter: ");
099            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
109    }
110
111    public static class NotLoggedInException extends SmackException {
112
113        /**
114         * 
115         */
116        private static final long serialVersionUID = 3216216839100019278L;
117
118        public NotLoggedInException() {
119            super("Client is not logged in");
120        }
121    }
122
123    public static class AlreadyLoggedInException extends SmackException {
124
125        /**
126         * 
127         */
128        private static final long serialVersionUID = 5011416918049935231L;
129
130        public AlreadyLoggedInException() {
131            super("Client is already logged in");
132        }
133    }
134
135    public static class AlreadyConnectedException extends SmackException {
136
137        /**
138         * 
139         */
140        private static final long serialVersionUID = 5011416918049135231L;
141
142        public AlreadyConnectedException() {
143            super("Client is already connected");
144        }
145    }
146
147    public static class NotConnectedException extends SmackException {
148
149        /**
150         * 
151         */
152        private static final long serialVersionUID = 9197980400776001173L;
153
154        public NotConnectedException() {
155            this(null);
156        }
157
158        public NotConnectedException(String optionalHint) {
159            super("Client is not, or no longer, connected."
160                            + (optionalHint != null ? ' ' + optionalHint : ""));
161        }
162    }
163
164    public static class IllegalStateChangeException extends SmackException {
165
166        /**
167         * 
168         */
169        private static final long serialVersionUID = -1766023961577168927L;
170
171        public IllegalStateChangeException() {
172        }
173    }
174
175    public static abstract class SecurityRequiredException extends SmackException {
176
177        /**
178         * 
179         */
180        private static final long serialVersionUID = 384291845029773545L;
181
182        public SecurityRequiredException(String message) {
183            super(message);
184        }
185    }
186
187    public static class SecurityRequiredByClientException extends SecurityRequiredException {
188        /**
189         * 
190         */
191        private static final long serialVersionUID = 2395325821201543159L;
192
193        public SecurityRequiredByClientException() {
194            super("SSL/TLS required by client but not supported by server");
195        }
196    }
197
198    public static class SecurityRequiredByServerException extends SecurityRequiredException {
199        /**
200         * 
201         */
202        private static final long serialVersionUID = 8268148813117631819L;
203
204        public SecurityRequiredByServerException() {
205            super("SSL/TLS required by server but disabled in client");
206        }
207    }
208
209    public static class SecurityNotPossibleException extends SmackException {
210
211        /**
212         * 
213         */
214        private static final long serialVersionUID = -6836090872690331336L;
215
216        public SecurityNotPossibleException(String message) {
217            super(message);
218        }
219    }
220
221    /**
222     * ConnectionException is thrown if Smack is unable to connect to all hosts of a given XMPP
223     * service. The failed hosts can be retrieved with
224     * {@link ConnectionException#getFailedAddresses()}, which will have the exception causing the
225     * connection failure set and retrievable with {@link HostAddress#getException()}.
226     */
227    public static class ConnectionException extends SmackException {
228
229        /**
230         * 
231         */
232        private static final long serialVersionUID = 1686944201672697996L;
233
234        private final List<HostAddress> failedAddresses;
235
236        public ConnectionException(Throwable wrappedThrowable) {
237            super(wrappedThrowable);
238            failedAddresses = new ArrayList<HostAddress>(0);
239        }
240
241        private ConnectionException(String message, List<HostAddress> failedAddresses) {
242            super(message);
243            this.failedAddresses = failedAddresses;
244        }
245
246        public static ConnectionException from(List<HostAddress> failedAddresses) {
247            final String DELIMITER = ", ";
248            StringBuilder sb = new StringBuilder("The following addresses failed: ");
249            for (HostAddress hostAddress : failedAddresses) {
250                sb.append(hostAddress.getErrorMessage());
251                sb.append(DELIMITER);
252            }
253            // Remove the last delimiter
254            sb.setLength(sb.length() - DELIMITER.length());
255            return new ConnectionException(sb.toString(), failedAddresses);
256        }
257
258        public List<HostAddress> getFailedAddresses() {
259            return failedAddresses;
260        }
261    }
262
263    public static class FeatureNotSupportedException extends SmackException {
264
265        /**
266         * 
267         */
268        private static final long serialVersionUID = 4713404802621452016L;
269
270        private final String feature;
271        private final String jid;
272
273        public FeatureNotSupportedException(String feature) {
274            this(feature, null);
275        }
276
277        public FeatureNotSupportedException(String feature, String jid) {
278            super(feature + " not supported" + (jid == null ? "" : " by '" + jid + "'"));
279            this.jid = jid;
280            this.feature = feature;
281        }
282
283        /**
284         * Get the feature which is not supported.
285         *
286         * @return the feature which is not supported
287         */
288        public String getFeature() {
289            return feature;
290        }
291
292        /**
293         * Get JID which does not support the feature. The JID can be null in cases when there are
294         * multiple JIDs queried for this feature.
295         *
296         * @return the JID which does not support the feature, or null
297         */
298        public String getJid() {
299            return jid;
300        }
301    }
302
303    public static class ResourceBindingNotOfferedException extends SmackException {
304
305        /**
306         * 
307         */
308        private static final long serialVersionUID = 2346934138253437571L;
309
310        public ResourceBindingNotOfferedException() {
311            super("Resource binding was not offered by server");
312        }
313    }
314}