• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009 Mike Cumings
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.kenai.jbosh;
18 
19 import java.net.URI;
20 import javax.net.ssl.SSLContext;
21 
22 /**
23  * BOSH client configuration information.  Instances of this class contain
24  * all information necessary to establish connectivity with a remote
25  * connection manager.
26  * <p/>
27  * Instances of this class are immutable, thread-safe,
28  * and can be re-used to configure multiple client session instances.
29  */
30 public final class BOSHClientConfig {
31 
32     /**
33      * Connection manager URI.
34      */
35     private final URI uri;
36 
37     /**
38      * Target domain.
39      */
40     private final String to;
41 
42     /**
43      * Client ID of this station.
44      */
45     private final String from;
46 
47     /**
48      * Default XML language.
49      */
50     private final String lang;
51 
52     /**
53      * Routing information for messages sent to CM.
54      */
55     private final String route;
56 
57     /**
58      * Proxy host.
59      */
60     private final String proxyHost;
61 
62     /**
63      * Proxy port.
64      */
65     private final int proxyPort;
66 
67     /**
68      * SSL context.
69      */
70     private final SSLContext sslContext;
71 
72     /**
73      * Flag indicating that compression should be attempted, if possible.
74      */
75     private final boolean compressionEnabled;
76 
77     ///////////////////////////////////////////////////////////////////////////
78     // Classes:
79 
80     /**
81      * Class instance builder, after the builder pattern.  This allows each
82      * {@code BOSHClientConfig} instance to be immutable while providing
83      * flexibility when building new {@code BOSHClientConfig} instances.
84      * <p/>
85      * Instances of this class are <b>not</b> thread-safe.  If template-style
86      * use is desired, see the {@code create(BOSHClientConfig)} method.
87      */
88     public static final class Builder {
89         // Required args
90         private final URI bURI;
91         private final String bDomain;
92 
93         // Optional args
94         private String bFrom;
95         private String bLang;
96         private String bRoute;
97         private String bProxyHost;
98         private int bProxyPort;
99         private SSLContext bSSLContext;
100         private Boolean bCompression;
101 
102         /**
103          * Creates a new builder instance, used to create instances of the
104          * {@code BOSHClientConfig} class.
105          *
106          * @param cmURI URI to use to contact the connection manager
107          * @param domain target domain to communicate with
108          */
Builder(final URI cmURI, final String domain)109         private Builder(final URI cmURI, final String domain) {
110             bURI = cmURI;
111             bDomain = domain;
112         }
113 
114         /**
115          * Creates a new builder instance, used to create instances of the
116          * {@code BOSHClientConfig} class.
117          *
118          * @param cmURI URI to use to contact the connection manager
119          * @param domain target domain to communicate with
120          * @return builder instance
121          */
create(final URI cmURI, final String domain)122         public static Builder create(final URI cmURI, final String domain) {
123             if (cmURI == null) {
124                 throw(new IllegalArgumentException(
125                         "Connection manager URI must not be null"));
126             }
127             if (domain == null) {
128                 throw(new IllegalArgumentException(
129                         "Target domain must not be null"));
130             }
131             String scheme = cmURI.getScheme();
132             if (!("http".equals(scheme) || "https".equals(scheme))) {
133                 throw(new IllegalArgumentException(
134                         "Only 'http' and 'https' URI are allowed"));
135             }
136             return new Builder(cmURI, domain);
137         }
138 
139         /**
140          * Creates a new builder instance using the existing configuration
141          * provided as a starting point.
142          *
143          * @param cfg configuration to copy
144          * @return builder instance
145          */
create(final BOSHClientConfig cfg)146         public static Builder create(final BOSHClientConfig cfg) {
147             Builder result = new Builder(cfg.getURI(), cfg.getTo());
148             result.bFrom = cfg.getFrom();
149             result.bLang = cfg.getLang();
150             result.bRoute = cfg.getRoute();
151             result.bProxyHost = cfg.getProxyHost();
152             result.bProxyPort = cfg.getProxyPort();
153             result.bSSLContext = cfg.getSSLContext();
154             result.bCompression = cfg.isCompressionEnabled();
155             return result;
156         }
157 
158         /**
159          * Set the ID of the client station, to be forwarded to the connection
160          * manager when new sessions are created.
161          *
162          * @param id client ID
163          * @return builder instance
164          */
setFrom(final String id)165         public Builder setFrom(final String id) {
166             if (id == null) {
167                 throw(new IllegalArgumentException(
168                         "Client ID must not be null"));
169             }
170             bFrom = id;
171             return this;
172         }
173 
174         /**
175          * Set the default language of any human-readable content within the
176          * XML.
177          *
178          * @param lang XML language ID
179          * @return builder instance
180          */
setXMLLang(final String lang)181         public Builder setXMLLang(final String lang) {
182             if (lang == null) {
183                 throw(new IllegalArgumentException(
184                         "Default language ID must not be null"));
185             }
186             bLang = lang;
187             return this;
188         }
189 
190         /**
191          * Sets the destination server/domain that the client should connect to.
192          * Connection managers may be configured to enable sessions with more
193          * that one server in different domains.  When requesting a session with
194          * such a "proxy" connection manager, a client should use this method to
195          * specify the server with which it wants to communicate.
196          *
197          * @param protocol connection protocol (e.g, "xmpp")
198          * @param host host or domain to be served by the remote server.  Note
199          *  that this is not necessarily the host name or domain name of the
200          *  remote server.
201          * @param port port number of the remote server
202          * @return builder instance
203          */
setRoute( final String protocol, final String host, final int port)204         public Builder setRoute(
205                 final String protocol,
206                 final String host,
207                 final int port) {
208             if (protocol == null) {
209                 throw(new IllegalArgumentException("Protocol cannot be null"));
210             }
211             if (protocol.contains(":")) {
212                 throw(new IllegalArgumentException(
213                         "Protocol cannot contain the ':' character"));
214             }
215             if (host == null) {
216                 throw(new IllegalArgumentException("Host cannot be null"));
217             }
218             if (host.contains(":")) {
219                 throw(new IllegalArgumentException(
220                         "Host cannot contain the ':' character"));
221             }
222             if (port <= 0) {
223                 throw(new IllegalArgumentException("Port number must be > 0"));
224             }
225             bRoute = protocol + ":" + host + ":" + port;
226             return this;
227         }
228 
229         /**
230          * Specify the hostname and port of an HTTP proxy to connect through.
231          *
232          * @param hostName proxy hostname
233          * @param port proxy port number
234          * @return builder instance
235          */
setProxy(final String hostName, final int port)236         public Builder setProxy(final String hostName, final int port) {
237             if (hostName == null || hostName.length() == 0) {
238                 throw(new IllegalArgumentException(
239                         "Proxy host name cannot be null or empty"));
240             }
241             if (port <= 0) {
242                 throw(new IllegalArgumentException(
243                         "Proxy port must be > 0"));
244             }
245             bProxyHost = hostName;
246             bProxyPort = port;
247             return this;
248         }
249 
250         /**
251          * Set the SSL context to use for this session.  This can be used
252          * to configure certificate-based authentication, etc..
253          *
254          * @param ctx SSL context
255          * @return builder instance
256          */
setSSLContext(final SSLContext ctx)257         public Builder setSSLContext(final SSLContext ctx) {
258             if (ctx == null) {
259                 throw(new IllegalArgumentException(
260                         "SSL context cannot be null"));
261             }
262             bSSLContext = ctx;
263             return this;
264         }
265 
266         /**
267          * Set whether or not compression of the underlying data stream
268          * should be attempted.  By default, compression is disabled.
269          *
270          * @param enabled set to {@code true} if compression should be
271          *  attempted when possible, {@code false} to disable compression
272          * @return builder instance
273          */
setCompressionEnabled(final boolean enabled)274         public Builder setCompressionEnabled(final boolean enabled) {
275             bCompression = Boolean.valueOf(enabled);
276             return this;
277         }
278 
279         /**
280          * Build the immutable object instance with the current configuration.
281          *
282          * @return BOSHClientConfig instance
283          */
build()284         public BOSHClientConfig build() {
285             // Default XML language
286             String lang;
287             if (bLang == null) {
288                 lang = "en";
289             } else {
290                 lang = bLang;
291             }
292 
293             // Default proxy port
294             int port;
295             if (bProxyHost == null) {
296                 port = 0;
297             } else {
298                 port = bProxyPort;
299             }
300 
301             // Default compression
302             boolean compression;
303             if (bCompression == null) {
304                 compression = false;
305             } else {
306                 compression = bCompression.booleanValue();
307             }
308 
309             return new BOSHClientConfig(
310                     bURI,
311                     bDomain,
312                     bFrom,
313                     lang,
314                     bRoute,
315                     bProxyHost,
316                     port,
317                     bSSLContext,
318                     compression);
319         }
320 
321     }
322 
323     ///////////////////////////////////////////////////////////////////////////
324     // Constructor:
325 
326     /**
327      * Prevent direct construction.
328      *
329      * @param cURI URI of the connection manager to connect to
330      * @param cDomain the target domain of the first stream
331      * @param cFrom client ID
332      * @param cLang default XML language
333      * @param cRoute target route
334      * @param cProxyHost proxy host
335      * @param cProxyPort proxy port
336      * @param cSSLContext SSL context
337      * @param cCompression compression enabled flag
338      */
BOSHClientConfig( final URI cURI, final String cDomain, final String cFrom, final String cLang, final String cRoute, final String cProxyHost, final int cProxyPort, final SSLContext cSSLContext, final boolean cCompression)339     private BOSHClientConfig(
340             final URI cURI,
341             final String cDomain,
342             final String cFrom,
343             final String cLang,
344             final String cRoute,
345             final String cProxyHost,
346             final int cProxyPort,
347             final SSLContext cSSLContext,
348             final boolean cCompression) {
349         uri = cURI;
350         to = cDomain;
351         from = cFrom;
352         lang = cLang;
353         route = cRoute;
354         proxyHost = cProxyHost;
355         proxyPort = cProxyPort;
356         sslContext = cSSLContext;
357         compressionEnabled = cCompression;
358     }
359 
360     /**
361      * Get the URI to use to contact the connection manager.
362      *
363      * @return connection manager URI.
364      */
getURI()365     public URI getURI() {
366         return uri;
367     }
368 
369     /**
370      * Get the ID of the target domain.
371      *
372      * @return domain id
373      */
getTo()374     public String getTo() {
375         return to;
376     }
377 
378     /**
379      * Get the ID of the local client.
380      *
381      * @return client id, or {@code null}
382      */
getFrom()383     public String getFrom() {
384         return from;
385     }
386 
387     /**
388      * Get the default language of any human-readable content within the
389      * XML.  Defaults to "en".
390      *
391      * @return XML language ID
392      */
getLang()393     public String getLang() {
394         return lang;
395     }
396 
397     /**
398      * Get the routing information for messages sent to the CM.
399      *
400      * @return route attribute string, or {@code null} if no routing
401      *  info was provided.
402      */
getRoute()403     public String getRoute() {
404         return route;
405     }
406 
407     /**
408      * Get the HTTP proxy host to use.
409      *
410      * @return proxy host, or {@code null} if no proxy information was specified
411      */
getProxyHost()412     public String getProxyHost() {
413         return proxyHost;
414     }
415 
416     /**
417      * Get the HTTP proxy port to use.
418      *
419      * @return proxy port, or 0 if no proxy information was specified
420      */
getProxyPort()421     public int getProxyPort() {
422         return proxyPort;
423     }
424 
425     /**
426      * Get the SSL context to use for this session.
427      *
428      * @return SSL context instance to use, or {@code null} if no
429      *  context instance was provided.
430      */
getSSLContext()431     public SSLContext getSSLContext() {
432         return sslContext;
433     }
434 
435     /**
436      * Determines whether or not compression of the underlying data stream
437      * should be attempted/allowed.  Defaults to {@code false}.
438      *
439      * @return {@code true} if compression should be attempted, {@code false}
440      *  if compression is disabled or was not specified
441      */
isCompressionEnabled()442     boolean isCompressionEnabled() {
443         return compressionEnabled;
444     }
445 
446 }
447