blob: 23915b6cc4e8946ba612c84692215283f0c30c3b [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001/*
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
17package com.kenai.jbosh;
18
19import java.net.URI;
20import 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 */
30public 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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
365 public URI getURI() {
366 return uri;
367 }
368
369 /**
370 * Get the ID of the target domain.
371 *
372 * @return domain id
373 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
442 boolean isCompressionEnabled() {
443 return compressionEnabled;
444 }
445
446}