1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2009 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smack;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.PipedReader;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.PipedWriter;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.Writer;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ExecutorService;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.Executors;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ThreadFactory;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.Connection;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.ConnectionCreationListener;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.ConnectionListener;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.PacketCollector;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.Roster;
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.XMPPException;
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet;
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Presence;
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.XMPPError;
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.StringUtils;
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClient;
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClientConfig;
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClientConnEvent;
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClientConnListener;
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClientRequestListener;
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHClientResponseListener;
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHException;
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BOSHMessageEvent;
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.BodyQName;
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport com.kenai.jbosh.ComposableBody;
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Creates a connection to a XMPP server via HTTP binding.
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * This is specified in the XEP-0206: XMPP Over BOSH.
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see Connection
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Guenther Niess
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class BOSHConnection extends Connection {
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The XMPP Over Bosh namespace.
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static final String XMPP_BOSH_NS = "urn:xmpp:xbosh";
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The BOSH namespace from XEP-0124.
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static final String BOSH_URI = "http://jabber.org/protocol/httpbind";
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The used BOSH client from the jbosh library.
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private BOSHClient client;
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Holds the initial configuration used while creating the connection.
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private final BOSHConfiguration config;
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    // Some flags which provides some info about the current state.
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean connected = false;
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean authenticated = false;
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean anonymous = false;
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean isFirstInitialization = true;
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean wasAuthenticated = false;
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean done = false;
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The Thread environment for sending packet listeners.
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private ExecutorService listenerExecutor;
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    // The readerPipe and consumer thread are used for the debugger.
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private PipedWriter readerPipe;
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Thread readerConsumer;
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The BOSH equivalent of the stream ID which is used for DIGEST authentication.
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected String authID = null;
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The session ID for the BOSH session with the connection manager.
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected String sessionID = null;
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The full JID of the authenticated user.
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String user = null;
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * The roster maybe also called buddy list holds the list of the users contacts.
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Roster roster = null;
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Create a HTTP Binding connection to a XMPP server.
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param https true if you want to use SSL
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *             (e.g. false for http://domain.lt:7070/http-bind).
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param host the hostname or IP address of the connection manager
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *             (e.g. domain.lt for http://domain.lt:7070/http-bind).
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param port the port of the connection manager
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *             (e.g. 7070 for http://domain.lt:7070/http-bind).
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param filePath the file which is described by the URL
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *             (e.g. /http-bind for http://domain.lt:7070/http-bind).
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param xmppDomain the XMPP service name
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *             (e.g. domain.lt for the user alice@domain.lt)
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public BOSHConnection(boolean https, String host, int port, String filePath, String xmppDomain) {
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        super(new BOSHConfiguration(https, host, port, filePath, xmppDomain));
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.config = (BOSHConfiguration) getConfiguration();
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Create a HTTP Binding connection to a XMPP server.
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param config The configuration which is used for this connection.
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public BOSHConnection(BOSHConfiguration config) {
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        super(config);
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.config = config;
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void connect() throws XMPPException {
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (connected) {
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Already connected to a server.");
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        done = false;
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Ensure a clean starting state
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (client != null) {
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                client.close();
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                client = null;
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            saslAuthentication.init();
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sessionID = null;
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            authID = null;
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Initialize BOSH client
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            BOSHClientConfig.Builder cfgBuilder = BOSHClientConfig.Builder
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .create(config.getURI(), config.getServiceName());
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (config.isProxyEnabled()) {
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                cfgBuilder.setProxy(config.getProxyAddress(), config.getProxyPort());
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            client = BOSHClient.create(cfgBuilder.build());
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Create an executor to deliver incoming packets to listeners.
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // We'll use a single thread with an unbounded queue.
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            listenerExecutor = Executors
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .newSingleThreadExecutor(new ThreadFactory() {
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        public Thread newThread(Runnable runnable) {
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            Thread thread = new Thread(runnable,
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    "Smack Listener Processor ("
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                            + connectionCounterValue + ")");
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            thread.setDaemon(true);
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            return thread;
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    });
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            client.addBOSHClientConnListener(new BOSHConnectionListener(this));
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            client.addBOSHClientResponseListener(new BOSHPacketReader(this));
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Initialize the debugger
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (config.isDebuggerEnabled()) {
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                initDebugger();
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (isFirstInitialization) {
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (debugger.getReaderListener() != null) {
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        addPacketListener(debugger.getReaderListener(), null);
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (debugger.getWriterListener() != null) {
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        addPacketSendingListener(debugger.getWriterListener(), null);
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Send the session creation request
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            client.send(ComposableBody.builder()
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .setNamespaceDefinition("xmpp", XMPP_BOSH_NS)
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .setAttribute(BodyQName.createWithPrefix(XMPP_BOSH_NS, "version", "xmpp"), "1.0")
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .build());
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } catch (Exception e) {
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException("Can't connect to " + getServiceName(), e);
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Wait for the response from the server
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (this) {
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            long endTime = System.currentTimeMillis() +
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                           SmackConfiguration.getPacketReplyTimeout() * 6;
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            while ((!connected) && (System.currentTimeMillis() < endTime)) {
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                try {
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    wait(Math.abs(endTime - System.currentTimeMillis()));
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                catch (InterruptedException e) {}
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If there is no feedback, throw an remote server timeout error
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!connected && !done) {
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            done = true;
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String errorMessage = "Timeout reached for the connection to "
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    + getHost() + ":" + getPort() + ".";
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new XMPPException(
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    errorMessage,
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    new XMPPError(XMPPError.Condition.remote_server_timeout, errorMessage));
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getConnectionID() {
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!connected) {
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else if (authID != null) {
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return authID;
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else {
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return sessionID;
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Roster getRoster() {
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (roster == null) {
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return null;
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!config.isRosterLoadedAtLogin()) {
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            roster.reload();
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If this is the first time the user has asked for the roster after calling
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // login, we want to wait for the server to send back the user's roster.
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // This behavior shields API users from having to worry about the fact that
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // roster operations are asynchronous, although they'll still have to listen
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // for changes to the roster. Note: because of this waiting logic, internal
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Smack code should be wary about calling the getRoster method, and may
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // need to access the roster object directly.
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!roster.rosterInitialized) {
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                synchronized (roster) {
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    long waitTime = SmackConfiguration.getPacketReplyTimeout();
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    long start = System.currentTimeMillis();
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    while (!roster.rosterInitialized) {
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        if (waitTime <= 0) {
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            break;
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        roster.wait(waitTime);
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        long now = System.currentTimeMillis();
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        waitTime -= now - start;
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        start = now;
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } catch (InterruptedException ie) {
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Ignore.
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return roster;
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public String getUser() {
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return user;
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean isAnonymous() {
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return anonymous;
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean isAuthenticated() {
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return authenticated;
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean isConnected() {
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return connected;
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean isSecureConnection() {
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // TODO: Implement SSL usage
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public boolean isUsingCompression() {
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // TODO: Implement compression
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return false;
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void login(String username, String password, String resource)
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throws XMPPException {
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!isConnected()) {
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Not connected to server.");
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (authenticated) {
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Already logged in to server.");
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Do partial version of nameprep on the username.
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        username = username.toLowerCase().trim();
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        String response;
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isSASLAuthenticationEnabled()
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                && saslAuthentication.hasNonAnonymousAuthentication()) {
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Authenticate using SASL
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (password != null) {
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                response = saslAuthentication.authenticate(username, password, resource);
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else {
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                response = saslAuthentication.authenticate(username, resource, config.getCallbackHandler());
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else {
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Authenticate using Non-SASL
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            response = new NonSASLAuthentication(this).authenticate(username, password, resource);
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Set the user.
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (response != null) {
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.user = response;
332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Update the serviceName with the one returned by the server
333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            config.setServiceName(StringUtils.parseServer(response));
334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        } else {
335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.user = username + "@" + getServiceName();
336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (resource != null) {
337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                this.user += "/" + resource;
338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Create the roster if it is not a reconnection.
342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (this.roster == null) {
343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (this.rosterStorage == null) {
344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                this.roster = new Roster(this);
345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else {
346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                this.roster = new Roster(this, rosterStorage);
347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Set presence to online.
351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isSendPresence()) {
352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sendPacket(new Presence(Presence.Type.available));
353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Indicate that we're now authenticated.
356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        authenticated = true;
357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        anonymous = false;
358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isRosterLoadedAtLogin()) {
360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.roster.reload();
361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Stores the autentication for future reconnection
363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        config.setLoginInfo(username, password, resource);
364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If debugging is enabled, change the the debug window title to include
366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // the
367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // name we are now logged-in as.l
368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isDebuggerEnabled() && debugger != null) {
369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            debugger.userHasLogged(user);
370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void loginAnonymously() throws XMPPException {
374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    	if (!isConnected()) {
375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Not connected to server.");
376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (authenticated) {
378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Already logged in to server.");
379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        String response;
382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isSASLAuthenticationEnabled() &&
383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                saslAuthentication.hasAnonymousAuthentication()) {
384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            response = saslAuthentication.authenticateAnonymously();
385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        else {
387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Authenticate using Non-SASL
388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            response = new NonSASLAuthentication(this).authenticateAnonymously();
389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Set the user value.
392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.user = response;
393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Update the serviceName with the one returned by the server
394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        config.setServiceName(StringUtils.parseServer(response));
395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Anonymous users can't have a roster.
397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        roster = null;
398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Set presence to online.
400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isSendPresence()) {
401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            sendPacket(new Presence(Presence.Type.available));
402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Indicate that we're now authenticated.
405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        authenticated = true;
406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        anonymous = true;
407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If debugging is enabled, change the the debug window title to include the
409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // name we are now logged-in as.
410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If DEBUG_ENABLED was set to true AFTER the connection was created the debugger
411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // will be null
412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (config.isDebuggerEnabled() && debugger != null) {
413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            debugger.userHasLogged(user);
414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void sendPacket(Packet packet) {
418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!isConnected()) {
419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Not connected to server.");
420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (packet == null) {
422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new NullPointerException("Packet is null.");
423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!done) {
425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Invoke interceptors for the new packet that is about to be sent.
426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Interceptors
427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // may modify the content of the packet.
428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            firePacketInterceptors(packet);
429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                send(ComposableBody.builder().setPayloadXML(packet.toXML())
432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        .build());
433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } catch (BOSHException e) {
434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                e.printStackTrace();
435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return;
436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Process packet writer listeners. Note that we're using the
439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // sending
440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // thread so it's expected that listeners are fast.
441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            firePacketSendingListeners(packet);
442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void disconnect(Presence unavailablePresence) {
446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!connected) {
447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return;
448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        shutdown(unavailablePresence);
450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Cleanup
452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (roster != null) {
453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            roster.cleanup();
454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            roster = null;
455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        sendListeners.clear();
457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        recvListeners.clear();
458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        collectors.clear();
459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        interceptors.clear();
460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Reset the connection flags
462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        wasAuthenticated = false;
463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        isFirstInitialization = true;
464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Notify connection listeners of the connection closing if done hasn't already been set.
466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (ConnectionListener listener : getConnectionListeners()) {
467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                listener.connectionClosed();
469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Exception e) {
471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Catch and print any exception so we can recover
472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // from a faulty listener and finish the shutdown process
473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                e.printStackTrace();
474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Closes the connection by setting presence to unavailable and closing the
480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * HTTP client. The shutdown logic will be used during a planned disconnection or when
481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * dealing with an unexpected disconnection. Unlike {@link #disconnect()} the connection's
482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * BOSH packet reader and {@link Roster} will not be removed; thus
483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * connection's state is kept.
484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param unavailablePresence the presence packet to send during shutdown.
486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected void shutdown(Presence unavailablePresence) {
488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        setWasAuthenticated(authenticated);
489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        authID = null;
490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        sessionID = null;
491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        done = true;
492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        authenticated = false;
493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        connected = false;
494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        isFirstInitialization = false;
495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            client.disconnect(ComposableBody.builder()
498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .setNamespaceDefinition("xmpp", XMPP_BOSH_NS)
499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .setPayloadXML(unavailablePresence.toXML())
500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    .build());
501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Wait 150 ms for processes to clean-up, then shutdown.
502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Thread.sleep(150);
503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        catch (Exception e) {
505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Ignore.
506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Close down the readers and writers.
509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (readerPipe != null) {
510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                readerPipe.close();
512d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Throwable ignore) { /* ignore */ }
514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            reader = null;
515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (reader != null) {
517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                reader.close();
519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Throwable ignore) { /* ignore */ }
521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            reader = null;
522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (writer != null) {
524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                writer.close();
526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Throwable ignore) { /* ignore */ }
528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            writer = null;
529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Shut down the listener executor.
532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (listenerExecutor != null) {
533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            listenerExecutor.shutdown();
534d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        readerConsumer = null;
536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sets whether the connection has already logged in the server.
540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param wasAuthenticated true if the connection has already been authenticated.
542d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
543d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private void setWasAuthenticated(boolean wasAuthenticated) {
544d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!this.wasAuthenticated) {
545d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.wasAuthenticated = wasAuthenticated;
546d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
547d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
548d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
549d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
550d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Send a HTTP request to the connection manager with the provided body element.
551d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
552d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param body the body which will be sent.
553d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
554d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected void send(ComposableBody body) throws BOSHException {
555d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!connected) {
556d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new IllegalStateException("Not connected to a server!");
557d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
558d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (body == null) {
559d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throw new NullPointerException("Body mustn't be null!");
560d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
561d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (sessionID != null) {
562d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            body = body.rebuild().setAttribute(
563d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    BodyQName.create(BOSH_URI, "sid"), sessionID).build();
564d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
565d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        client.send(body);
566d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
567d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
568d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
569d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Processes a packet after it's been fully parsed by looping through the
570d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * installed packet collectors and listeners and letting them examine the
571d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * packet to see if they are a match with the filter.
572d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
573d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param packet the packet to process.
574d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
575d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected void processPacket(Packet packet) {
576d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (packet == null) {
577d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return;
578d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
579d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
580d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Loop through all collectors and notify the appropriate ones.
581d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (PacketCollector collector : getPacketCollectors()) {
582d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            collector.processPacket(packet);
583d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
584d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
585d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Deliver the incoming packet to listeners.
586d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        listenerExecutor.submit(new ListenerNotification(packet));
587d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
588d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
589d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
590d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Initialize the SmackDebugger which allows to log and debug XML traffic.
591d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
592d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected void initDebugger() {
593d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // TODO: Maybe we want to extend the SmackDebugger for simplification
594d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        //       and a performance boost.
595d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
596d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Initialize a empty writer which discards all data.
597d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        writer = new Writer() {
598d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void write(char[] cbuf, int off, int len) { /* ignore */}
599d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void close() { /* ignore */ }
600d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                public void flush() { /* ignore */ }
601d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            };
602d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
603d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Initialize a pipe for received raw data.
604d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
605d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            readerPipe = new PipedWriter();
606d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            reader = new PipedReader(readerPipe);
607d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
608d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        catch (IOException e) {
609d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Ignore
610d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
611d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
612d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Call the method from the parent class which initializes the debugger.
613d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        super.initDebugger();
614d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
615d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Add listeners for the received and sent raw data.
616d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        client.addBOSHClientResponseListener(new BOSHClientResponseListener() {
617d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void responseReceived(BOSHMessageEvent event) {
618d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (event.getBody() != null) {
619d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    try {
620d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        readerPipe.write(event.getBody().toXML());
621d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        readerPipe.flush();
622d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    } catch (Exception e) {
623d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Ignore
624d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
625d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
626d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
627d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        });
628d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        client.addBOSHClientRequestListener(new BOSHClientRequestListener() {
629d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void requestSent(BOSHMessageEvent event) {
630d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (event.getBody() != null) {
631d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    try {
632d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        writer.write(event.getBody().toXML());
633d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    } catch (Exception e) {
634d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Ignore
635d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
636d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
637d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
638d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        });
639d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
640d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Create and start a thread which discards all read data.
641d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        readerConsumer = new Thread() {
642d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            private Thread thread = this;
643d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            private int bufferLength = 1024;
644d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
645d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            public void run() {
646d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                try {
647d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    char[] cbuf = new char[bufferLength];
648d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    while (readerConsumer == thread && !done) {
649d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        reader.read(cbuf, 0, bufferLength);
650d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
651d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } catch (IOException e) {
652d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // Ignore
653d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
654d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
655d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        };
656d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        readerConsumer.setDaemon(true);
657d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        readerConsumer.start();
658d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
659d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
660d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
661d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Sends out a notification that there was an error with the connection
662d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * and closes the connection.
663d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
664d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param e the exception that causes the connection close event.
665d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
666d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected void notifyConnectionError(Exception e) {
667d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Closes the connection temporary. A reconnection is possible
668d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        shutdown(new Presence(Presence.Type.unavailable));
669d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Print the stack trace to help catch the problem
670d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        e.printStackTrace();
671d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Notify connection listeners of the error.
672d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        for (ConnectionListener listener : getConnectionListeners()) {
673d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
674d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                listener.connectionClosedOnError(e);
675d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
676d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (Exception e2) {
677d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Catch and print any exception so we can recover
678d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // from a faulty listener
679d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                e2.printStackTrace();
680d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
681d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
682d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
683d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
684d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
685d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
686d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * A listener class which listen for a successfully established connection
687d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * and connection errors and notifies the BOSHConnection.
688d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
689d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @author Guenther Niess
690d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
691d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private class BOSHConnectionListener implements BOSHClientConnListener {
692d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
693d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private final BOSHConnection connection;
694d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
695d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public BOSHConnectionListener(BOSHConnection connection) {
696d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.connection = connection;
697d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
698d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
699d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        /**
700d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Notify the BOSHConnection about connection state changes.
701d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * Process the connection listeners and try to login if the
702d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         * connection was formerly authenticated and is now reconnected.
703d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen         */
704d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public void connectionEvent(BOSHClientConnEvent connEvent) {
705d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
706d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (connEvent.isConnected()) {
707d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connected = true;
708d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (isFirstInitialization) {
709d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        isFirstInitialization = false;
710d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        for (ConnectionCreationListener listener : getConnectionCreationListeners()) {
711d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            listener.connectionCreated(connection);
712d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
713d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
714d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    else {
715d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        try {
716d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            if (wasAuthenticated) {
717d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                connection.login(
718d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                        config.getUsername(),
719d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                        config.getPassword(),
720d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                        config.getResource());
721d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            }
722d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            for (ConnectionListener listener : getConnectionListeners()) {
723d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                 listener.reconnectionSuccessful();
724d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            }
725d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
726d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        catch (XMPPException e) {
727d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            for (ConnectionListener listener : getConnectionListeners()) {
728d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                listener.reconnectionFailed(e);
729d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                           }
730d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
731d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
732d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
733d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                else {
734d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (connEvent.isError()) {
735d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        try {
736d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            connEvent.getCause();
737d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
738d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        catch (Exception e) {
739d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            notifyConnectionError(e);
740d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
741d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
742d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connected = false;
743d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
744d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
745d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            finally {
746d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                synchronized (connection) {
747d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    connection.notifyAll();
748d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
749d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
750d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
751d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
752d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
753d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
754d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * This class notifies all listeners that a packet was received.
755d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
756d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private class ListenerNotification implements Runnable {
757d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
758d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private Packet packet;
759d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
760d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public ListenerNotification(Packet packet) {
761d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.packet = packet;
762d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
763d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
764d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public void run() {
765d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (ListenerWrapper listenerWrapper : recvListeners.values()) {
766d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                listenerWrapper.notifyListener(packet);
767d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
768d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
769d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
770d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
771d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	@Override
772d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	public void setRosterStorage(RosterStorage storage)
773d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throws IllegalStateException {
774d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		if(this.roster!=null){
775d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new IllegalStateException("Roster is already initialized");
776d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
777d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		this.rosterStorage = storage;
778d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen	}
779d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
780