• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1diff --git com/kenai/jbosh/ApacheHTTPResponse.java com/kenai/jbosh/ApacheHTTPResponse.java
2new file mode 100644
3index 0000000..9f6731f
4--- /dev/null
5+++ com/kenai/jbosh/ApacheHTTPResponse.java
6@@ -0,0 +1,253 @@
7+/*
8+ * Copyright 2009 Guenther Niess
9+ *
10+ * Licensed under the Apache License, Version 2.0 (the "License");
11+ * you may not use this file except in compliance with the License.
12+ * You may obtain a copy of the License at
13+ *
14+ *   http://www.apache.org/licenses/LICENSE-2.0
15+ *
16+ * Unless required by applicable law or agreed to in writing, software
17+ * distributed under the License is distributed on an "AS IS" BASIS,
18+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19+ * See the License for the specific language governing permissions and
20+ * limitations under the License.
21+ */
22+
23+package com.kenai.jbosh;
24+
25+import java.io.IOException;
26+import java.util.concurrent.locks.Lock;
27+import java.util.concurrent.locks.ReentrantLock;
28+
29+import org.apache.http.HttpEntity;
30+import org.apache.http.HttpResponse;
31+import org.apache.http.client.HttpClient;
32+import org.apache.http.client.methods.HttpPost;
33+import org.apache.http.entity.ByteArrayEntity;
34+
35+import org.apache.http.protocol.BasicHttpContext;
36+import org.apache.http.protocol.HttpContext;
37+import org.apache.http.util.EntityUtils;
38+
39+final class ApacheHTTPResponse implements HTTPResponse {
40+
41+    ///////////////////////////////////////////////////////////////////////////
42+    // Constants:
43+
44+    /**
45+     * Name of the accept encoding header.
46+     */
47+    private static final String ACCEPT_ENCODING = "Accept-Encoding";
48+
49+    /**
50+     * Value to use for the ACCEPT_ENCODING header.
51+     */
52+    private static final String ACCEPT_ENCODING_VAL =
53+            ZLIBCodec.getID() + ", " + GZIPCodec.getID();
54+
55+    /**
56+     * Name of the character set to encode the body to/from.
57+     */
58+    private static final String CHARSET = "UTF-8";
59+
60+    /**
61+     * Content type to use when transmitting the body data.
62+     */
63+    private static final String CONTENT_TYPE = "text/xml; charset=utf-8";
64+
65+    ///////////////////////////////////////////////////////////////////////////
66+    // Class variables:
67+
68+    /**
69+     * Lock used for internal synchronization.
70+     */
71+    private final Lock lock = new ReentrantLock();
72+
73+    /**
74+     * The execution state of an HTTP process.
75+     */
76+    private final HttpContext context;
77+
78+    /**
79+     * HttpClient instance to use to communicate.
80+     */
81+    private final HttpClient client;
82+
83+    /**
84+     * The HTTP POST request is sent to the server.
85+     */
86+    private final HttpPost post;
87+
88+    /**
89+     * A flag which indicates if the transmission was already done.
90+     */
91+    private boolean sent;
92+
93+    /**
94+     * Exception to throw when the response data is attempted to be accessed,
95+     * or {@code null} if no exception should be thrown.
96+     */
97+    private BOSHException toThrow;
98+
99+    /**
100+     * The response body which was received from the server or {@code null}
101+     * if that has not yet happened.
102+     */
103+    private AbstractBody body;
104+
105+    /**
106+     * The HTTP response status code.
107+     */
108+    private int statusCode;
109+
110+    ///////////////////////////////////////////////////////////////////////////
111+    // Constructors:
112+
113+    /**
114+     * Create and send a new request to the upstream connection manager,
115+     * providing deferred access to the results to be returned.
116+     *
117+     * @param client client instance to use when sending the request
118+     * @param cfg client configuration
119+     * @param params connection manager parameters from the session creation
120+     *  response, or {@code null} if the session has not yet been established
121+     * @param request body of the client request
122+     */
123+    ApacheHTTPResponse(
124+            final HttpClient client,
125+            final BOSHClientConfig cfg,
126+            final CMSessionParams params,
127+            final AbstractBody request) {
128+        super();
129+        this.client = client;
130+        this.context = new BasicHttpContext();
131+        this.post = new HttpPost(cfg.getURI().toString());
132+        this.sent = false;
133+
134+        try {
135+            String xml = request.toXML();
136+            byte[] data = xml.getBytes(CHARSET);
137+
138+            String encoding = null;
139+            if (cfg.isCompressionEnabled() && params != null) {
140+                AttrAccept accept = params.getAccept();
141+                if (accept != null) {
142+                    if (accept.isAccepted(ZLIBCodec.getID())) {
143+                        encoding = ZLIBCodec.getID();
144+                        data = ZLIBCodec.encode(data);
145+                    } else if (accept.isAccepted(GZIPCodec.getID())) {
146+                        encoding = GZIPCodec.getID();
147+                        data = GZIPCodec.encode(data);
148+                    }
149+                }
150+            }
151+
152+            ByteArrayEntity entity = new ByteArrayEntity(data);
153+            entity.setContentType(CONTENT_TYPE);
154+            if (encoding != null) {
155+                entity.setContentEncoding(encoding);
156+            }
157+            post.setEntity(entity);
158+            if (cfg.isCompressionEnabled()) {
159+                post.setHeader(ACCEPT_ENCODING, ACCEPT_ENCODING_VAL);
160+            }
161+        } catch (Exception e) {
162+            toThrow = new BOSHException("Could not generate request", e);
163+        }
164+    }
165+
166+    ///////////////////////////////////////////////////////////////////////////
167+    // HTTPResponse interface methods:
168+
169+    /**
170+     * Abort the client transmission and response processing.
171+     */
172+    public void abort() {
173+        if (post != null) {
174+            post.abort();
175+            toThrow = new BOSHException("HTTP request aborted");
176+        }
177+    }
178+
179+    /**
180+     * Wait for and then return the response body.
181+     *
182+     * @return body of the response
183+     * @throws InterruptedException if interrupted while awaiting the response
184+     * @throws BOSHException on communication failure
185+     */
186+    public AbstractBody getBody() throws InterruptedException, BOSHException {
187+        if (toThrow != null) {
188+            throw(toThrow);
189+        }
190+        lock.lock();
191+        try {
192+            if (!sent) {
193+                awaitResponse();
194+            }
195+        } finally {
196+            lock.unlock();
197+        }
198+        return body;
199+    }
200+
201+    /**
202+     * Wait for and then return the response HTTP status code.
203+     *
204+     * @return HTTP status code of the response
205+     * @throws InterruptedException if interrupted while awaiting the response
206+     * @throws BOSHException on communication failure
207+     */
208+    public int getHTTPStatus() throws InterruptedException, BOSHException {
209+        if (toThrow != null) {
210+            throw(toThrow);
211+        }
212+        lock.lock();
213+        try {
214+            if (!sent) {
215+                awaitResponse();
216+            }
217+        } finally {
218+            lock.unlock();
219+        }
220+        return statusCode;
221+    }
222+
223+    ///////////////////////////////////////////////////////////////////////////
224+    // Package-private methods:
225+
226+    /**
227+     * Await the response, storing the result in the instance variables of
228+     * this class when they arrive.
229+     *
230+     * @throws InterruptedException if interrupted while awaiting the response
231+     * @throws BOSHException on communication failure
232+     */
233+    private synchronized void awaitResponse() throws BOSHException {
234+        HttpEntity entity = null;
235+        try {
236+            HttpResponse httpResp = client.execute(post, context);
237+            entity = httpResp.getEntity();
238+            byte[] data = EntityUtils.toByteArray(entity);
239+            String encoding = entity.getContentEncoding() != null ?
240+                    entity.getContentEncoding().getValue() :
241+                    null;
242+            if (ZLIBCodec.getID().equalsIgnoreCase(encoding)) {
243+                data = ZLIBCodec.decode(data);
244+            } else if (GZIPCodec.getID().equalsIgnoreCase(encoding)) {
245+                data = GZIPCodec.decode(data);
246+            }
247+            body = StaticBody.fromString(new String(data, CHARSET));
248+            statusCode = httpResp.getStatusLine().getStatusCode();
249+            sent = true;
250+        } catch (IOException iox) {
251+            abort();
252+            toThrow = new BOSHException("Could not obtain response", iox);
253+            throw(toThrow);
254+        } catch (RuntimeException ex) {
255+            abort();
256+            throw(ex);
257+        }
258+    }
259+}
260diff --git com/kenai/jbosh/ApacheHTTPSender.java com/kenai/jbosh/ApacheHTTPSender.java
261new file mode 100644
262index 0000000..2abb4ee
263--- /dev/null
264+++ com/kenai/jbosh/ApacheHTTPSender.java
265@@ -0,0 +1,156 @@
266+/*
267+ * Copyright 2009 Guenther Niess
268+ *
269+ * Licensed under the Apache License, Version 2.0 (the "License");
270+ * you may not use this file except in compliance with the License.
271+ * You may obtain a copy of the License at
272+ *
273+ *   http://www.apache.org/licenses/LICENSE-2.0
274+ *
275+ * Unless required by applicable law or agreed to in writing, software
276+ * distributed under the License is distributed on an "AS IS" BASIS,
277+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
278+ * See the License for the specific language governing permissions and
279+ * limitations under the License.
280+ */
281+
282+package com.kenai.jbosh;
283+
284+import java.util.concurrent.locks.Lock;
285+import java.util.concurrent.locks.ReentrantLock;
286+
287+import org.apache.http.HttpHost;
288+import org.apache.http.HttpVersion;
289+import org.apache.http.client.HttpClient;
290+import org.apache.http.conn.ClientConnectionManager;
291+import org.apache.http.conn.params.ConnManagerParams;
292+import org.apache.http.conn.params.ConnRoutePNames;
293+import org.apache.http.conn.scheme.PlainSocketFactory;
294+import org.apache.http.conn.scheme.Scheme;
295+import org.apache.http.conn.scheme.SchemeRegistry;
296+import org.apache.http.conn.ssl.SSLSocketFactory;
297+import org.apache.http.impl.client.DefaultHttpClient;
298+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
299+import org.apache.http.params.BasicHttpParams;
300+import org.apache.http.params.HttpParams;
301+import org.apache.http.params.HttpProtocolParams;
302+
303+/**
304+ * Implementation of the {@code HTTPSender} interface which uses the
305+ * Apache HttpClient API to send messages to the connection manager.
306+ */
307+final class ApacheHTTPSender implements HTTPSender {
308+
309+    /**
310+     * Lock used for internal synchronization.
311+     */
312+    private final Lock lock = new ReentrantLock();
313+
314+    /**
315+     * Session configuration.
316+     */
317+    private BOSHClientConfig cfg;
318+
319+    /**
320+     * HttpClient instance to use to communicate.
321+     */
322+    private HttpClient httpClient;
323+
324+    ///////////////////////////////////////////////////////////////////////////
325+    // Constructors:
326+
327+    /**
328+     * Prevent construction apart from our package.
329+     */
330+    ApacheHTTPSender() {
331+        // Load Apache HTTP client class
332+        HttpClient.class.getName();
333+    }
334+
335+    ///////////////////////////////////////////////////////////////////////////
336+    // HTTPSender interface methods:
337+
338+    /**
339+     * {@inheritDoc}
340+     */
341+    public void init(final BOSHClientConfig session) {
342+        lock.lock();
343+        try {
344+            cfg = session;
345+            httpClient = initHttpClient(session);
346+        } finally {
347+            lock.unlock();
348+        }
349+    }
350+
351+    /**
352+     * {@inheritDoc}
353+     */
354+    public void destroy() {
355+        lock.lock();
356+        try {
357+            if (httpClient != null) {
358+                httpClient.getConnectionManager().shutdown();
359+            }
360+        } finally {
361+            cfg = null;
362+            httpClient = null;
363+            lock.unlock();
364+        }
365+    }
366+
367+    /**
368+     * {@inheritDoc}
369+     */
370+    public HTTPResponse send(
371+            final CMSessionParams params,
372+            final AbstractBody body) {
373+        HttpClient mClient;
374+        BOSHClientConfig mCfg;
375+        lock.lock();
376+        try {
377+            if (httpClient == null) {
378+                httpClient = initHttpClient(cfg);
379+            }
380+            mClient = httpClient;
381+            mCfg = cfg;
382+        } finally {
383+            lock.unlock();
384+        }
385+        return new ApacheHTTPResponse(mClient, mCfg, params, body);
386+    }
387+
388+    ///////////////////////////////////////////////////////////////////////////
389+    // Package-private methods:
390+
391+    private synchronized HttpClient initHttpClient(final BOSHClientConfig config) {
392+        // Create and initialize HTTP parameters
393+        HttpParams params = new BasicHttpParams();
394+        ConnManagerParams.setMaxTotalConnections(params, 100);
395+        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
396+        HttpProtocolParams.setUseExpectContinue(params, false);
397+        if (config != null &&
398+                config.getProxyHost() != null &&
399+                config.getProxyPort() != 0) {
400+            HttpHost proxy = new HttpHost(
401+                    config.getProxyHost(),
402+                    config.getProxyPort());
403+            params.setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
404+        }
405+
406+        // Create and initialize scheme registry
407+        SchemeRegistry schemeRegistry = new SchemeRegistry();
408+        schemeRegistry.register(
409+                new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
410+            SSLSocketFactory sslFactory = SSLSocketFactory.getSocketFactory();
411+            sslFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
412+            schemeRegistry.register(
413+                    new Scheme("https", sslFactory, 443));
414+
415+        // Create an HttpClient with the ThreadSafeClientConnManager.
416+        // This connection manager must be used if more than one thread will
417+        // be using the HttpClient.
418+        ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
419+        return new DefaultHttpClient(cm, params);
420+    }
421+}
422diff --git com/kenai/jbosh/BodyParserXmlPull.java com/kenai/jbosh/BodyParserXmlPull.java
423index cc95236..5f23b06 100644
424--- com/kenai/jbosh/BodyParserXmlPull.java
425+++ com/kenai/jbosh/BodyParserXmlPull.java
426@@ -22,7 +22,6 @@ import java.lang.ref.SoftReference;
427 import java.util.logging.Level;
428 import java.util.logging.Logger;
429 import javax.xml.XMLConstants;
430-import javax.xml.namespace.QName;
431 import org.xmlpull.v1.XmlPullParser;
432 import org.xmlpull.v1.XmlPullParserException;
433 import org.xmlpull.v1.XmlPullParserFactory;
434diff --git com/kenai/jbosh/BodyQName.java com/kenai/jbosh/BodyQName.java
435index fc7ab0c..83acdf1 100644
436--- com/kenai/jbosh/BodyQName.java
437+++ com/kenai/jbosh/BodyQName.java
438@@ -16,8 +16,6 @@
439
440 package com.kenai.jbosh;
441
442-import javax.xml.namespace.QName;
443-
444 /**
445  * Qualified name of an attribute of the wrapper element.  This class is
446  * analagous to the {@code javax.xml.namespace.QName} class.
447