Home | History | Annotate | Download | only in jbosh
      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          */
    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 }
    447