blob: 23915b6cc4e8946ba612c84692215283f0c30c3b [file] [log] [blame]
/*
* Copyright 2009 Mike Cumings
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kenai.jbosh;
import java.net.URI;
import javax.net.ssl.SSLContext;
/**
* BOSH client configuration information. Instances of this class contain
* all information necessary to establish connectivity with a remote
* connection manager.
* <p/>
* Instances of this class are immutable, thread-safe,
* and can be re-used to configure multiple client session instances.
*/
public final class BOSHClientConfig {
/**
* Connection manager URI.
*/
private final URI uri;
/**
* Target domain.
*/
private final String to;
/**
* Client ID of this station.
*/
private final String from;
/**
* Default XML language.
*/
private final String lang;
/**
* Routing information for messages sent to CM.
*/
private final String route;
/**
* Proxy host.
*/
private final String proxyHost;
/**
* Proxy port.
*/
private final int proxyPort;
/**
* SSL context.
*/
private final SSLContext sslContext;
/**
* Flag indicating that compression should be attempted, if possible.
*/
private final boolean compressionEnabled;
///////////////////////////////////////////////////////////////////////////
// Classes:
/**
* Class instance builder, after the builder pattern. This allows each
* {@code BOSHClientConfig} instance to be immutable while providing
* flexibility when building new {@code BOSHClientConfig} instances.
* <p/>
* Instances of this class are <b>not</b> thread-safe. If template-style
* use is desired, see the {@code create(BOSHClientConfig)} method.
*/
public static final class Builder {
// Required args
private final URI bURI;
private final String bDomain;
// Optional args
private String bFrom;
private String bLang;
private String bRoute;
private String bProxyHost;
private int bProxyPort;
private SSLContext bSSLContext;
private Boolean bCompression;
/**
* Creates a new builder instance, used to create instances of the
* {@code BOSHClientConfig} class.
*
* @param cmURI URI to use to contact the connection manager
* @param domain target domain to communicate with
*/
private Builder(final URI cmURI, final String domain) {
bURI = cmURI;
bDomain = domain;
}
/**
* Creates a new builder instance, used to create instances of the
* {@code BOSHClientConfig} class.
*
* @param cmURI URI to use to contact the connection manager
* @param domain target domain to communicate with
* @return builder instance
*/
public static Builder create(final URI cmURI, final String domain) {
if (cmURI == null) {
throw(new IllegalArgumentException(
"Connection manager URI must not be null"));
}
if (domain == null) {
throw(new IllegalArgumentException(
"Target domain must not be null"));
}
String scheme = cmURI.getScheme();
if (!("http".equals(scheme) || "https".equals(scheme))) {
throw(new IllegalArgumentException(
"Only 'http' and 'https' URI are allowed"));
}
return new Builder(cmURI, domain);
}
/**
* Creates a new builder instance using the existing configuration
* provided as a starting point.
*
* @param cfg configuration to copy
* @return builder instance
*/
public static Builder create(final BOSHClientConfig cfg) {
Builder result = new Builder(cfg.getURI(), cfg.getTo());
result.bFrom = cfg.getFrom();
result.bLang = cfg.getLang();
result.bRoute = cfg.getRoute();
result.bProxyHost = cfg.getProxyHost();
result.bProxyPort = cfg.getProxyPort();
result.bSSLContext = cfg.getSSLContext();
result.bCompression = cfg.isCompressionEnabled();
return result;
}
/**
* Set the ID of the client station, to be forwarded to the connection
* manager when new sessions are created.
*
* @param id client ID
* @return builder instance
*/
public Builder setFrom(final String id) {
if (id == null) {
throw(new IllegalArgumentException(
"Client ID must not be null"));
}
bFrom = id;
return this;
}
/**
* Set the default language of any human-readable content within the
* XML.
*
* @param lang XML language ID
* @return builder instance
*/
public Builder setXMLLang(final String lang) {
if (lang == null) {
throw(new IllegalArgumentException(
"Default language ID must not be null"));
}
bLang = lang;
return this;
}
/**
* Sets the destination server/domain that the client should connect to.
* Connection managers may be configured to enable sessions with more
* that one server in different domains. When requesting a session with
* such a "proxy" connection manager, a client should use this method to
* specify the server with which it wants to communicate.
*
* @param protocol connection protocol (e.g, "xmpp")
* @param host host or domain to be served by the remote server. Note
* that this is not necessarily the host name or domain name of the
* remote server.
* @param port port number of the remote server
* @return builder instance
*/
public Builder setRoute(
final String protocol,
final String host,
final int port) {
if (protocol == null) {
throw(new IllegalArgumentException("Protocol cannot be null"));
}
if (protocol.contains(":")) {
throw(new IllegalArgumentException(
"Protocol cannot contain the ':' character"));
}
if (host == null) {
throw(new IllegalArgumentException("Host cannot be null"));
}
if (host.contains(":")) {
throw(new IllegalArgumentException(
"Host cannot contain the ':' character"));
}
if (port <= 0) {
throw(new IllegalArgumentException("Port number must be > 0"));
}
bRoute = protocol + ":" + host + ":" + port;
return this;
}
/**
* Specify the hostname and port of an HTTP proxy to connect through.
*
* @param hostName proxy hostname
* @param port proxy port number
* @return builder instance
*/
public Builder setProxy(final String hostName, final int port) {
if (hostName == null || hostName.length() == 0) {
throw(new IllegalArgumentException(
"Proxy host name cannot be null or empty"));
}
if (port <= 0) {
throw(new IllegalArgumentException(
"Proxy port must be > 0"));
}
bProxyHost = hostName;
bProxyPort = port;
return this;
}
/**
* Set the SSL context to use for this session. This can be used
* to configure certificate-based authentication, etc..
*
* @param ctx SSL context
* @return builder instance
*/
public Builder setSSLContext(final SSLContext ctx) {
if (ctx == null) {
throw(new IllegalArgumentException(
"SSL context cannot be null"));
}
bSSLContext = ctx;
return this;
}
/**
* Set whether or not compression of the underlying data stream
* should be attempted. By default, compression is disabled.
*
* @param enabled set to {@code true} if compression should be
* attempted when possible, {@code false} to disable compression
* @return builder instance
*/
public Builder setCompressionEnabled(final boolean enabled) {
bCompression = Boolean.valueOf(enabled);
return this;
}
/**
* Build the immutable object instance with the current configuration.
*
* @return BOSHClientConfig instance
*/
public BOSHClientConfig build() {
// Default XML language
String lang;
if (bLang == null) {
lang = "en";
} else {
lang = bLang;
}
// Default proxy port
int port;
if (bProxyHost == null) {
port = 0;
} else {
port = bProxyPort;
}
// Default compression
boolean compression;
if (bCompression == null) {
compression = false;
} else {
compression = bCompression.booleanValue();
}
return new BOSHClientConfig(
bURI,
bDomain,
bFrom,
lang,
bRoute,
bProxyHost,
port,
bSSLContext,
compression);
}
}
///////////////////////////////////////////////////////////////////////////
// Constructor:
/**
* Prevent direct construction.
*
* @param cURI URI of the connection manager to connect to
* @param cDomain the target domain of the first stream
* @param cFrom client ID
* @param cLang default XML language
* @param cRoute target route
* @param cProxyHost proxy host
* @param cProxyPort proxy port
* @param cSSLContext SSL context
* @param cCompression compression enabled flag
*/
private 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) {
uri = cURI;
to = cDomain;
from = cFrom;
lang = cLang;
route = cRoute;
proxyHost = cProxyHost;
proxyPort = cProxyPort;
sslContext = cSSLContext;
compressionEnabled = cCompression;
}
/**
* Get the URI to use to contact the connection manager.
*
* @return connection manager URI.
*/
public URI getURI() {
return uri;
}
/**
* Get the ID of the target domain.
*
* @return domain id
*/
public String getTo() {
return to;
}
/**
* Get the ID of the local client.
*
* @return client id, or {@code null}
*/
public String getFrom() {
return from;
}
/**
* Get the default language of any human-readable content within the
* XML. Defaults to "en".
*
* @return XML language ID
*/
public String getLang() {
return lang;
}
/**
* Get the routing information for messages sent to the CM.
*
* @return route attribute string, or {@code null} if no routing
* info was provided.
*/
public String getRoute() {
return route;
}
/**
* Get the HTTP proxy host to use.
*
* @return proxy host, or {@code null} if no proxy information was specified
*/
public String getProxyHost() {
return proxyHost;
}
/**
* Get the HTTP proxy port to use.
*
* @return proxy port, or 0 if no proxy information was specified
*/
public int getProxyPort() {
return proxyPort;
}
/**
* Get the SSL context to use for this session.
*
* @return SSL context instance to use, or {@code null} if no
* context instance was provided.
*/
public SSLContext getSSLContext() {
return sslContext;
}
/**
* Determines whether or not compression of the underlying data stream
* should be attempted/allowed. Defaults to {@code false}.
*
* @return {@code true} if compression should be attempted, {@code false}
* if compression is disabled or was not specified
*/
boolean isCompressionEnabled() {
return compressionEnabled;
}
}