Apply builder pattern to ConnectionConfiguration

Introducing a clean split between the constant connection configuration
parameters, which are now all in ConnectionConfiguration and the dynamic
connection state (e.g. hostAddresses) which are now in
AbstractXMPPConnection.

Also removed all arguments of login() since the username, password,
resource and callback handler need now to be configured via
ConnectionConfiguration.

Also remove documentation/extensions/messageevents.md, as it's already
in documentation/legacy
This commit is contained in:
Florian Schmaus 2014-11-09 18:30:16 +01:00
parent 69f387b344
commit c81cd34561
24 changed files with 760 additions and 708 deletions

View File

@ -28,18 +28,21 @@ Connect and Disconnect
----------------------
```
// Create the configuration for this new connection_
ConnectionConfiguration config = new ConnectionConfiguration("jabber.org", 5222);
// Create the configuration for this new connection
XMPPTCPConnectionConfigurationBuilder configBuilder = XMPPTCPConnectionConfiguration.builder();
configBuilder.setUsernameAndPassword("username", "password");
configBuilder.setResource("SomeResource");
configBuilder.setServiceName("jabber.org");
AbstractXMPPConnection connection = new XMPPTCPConnection(config);
// Connect to the server_
AbstractXMPPConnection connection = new XMPPTCPConnection(configBuilder.build());
// Connect to the server
connection.connect();
// Log into the server_
connection.login("username", "password", "SomeResource");
// Log into the server
connection.login();
...
// Disconnect from the server_
// Disconnect from the server
connection.disconnect();
```

View File

@ -34,9 +34,7 @@ receive the roster entries.
In this example we can see how user1 sends his roster to user2.
```
// Connect to the server and log in
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
XMPPConnection conn1 = …
// Create a new roster exchange manager on conn1
RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1);
@ -64,9 +62,7 @@ the id of the user that will receive the roster entries.
In this example we can see how user1 sends his roster groups to user2.
```
// Connect to the server and log in
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
XMPPConnection conn1 = …
// Create a new roster exchange manager on conn1
RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1);
@ -95,9 +91,7 @@ the id of the user that will receive the roster entries.
In this example we can see how user1 sends a roster entry to user2.
```
// Connect to the server and log in
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
XMPPConnection conn1 = …
// Create a new roster exchange manager on conn1
RosterExchangeManager rosterExchangeManager = new RosterExchangeManager(conn1);
@ -127,10 +121,9 @@ adds the received entries to his roster.
```
// Connect to the server and log in the users
conn1 = new XMPPConnection(host);
conn1.login(server_user1, pass1);
conn2 = new XMPPConnection(host);
conn2.login(server_user2, pass2);
XMPPConnection conn1 = …
XMPPConnection conn2 = …
final Roster user2_roster = conn2.getRoster();
// Create a RosterExchangeManager that will help user2 to listen and accept

View File

@ -44,13 +44,19 @@ The `XMPPTCPConnection` class is used to create a connection to an XMPP
server. Below are code examples for making a connection:
```
// Create a connection to the jabber.org server._
XMPPConnection conn1 = **new** XMPPTCPConnection("jabber.org");
// Create a connection to the jabber.org server.
AbstractXMPPConnection conn1 = **new** XMPPTCPConnection("username", "password" "jabber.org");
conn1.connect();
// Create a connection to the jabber.org server on a specific port._
ConnectionConfiguration config = new ConnectionConfiguration("jabber.org", 5222);
XMPPConnection conn2 = **new** XMPPTCPConnection(config);
// Create a connection to the jabber.org server on a specific port.
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setUsernameAndPassword("username", "password")
.setServiceName("jabber.org")
.setHost("earl.jabber.org")
.setPort("8222")
.build();
AbstractXMPPConnection conn2 = **new** XMPPTCPConnection(config);
conn2.connect();
```
@ -60,10 +66,10 @@ ConnectionConfiguration class provides advanced control over the connection
created, such as the ability to disable or require encryption. See
[XMPPConnection Management](connections.html) for full details.
Once you've created a connection, you should login using a username and
password with the `XMPPConnection.login(String username, String password)`
method. Once you've logged in, you can being chatting with other users by
creating new `Chat` or `GroupChat` objects.
Once you've created a connection, you should login with the
`XMPPConnection.login()` method. Once you've logged in, you can being
chatting with other users by creating new `Chat` or `GroupChat`
objects.
Working with the Roster
----------------------

View File

@ -12,9 +12,9 @@ Smack Key Advantages
* Extremely simple to use, yet powerful API. Sending a text message to a user can be accomplished in only a few lines of code:
```java
AbstractXMPPConnection connection = new XMPPTCPConnection("jabber.org");
AbstractXMPPConnection connection = new XMPPTCPConnection("mtucker", "password", "jabber.org");
connection.connect();
connection.login("mtucker", "password");
connection.login();
Chat chat = ChatManager.getInstanceFor(connection)
.createChat("jsmith@jivesoftware.com", new MessageListener() {

View File

@ -22,7 +22,6 @@ import java.net.URISyntaxException;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.proxy.ProxyInfo;
import org.jivesoftware.smack.util.dns.HostAddress;
/**
* Configuration to use while establishing the connection to the XMPP server via
@ -33,60 +32,17 @@ import org.jivesoftware.smack.util.dns.HostAddress;
*/
public class BOSHConfiguration extends ConnectionConfiguration {
private boolean ssl;
private String file;
private final boolean https;
private final String file;
public BOSHConfiguration(String xmppDomain) {
super(xmppDomain, 7070);
ssl = false;
file = "/http-bind/";
}
public BOSHConfiguration(String xmppDomain, int port) {
super(xmppDomain, port);
ssl = false;
file = "/http-bind/";
}
/**
* Create a HTTP Binding configuration.
*
* @param https true if you want to use SSL
* (e.g. false for http://domain.lt:7070/http-bind).
* @param host the hostname or IP address of the connection manager
* (e.g. domain.lt for http://domain.lt:7070/http-bind).
* @param port the port of the connection manager
* (e.g. 7070 for http://domain.lt:7070/http-bind).
* @param filePath the file which is described by the URL
* (e.g. /http-bind for http://domain.lt:7070/http-bind).
* @param xmppDomain the XMPP service name
* (e.g. domain.lt for the user alice@domain.lt)
*/
public BOSHConfiguration(boolean https, String host, int port, String filePath, String xmppDomain) {
super(host, port, xmppDomain);
ssl = https;
file = (filePath != null ? filePath : "/");
}
/**
* Create a HTTP Binding configuration.
*
* @param https true if you want to use SSL
* (e.g. false for http://domain.lt:7070/http-bind).
* @param host the hostname or IP address of the connection manager
* (e.g. domain.lt for http://domain.lt:7070/http-bind).
* @param port the port of the connection manager
* (e.g. 7070 for http://domain.lt:7070/http-bind).
* @param filePath the file which is described by the URL
* (e.g. /http-bind for http://domain.lt:7070/http-bind).
* @param proxy the configuration of a proxy server.
* @param xmppDomain the XMPP service name
* (e.g. domain.lt for the user alice@domain.lt)
*/
public BOSHConfiguration(boolean https, String host, int port, String filePath, ProxyInfo proxy, String xmppDomain) {
super(host, port, xmppDomain, proxy);
ssl = https;
file = (filePath != null ? filePath : "/");
private BOSHConfiguration(BOSHConfigurationBuilder builder) {
super(builder);
https = builder.https;
if (builder.file.charAt(0) != '/') {
file = '/' + builder.file;
} else {
file = builder.file;
}
}
public boolean isProxyEnabled() {
@ -105,24 +61,47 @@ public class BOSHConfiguration extends ConnectionConfiguration {
return (proxy != null ? proxy.getProxyPort() : 8080);
}
public boolean isUsingSSL() {
return ssl;
public boolean isUsingHTTPS() {
return https;
}
public URI getURI() throws URISyntaxException {
if (file.charAt(0) != '/') {
file = '/' + file;
return new URI((https ? "https://" : "http://") + this.host + ":" + this.port + file);
}
public static BOSHConfigurationBuilder builder() {
return new BOSHConfigurationBuilder();
}
public static class BOSHConfigurationBuilder extends ConnectionConfigurationBuilder<BOSHConfigurationBuilder, BOSHConfiguration> {
private boolean https;
private String file;
private BOSHConfigurationBuilder() {
}
String host;
int port;
if (hostAddresses != null) {
HostAddress hostAddress = hostAddresses.get(0);
host = hostAddress.getFQDN();
port = hostAddress.getPort();
} else {
host = getServiceName();
port = 80;
public BOSHConfigurationBuilder setUseHttps(boolean useHttps) {
https = useHttps;
return this;
}
public BOSHConfigurationBuilder useHttps() {
return setUseHttps(true);
}
public BOSHConfigurationBuilder setFile(String file) {
this.file = file;
return this;
}
@Override
public BOSHConfiguration build() {
return new BOSHConfiguration(this);
}
@Override
protected BOSHConfigurationBuilder getThis() {
return this;
}
return new URI((ssl ? "https://" : "http://") + host + ":" + port + file);
}
}

View File

@ -21,7 +21,6 @@ import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.Writer;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -30,7 +29,6 @@ import javax.security.sasl.SaslException;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.AlreadyLoggedInException;
import org.jivesoftware.smack.SmackException.ConnectionException;
import org.jivesoftware.smack.SASLAuthentication;
import org.jivesoftware.smack.XMPPConnection;
@ -106,6 +104,8 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
/**
* Create a HTTP Binding connection to a XMPP server.
*
* @param username the username to use.
* @param password the password to use.
* @param https true if you want to use SSL
* (e.g. false for http://domain.lt:7070/http-bind).
* @param host the hostname or IP address of the connection manager
@ -117,9 +117,10 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
* @param xmppDomain the XMPP service name
* (e.g. domain.lt for the user alice@domain.lt)
*/
public XMPPBOSHConnection(boolean https, String host, int port, String filePath, String xmppDomain) {
super(new BOSHConfiguration(https, host, port, filePath, xmppDomain));
this.config = (BOSHConfiguration) getConfiguration();
public XMPPBOSHConnection(String username, String password, boolean https, String host, int port, String filePath, String xmppDomain) {
this(BOSHConfiguration.builder().setUseHttps(https).setHost(host)
.setPort(port).setFile(filePath).setServiceName(xmppDomain)
.setUsernameAndPassword(username, password).build());
}
/**
@ -134,9 +135,6 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
@Override
protected void connectInternal() throws SmackException {
if (connected) {
throw new IllegalStateException("Already connected to a server.");
}
done = false;
try {
// Ensure a clean starting state
@ -224,18 +222,12 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
return false;
}
public void login(String username, String password, String resource)
@Override
protected void loginNonAnonymously()
throws XMPPException, SmackException, IOException {
if (!isConnected()) {
throw new NotConnectedException();
}
if (authenticated) {
throw new AlreadyLoggedInException();
}
// Do partial version of nameprep on the username.
username = username.toLowerCase(Locale.US).trim();
String password = config.getPassword();
String resource = config.getResource();
String username = config.getUsername();
if (saslAuthentication.hasNonAnonymousAuthentication()) {
// Authenticate using SASL
if (password != null) {
@ -249,19 +241,11 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
bindResourceAndEstablishSession(resource);
// Stores the authentication for future reconnection
setLoginInfo(username, password, resource);
afterSuccessfulLogin(false, false);
afterSuccessfulLogin(false);
}
public void loginAnonymously() throws XMPPException, SmackException, IOException {
if (!isConnected()) {
throw new NotConnectedException();
}
if (authenticated) {
throw new AlreadyLoggedInException();
}
@Override
protected void loginAnonymously() throws XMPPException, SmackException, IOException {
// Wait with SASL auth until the SASL mechanisms have been received
saslFeatureReceived.checkIfSuccessOrWaitOrThrow();
@ -275,7 +259,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
bindResourceAndEstablishSession(null);
afterSuccessfulLogin(true, false);
afterSuccessfulLogin(false);
}
@Override
@ -313,7 +297,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
*/
@Override
protected void shutdown() {
setWasAuthenticated(authenticated);
setWasAuthenticated();
authID = null;
sessionID = null;
done = true;
@ -508,10 +492,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
else {
try {
if (wasAuthenticated) {
connection.login(
config.getUsername(),
config.getPassword(),
config.getResource());
connection.login();
}
for (ConnectionListener listener : getConnectionListeners()) {
listener.reconnectionSuccessful();

View File

@ -19,6 +19,7 @@ package org.jivesoftware.smack;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
@ -39,7 +40,10 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jivesoftware.smack.ConnectionConfiguration.ConnectionConfigurationBuilder;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.SmackException.AlreadyConnectedException;
import org.jivesoftware.smack.SmackException.AlreadyLoggedInException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.ConnectionException;
@ -66,7 +70,9 @@ import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.rosterstore.RosterStore;
import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smack.util.DNSUtil;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.dns.HostAddress;
import org.jxmpp.util.XmppStringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@ -255,8 +261,6 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
*/
protected boolean wasAuthenticated = false;
private boolean anonymous = false;
/**
* Create a new XMPPConnection to a XMPP server.
*
@ -272,6 +276,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@Override
public String getServiceName() {
if (serviceName != null) {
return serviceName;
}
return config.getServiceName();
}
@ -312,6 +319,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
* @throws ConnectionException with detailed information about the failed connection.
*/
public void connect() throws SmackException, IOException, XMPPException {
throwAlreadyConnectedExceptionIfAppropriate();
saslAuthentication.init();
saslFeatureReceived.init();
lastFeaturesReceived.init();
@ -340,64 +348,31 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
* Before logging in (i.e. authenticate) to the server the connection must be connected.
*
* It is possible to log in without sending an initial available presence by using
* {@link ConnectionConfiguration#setSendPresence(boolean)}. If this connection is
* {@link ConnectionConfigurationBuilder#setSendPresence(boolean)}. If this connection is
* not interested in loading its roster upon login then use
* {@link ConnectionConfiguration#setRosterLoadedAtLogin(boolean)}.
* {@link ConnectionConfigurationBuilder#setRosterLoadedAtLogin(boolean)}.
* Finally, if you want to not pass a password and instead use a more advanced mechanism
* while using SASL then you may be interested in using
* {@link ConnectionConfiguration#setCallbackHandler(javax.security.auth.callback.CallbackHandler)}.
* {@link ConnectionConfigurationBuilder#setCallbackHandler(javax.security.auth.callback.CallbackHandler)}.
* For more advanced login settings see {@link ConnectionConfiguration}.
*
* @param username the username.
* @param password the password or <tt>null</tt> if using a CallbackHandler.
* @throws XMPPException if an error occurs on the XMPP protocol level.
* @throws SmackException if an error occurs somehwere else besides XMPP protocol level.
* @throws IOException
*/
public void login(String username, String password) throws XMPPException, SmackException, IOException {
login(username, password, "Smack");
public void login() throws XMPPException, SmackException, IOException {
throwNotConnectedExceptionIfAppropriate();
throwAlreadyLoggedInExceptionIfAppropriate();
if (isAnonymous()) {
loginAnonymously();
} else {
loginNonAnonymously();
}
}
/**
* Logs in to the server using the strongest authentication mode supported by
* the server, then sets presence to available. If the server supports SASL authentication
* then the user will be authenticated using SASL if not Non-SASL authentication will
* be tried. If more than five seconds (default timeout) elapses in each step of the
* authentication process without a response from the server, or if an error occurs, a
* XMPPException will be thrown.<p>
*
* Before logging in (i.e. authenticate) to the server the connection must be connected.
*
* It is possible to log in without sending an initial available presence by using
* {@link ConnectionConfiguration#setSendPresence(boolean)}. If this connection is
* not interested in loading its roster upon login then use
* {@link ConnectionConfiguration#setRosterLoadedAtLogin(boolean)}.
* Finally, if you want to not pass a password and instead use a more advanced mechanism
* while using SASL then you may be interested in using
* {@link ConnectionConfiguration#setCallbackHandler(javax.security.auth.callback.CallbackHandler)}.
* For more advanced login settings see {@link ConnectionConfiguration}.
*
* @param username the username.
* @param password the password or <tt>null</tt> if using a CallbackHandler.
* @param resource the resource.
* @throws XMPPException if an error occurs on the XMPP protocol level.
* @throws SmackException if an error occurs somehwere else besides XMPP protocol level.
* @throws IOException
*/
public abstract void login(String username, String password, String resource) throws XMPPException, SmackException, IOException;
/**
* Logs in to the server anonymously. Very few servers are configured to support anonymous
* authentication, so it's fairly likely logging in anonymously will fail. If anonymous login
* does succeed, your XMPP address will likely be in the form "123ABC@server/789XYZ" or
* "server/123ABC" (where "123ABC" and "789XYZ" is a random value generated by the server).
*
* @throws XMPPException if an error occurs on the XMPP protocol level.
* @throws SmackException if an error occurs somehwere else besides XMPP protocol level.
* @throws IOException
*/
public abstract void loginAnonymously() throws XMPPException, SmackException, IOException;
protected abstract void loginNonAnonymously() throws XMPPException, SmackException, IOException;
protected abstract void loginAnonymously() throws XMPPException, SmackException, IOException;
@Override
public final boolean isConnected() {
@ -437,7 +412,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
PacketCollector packetCollector = createPacketCollectorAndSend(new PacketIDFilter(bindResource), bindResource);
Bind response = packetCollector.nextResultOrThrow();
user = response.getJid();
setServiceName(XmppStringUtils.parseDomain(user));
serviceName = XmppStringUtils.parseDomain(user);
if (hasFeature(Session.ELEMENT, Session.NAMESPACE) && !getConfiguration().isLegacySessionDisabled()) {
Session session = new Session();
@ -446,10 +421,9 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
}
}
protected void afterSuccessfulLogin(final boolean anonymous, final boolean resumed) throws NotConnectedException {
protected void afterSuccessfulLogin(final boolean resumed) throws NotConnectedException {
// Indicate that we're now authenticated.
this.authenticated = true;
this.anonymous = anonymous;
// If debugging is enabled, change the the debug window title to include the
// name we are now logged-in as.
@ -476,33 +450,53 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
@Override
public boolean isAnonymous() {
return anonymous;
return config.isAnonymous();
}
protected void setServiceName(String serviceName) {
config.setServiceName(serviceName);
}
private String serviceName;
protected void setLoginInfo(String username, String password, String resource) {
config.setLoginInfo(username, password, resource);
}
protected List<HostAddress> hostAddresses;
protected void maybeResolveDns() throws Exception {
config.maybeResolveDns();
protected void populateHostAddresses() throws Exception {
// N.B.: Important to use config.serviceName and not AbstractXMPPConnection.serviceName
if (config.host != null) {
hostAddresses = new ArrayList<HostAddress>(1);
HostAddress hostAddress;
hostAddress = new HostAddress(config.host, config.port);
hostAddresses.add(hostAddress);
} else {
hostAddresses = DNSUtil.resolveXMPPDomain(config.serviceName);
}
}
protected Lock getConnectionLock() {
return connectionLock;
}
@Override
public void sendPacket(Packet packet) throws NotConnectedException {
protected void throwNotConnectedExceptionIfAppropriate() throws NotConnectedException {
if (!isConnected()) {
throw new NotConnectedException();
}
}
protected void throwAlreadyConnectedExceptionIfAppropriate() throws AlreadyConnectedException {
if (isConnected()) {
throw new AlreadyConnectedException();
}
}
protected void throwAlreadyLoggedInExceptionIfAppropriate() throws AlreadyLoggedInException {
if (isAuthenticated()) {
throw new AlreadyLoggedInException();
}
}
@Override
public void sendPacket(Packet packet) throws NotConnectedException {
if (packet == null) {
throw new IllegalArgumentException("Packet must not be null");
}
throwNotConnectedExceptionIfAppropriate();
switch (fromMode) {
case OMITTED:
packet.setFrom(null);
@ -897,9 +891,8 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
* Sets whether the connection has already logged in the server. This method assures that the
* {@link #wasAuthenticated} flag is never reset once it has ever been set.
*
* @param authenticated true if the connection has already been authenticated.
*/
protected void setWasAuthenticated(boolean authenticated) {
protected void setWasAuthenticated() {
// Never reset the flag if the connection has ever been authenticated
if (!wasAuthenticated) {
wasAuthenticated = authenticated;
@ -1229,4 +1222,5 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected void reportStanzaReceived() {
this.lastStanzaReceived = System.currentTimeMillis();
}
}

View File

@ -17,33 +17,23 @@
package org.jivesoftware.smack;
import java.util.Locale;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.proxy.ProxyInfo;
import org.jivesoftware.smack.rosterstore.RosterStore;
import org.jivesoftware.smack.util.DNSUtil;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.dns.HostAddress;
import org.jxmpp.util.XmppStringUtils;
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.security.auth.callback.CallbackHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Configuration to use while establishing the connection to the server. It is possible to
* configure the path to the trustore file that keeps the trusted CA root certificates and
* enable or disable all or some of the checkings done while verifying server certificates.<p>
*
* It is also possible to configure if TLS, SASL, and compression are used or not.
* Configuration to use while establishing the connection to the server.
*
* @author Gaston Dombiak
*/
public class ConnectionConfiguration implements Cloneable {
public abstract class ConnectionConfiguration {
static {
// Ensure that Smack is initialized when ConnectionConfiguration is used, or otherwise e.g.
@ -56,168 +46,104 @@ public class ConnectionConfiguration implements Cloneable {
* of the server. However, there are some servers like google where host would be
* talk.google.com and the serviceName would be gmail.com.
*/
private String serviceName;
protected final String serviceName;
protected final String host;
protected final int port;
protected List<HostAddress> hostAddresses;
private String keystorePath;
private String keystoreType;
private String pkcs11Library;
private SSLContext customSSLContext;
private boolean compressionEnabled = false;
private final String keystorePath;
private final String keystoreType;
private final String pkcs11Library;
private final SSLContext customSSLContext;
/**
* Used to get information from the user
*/
private CallbackHandler callbackHandler;
private final CallbackHandler callbackHandler;
private boolean debuggerEnabled = SmackConfiguration.DEBUG_ENABLED;
private final boolean debuggerEnabled;
// Holds the socket factory that is used to generate the socket in the connection
private SocketFactory socketFactory;
// Holds the authentication information for future reconnections
private String username;
private String password;
private String resource;
private boolean sendPresence = true;
private boolean rosterLoadedAtLogin = true;
private boolean legacySessionDisabled = false;
private boolean useDnsSrvRr = true;
private SecurityMode securityMode = SecurityMode.enabled;
private final SocketFactory socketFactory;
private final String username;
private final String password;
private final String resource;
private final boolean sendPresence;
private final boolean rosterLoadedAtLogin;
private final boolean legacySessionDisabled;
private final SecurityMode securityMode;
/**
*
*/
private String[] enabledSSLProtocols;
private final String[] enabledSSLProtocols;
/**
*
*/
private String[] enabledSSLCiphers;
private final String[] enabledSSLCiphers;
private HostnameVerifier hostnameVerifier;
private final HostnameVerifier hostnameVerifier;
/**
* Permanent store for the Roster, needed for roster versioning
*/
private RosterStore rosterStore;
private final RosterStore rosterStore;
// Holds the proxy information (such as proxyhost, proxyport, username, password etc)
protected ProxyInfo proxy;
protected final ProxyInfo proxy;
/**
* Creates a new ConnectionConfiguration for the specified service name.
* A DNS SRV lookup will be performed to find out the actual host address
* and port to use for the connection.
*
* @param serviceName the name of the service provided by an XMPP server.
*/
public ConnectionConfiguration(String serviceName) {
init(serviceName, ProxyInfo.forDefaultProxy());
}
/**
* Creates a new ConnectionConfiguration for the specified service name
* with specified proxy.
* A DNS SRV lookup will be performed to find out the actual host address
* and port to use for the connection.
*
* @param serviceName the name of the service provided by an XMPP server.
* @param proxy the proxy through which XMPP is to be connected
*/
public ConnectionConfiguration(String serviceName,ProxyInfo proxy) {
init(serviceName, proxy);
}
/**
* Creates a new ConnectionConfiguration using the specified host, port and
* service name. This is useful for manually overriding the DNS SRV lookup
* process that's used with the {@link #ConnectionConfiguration(String)}
* constructor. For example, say that an XMPP server is running at localhost
* in an internal network on port 5222 but is configured to think that it's
* "example.com" for testing purposes. This constructor is necessary to connect
* to the server in that case since a DNS SRV lookup for example.com would not
* point to the local testing server.
*
* @param host the host where the XMPP server is running.
* @param port the port where the XMPP is listening.
* @param serviceName the name of the service provided by an XMPP server.
*/
public ConnectionConfiguration(String host, int port, String serviceName) {
initHostAddresses(host, port);
init(serviceName, ProxyInfo.forDefaultProxy());
}
/**
* Creates a new ConnectionConfiguration using the specified host, port and
* service name. This is useful for manually overriding the DNS SRV lookup
* process that's used with the {@link #ConnectionConfiguration(String)}
* constructor. For example, say that an XMPP server is running at localhost
* in an internal network on port 5222 but is configured to think that it's
* "example.com" for testing purposes. This constructor is necessary to connect
* to the server in that case since a DNS SRV lookup for example.com would not
* point to the local testing server.
*
* @param host the host where the XMPP server is running.
* @param port the port where the XMPP is listening.
* @param serviceName the name of the service provided by an XMPP server.
* @param proxy the proxy through which XMPP is to be connected
*/
public ConnectionConfiguration(String host, int port, String serviceName, ProxyInfo proxy) {
initHostAddresses(host, port);
init(serviceName, proxy);
}
/**
* Creates a new ConnectionConfiguration for a connection that will connect
* to the desired host and port.
*
* @param host the host where the XMPP server is running.
* @param port the port where the XMPP is listening.
*/
public ConnectionConfiguration(String host, int port) {
initHostAddresses(host, port);
init(host, ProxyInfo.forDefaultProxy());
}
/**
* Creates a new ConnectionConfiguration for a connection that will connect
* to the desired host and port with desired proxy.
*
* @param host the host where the XMPP server is running.
* @param port the port where the XMPP is listening.
* @param proxy the proxy through which XMPP is to be connected
*/
public ConnectionConfiguration(String host, int port, ProxyInfo proxy) {
initHostAddresses(host, port);
init(host, proxy);
}
protected void init(String serviceName, ProxyInfo proxy) {
if (StringUtils.isEmpty(serviceName)) {
throw new IllegalArgumentException("serviceName must not be the empty String");
protected ConnectionConfiguration(ConnectionConfigurationBuilder<?,?> builder) {
if (builder.username != null) {
// Do partial version of nameprep on the username.
username = builder.username.toLowerCase(Locale.US).trim();
} else {
username = null;
}
password = builder.password;
callbackHandler = builder.callbackHandler;
if (callbackHandler == null && (password == null || username == null) && !builder.anonymous) {
throw new IllegalArgumentException(
"Must provide either a username and password, a callback handler or set the connection configuration anonymous");
}
this.serviceName = serviceName;
this.proxy = proxy;
keystorePath = System.getProperty("javax.net.ssl.keyStore");
keystoreType = "jks";
pkcs11Library = "pkcs11.config";
//Setting the SocketFactory according to proxy supplied
socketFactory = proxy.getSocketFactory();
// Resource can be null, this means that the server must provide one
resource = builder.resource;
serviceName = builder.serviceName;
if (serviceName == null) {
throw new IllegalArgumentException("Must provide XMPP service name");
}
host = builder.host;
port = builder.port;
proxy = builder.proxy;
if (proxy != null) {
if (builder.socketFactory != null) {
throw new IllegalArgumentException("Can not use proxy together with custom socket factory");
}
socketFactory = proxy.getSocketFactory();
} else {
socketFactory = builder.socketFactory;
}
securityMode = builder.securityMode;
keystoreType = builder.keystoreType;
keystorePath = builder.keystorePath;
pkcs11Library = builder.pkcs11Library;
customSSLContext = builder.customSSLContext;
enabledSSLProtocols = builder.enabledSSLProtocols;
enabledSSLCiphers = builder.enabledSSLCiphers;
hostnameVerifier = builder.hostnameVerifier;
sendPresence = builder.sendPresence;
rosterLoadedAtLogin = builder.rosterLoadedAtLogin;
legacySessionDisabled = builder.legacySessionDisabled;
rosterStore = builder.rosterStore;
debuggerEnabled = builder.debuggerEnabled;
}
/**
* Sets the server name, also known as XMPP domain of the target server.
*
* @param serviceName the XMPP domain of the target server.
*/
void setServiceName(String serviceName) {
serviceName = XmppStringUtils.parseDomain(serviceName);
this.serviceName = serviceName;
public boolean isAnonymous() {
return username == null && callbackHandler == null;
}
/**
@ -239,16 +165,6 @@ public class ConnectionConfiguration implements Cloneable {
return securityMode;
}
/**
* Sets the TLS security mode used when making the connection. By default,
* the mode is {@link SecurityMode#enabled}.
*
* @param securityMode the security mode.
*/
public void setSecurityMode(SecurityMode securityMode) {
this.securityMode = securityMode;
}
/**
* Retuns the path to the keystore file. The key store file contains the
* certificates that may be used to authenticate the client to the server,
@ -260,17 +176,6 @@ public class ConnectionConfiguration implements Cloneable {
return keystorePath;
}
/**
* Sets the path to the keystore file. The key store file contains the
* certificates that may be used to authenticate the client to the server,
* in the event the server requests or requires it.
*
* @param keystorePath the path to the keystore file.
*/
public void setKeystorePath(String keystorePath) {
this.keystorePath = keystorePath;
}
/**
* Returns the keystore type, or <tt>null</tt> if it's not set.
*
@ -280,16 +185,6 @@ public class ConnectionConfiguration implements Cloneable {
return keystoreType;
}
/**
* Sets the keystore type.
*
* @param keystoreType the keystore type.
*/
public void setKeystoreType(String keystoreType) {
this.keystoreType = keystoreType;
}
/**
* Returns the PKCS11 library file location, needed when the
* Keystore type is PKCS11.
@ -301,17 +196,7 @@ public class ConnectionConfiguration implements Cloneable {
}
/**
* Sets the PKCS11 library file location, needed when the
* Keystore type is PKCS11
*
* @param pkcs11Library the path to the PKCS11 library file
*/
public void setPKCS11Library(String pkcs11Library) {
this.pkcs11Library = pkcs11Library;
}
/**
* Gets the custom SSLContext previously set with {@link #setCustomSSLContext(SSLContext)} for
* Gets the custom SSLContext previously set with {@link ConnectionConfigurationBuilder#setCustomSSLContext(SSLContext)} for
* SSL sockets. This is null by default.
*
* @return the custom SSLContext or null.
@ -320,28 +205,6 @@ public class ConnectionConfiguration implements Cloneable {
return this.customSSLContext;
}
/**
* Sets a custom SSLContext for creating SSL sockets.
* <p>
* For more information on how to create a SSLContext see <a href=
* "http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager"
* >Java Secure Socket Extension (JSEE) Reference Guide: Creating Your Own X509TrustManager</a>
*
* @param context the custom SSLContext for new sockets
*/
public void setCustomSSLContext(SSLContext context) {
this.customSSLContext = context;
}
/**
* Set the enabled SSL/TLS protocols.
*
* @param enabledSSLProtocols
*/
public void setEnabledSSLProtocols(String[] enabledSSLProtocols) {
this.enabledSSLProtocols = enabledSSLProtocols;
}
/**
* Return the enabled SSL/TLS protocols.
*
@ -351,15 +214,6 @@ public class ConnectionConfiguration implements Cloneable {
return enabledSSLProtocols;
}
/**
* Set the enabled SSL/TLS ciphers.
*
* @param enabledSSLCiphers the enabled SSL/TLS ciphers
*/
public void setEnabledSSLCiphers(String[] enabledSSLCiphers) {
this.enabledSSLCiphers = enabledSSLCiphers;
}
/**
* Return the enabled SSL/TLS ciphers.
*
@ -369,16 +223,6 @@ public class ConnectionConfiguration implements Cloneable {
return enabledSSLCiphers;
}
/**
* Set the HostnameVerifier used to verify the hostname of SSLSockets used by XMPP connections
* created with this ConnectionConfiguration.
*
* @param verifier
*/
public void setHostnameVerifier(HostnameVerifier verifier) {
hostnameVerifier = verifier;
}
/**
* Returns the configured HostnameVerifier of this ConnectionConfiguration or the Smack default
* HostnameVerifier configured with
@ -392,30 +236,6 @@ public class ConnectionConfiguration implements Cloneable {
return SmackConfiguration.getDefaultHostnameVerifier();
}
/**
* Returns true if the connection is going to use stream compression. Stream compression
* will be requested after TLS was established (if TLS was enabled) and only if the server
* offered stream compression. With stream compression network traffic can be reduced
* up to 90%. By default compression is disabled.
*
* @return true if the connection is going to use stream compression.
*/
public boolean isCompressionEnabled() {
return compressionEnabled;
}
/**
* Sets if the connection is going to use stream compression. Stream compression
* will be requested after TLS was established (if TLS was enabled) and only if the server
* offered stream compression. With stream compression network traffic can be reduced
* up to 90%. By default compression is disabled.
*
* @param compressionEnabled if the connection is going to use stream compression.
*/
public void setCompressionEnabled(boolean compressionEnabled) {
this.compressionEnabled = compressionEnabled;
}
/**
* Returns true if the new connection about to be establish is going to be debugged. By
* default the value of {@link SmackConfiguration#DEBUG_ENABLED} is used.
@ -426,38 +246,6 @@ public class ConnectionConfiguration implements Cloneable {
return debuggerEnabled;
}
/**
* Sets if the new connection about to be establish is going to be debugged. By
* default the value of {@link SmackConfiguration#DEBUG_ENABLED} is used.
*
* @param debuggerEnabled if the new connection about to be establish is going to be debugged.
*/
public void setDebuggerEnabled(boolean debuggerEnabled) {
this.debuggerEnabled = debuggerEnabled;
}
/**
* Sets the socket factory used to create new xmppConnection sockets.
* This is useful when connecting through SOCKS5 proxies.
*
* @param socketFactory used to create new sockets.
*/
public void setSocketFactory(SocketFactory socketFactory) {
this.socketFactory = socketFactory;
}
/**
* Sets if an initial available presence will be sent to the server. By default
* an available presence will be sent to the server indicating that this presence
* is not online and available to receive messages. If you want to log in without
* being 'noticed' then pass a <tt>false</tt> value.
*
* @param sendPresence true if an initial available presence will be sent while logging in.
*/
public void setSendPresence(boolean sendPresence) {
this.sendPresence = sendPresence;
}
/**
* Returns true if the roster will be loaded from the server when logging in. This
* is the common behaviour for clients but sometimes clients may want to differ this
@ -469,17 +257,6 @@ public class ConnectionConfiguration implements Cloneable {
return rosterLoadedAtLogin;
}
/**
* Sets if the roster will be loaded from the server when logging in. This
* is the common behaviour for clients but sometimes clients may want to differ this
* or just never do it if not interested in rosters.
*
* @param rosterLoadedAtLogin if the roster will be loaded from the server when logging in.
*/
public void setRosterLoadedAtLogin(boolean rosterLoadedAtLogin) {
this.rosterLoadedAtLogin = rosterLoadedAtLogin;
}
/**
* Returns true if a {@link Session} will be requested on login if the server
* supports it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't
@ -491,17 +268,6 @@ public class ConnectionConfiguration implements Cloneable {
return legacySessionDisabled;
}
/**
* Sets if a {@link Session} will be requested on login if the server supports
* it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't even
* mention this part of the protocol.
*
* @param legacySessionDisabled if a session has to be requested when logging in.
*/
public void setLegacySessionDisabled(boolean legacySessionDisabled) {
this.legacySessionDisabled = legacySessionDisabled;
}
/**
* Returns a CallbackHandler to obtain information, such as the password or
* principal information during the SASL authentication. A CallbackHandler
@ -515,19 +281,6 @@ public class ConnectionConfiguration implements Cloneable {
return callbackHandler;
}
/**
* Sets a CallbackHandler to obtain information, such as the password or
* principal information during the SASL authentication. A CallbackHandler
* will be used <b>ONLY</b> if no password was specified during the login while
* using SASL authentication.
*
* @param callbackHandler to obtain information, such as the password or
* principal information during the SASL authentication.
*/
public void setCallbackHandler(CallbackHandler callbackHandler) {
this.callbackHandler = callbackHandler;
}
/**
* Returns the socket factory used to create new xmppConnection sockets.
* This is useful when connecting through SOCKS5 proxies.
@ -538,17 +291,6 @@ public class ConnectionConfiguration implements Cloneable {
return this.socketFactory;
}
public List<HostAddress> getHostAddresses() {
return Collections.unmodifiableList(hostAddresses);
}
/**
* Set the permanent roster store
*/
public void setRosterStore(RosterStore store) {
rosterStore = store;
}
/**
* Get the permanent roster store
*/
@ -620,25 +362,319 @@ public class ConnectionConfiguration implements Cloneable {
return sendPresence;
}
void setLoginInfo(String username, String password, String resource) {
this.username = username;
this.password = password;
this.resource = resource;
/**
* Returns true if the connection is going to use stream compression. Stream compression
* will be requested after TLS was established (if TLS was enabled) and only if the server
* offered stream compression. With stream compression network traffic can be reduced
* up to 90%. By default compression is disabled.
*
* @return true if the connection is going to use stream compression.
*/
public boolean isCompressionEnabled() {
// Compression for non-TCP connections is always disabled
return false;
}
void maybeResolveDns() throws Exception {
if (!useDnsSrvRr) return;
hostAddresses = DNSUtil.resolveXMPPDomain(serviceName);
}
/**
* A builder for XMPP connection configurations.
* <p>
* This is an abstract class that uses the builder design pattern and the "getThis() trick" to recover the type of
* the builder in a class hierarchies with a self-referential generic supertype. Otherwise chaining of build
* instructions from the superclasses followed by build instructions of a sublcass would not be possible, because
* the superclass build instructions would return the builder of the superclass and not the one of the subclass. You
* can read more about it a Angelika Langer's Generics FAQ, especially the entry <a
* href="http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206">What is the
* "getThis()" trick?</a>.
* </p>
*
* @param <B> the builder type parameter.
* @param <C> the resulting connection configuration type parameter.
*/
public static abstract class ConnectionConfigurationBuilder<B extends ConnectionConfigurationBuilder<B, C>, C extends ConnectionConfiguration> {
private SecurityMode securityMode = SecurityMode.enabled;
private String keystorePath = System.getProperty("javax.net.ssl.keyStore");
private String keystoreType = "jks";
private String pkcs11Library = "pkcs11.config";
private SSLContext customSSLContext;
private String[] enabledSSLProtocols;
private String[] enabledSSLCiphers;
private HostnameVerifier hostnameVerifier;
private String username;
private String password;
private boolean anonymous;
private String resource = "Smack";
private boolean sendPresence = true;
private boolean rosterLoadedAtLogin = true;
private boolean legacySessionDisabled = false;
private RosterStore rosterStore;
private ProxyInfo proxy;
private CallbackHandler callbackHandler;
private boolean debuggerEnabled = SmackConfiguration.DEBUG_ENABLED;
private SocketFactory socketFactory;
private String serviceName;
private String host;
private int port = 5222;
private void initHostAddresses(String host, int port) {
if (StringUtils.isEmpty(host)) {
throw new IllegalArgumentException("host must not be the empty String");
protected ConnectionConfigurationBuilder() {
}
hostAddresses = new ArrayList<HostAddress>(1);
HostAddress hostAddress;
hostAddress = new HostAddress(host, port);
hostAddresses.add(hostAddress);
useDnsSrvRr = false;
/**
* Set the XMPP entities username and password.
* <p>
* The username is the localpart of the entities JID, e.g. <code>localpart@example.org</code>. In order to
* create an anonymous connection, call {@link #makeAnonymous} instead.
* </p>
*
* @param username
* @param password
* @return a reference to this builder.
*/
public B setUsernameAndPassword(String username, String password) {
this.username = username;
this.password = password;
return getThis();
}
/**
* Create a configuration for a anonymous XMPP connection.
* <p>
* Anonyous connections don't provide a username or other authentification credentials like a password. Instead
* the XMPP server, if supporting anonymous connections, will assign a username to the client.
* </p>
*
* @return a reference to this builder.
*/
public B makeAnonymous() {
this.username = null;
this.password = null;
anonymous = true;
return getThis();
}
/**
* Set the service name of this XMPP service (i.e., the XMPP domain).
*
* @param serviceName the service name
* @return a reference to this builder.
*/
public B setServiceName(String serviceName) {
this.serviceName = serviceName;
return getThis();
}
/**
* Set the resource to use.
* <p>
* If <code>resource</code> is <code>null</code>, then the server will automatically create a resource for the
* client. Default resource is "Smack".
* </p>
*
* @param resource the resource to use.
* @return a reference to this builder.
*/
public B setResource(String resource) {
this.resource = resource;
return getThis();
}
public B setHost(String host) {
this.host = host;
return getThis();
}
public B setPort(int port) {
this.port = port;
return getThis();
}
/**
* Sets a CallbackHandler to obtain information, such as the password or
* principal information during the SASL authentication. A CallbackHandler
* will be used <b>ONLY</b> if no password was specified during the login while
* using SASL authentication.
*
* @param callbackHandler to obtain information, such as the password or
* principal information during the SASL authentication.
* @return a reference to this builder.
*/
public B setCallbackHandler(CallbackHandler callbackHandler) {
this.callbackHandler = callbackHandler;
return getThis();
}
/**
* Sets the TLS security mode used when making the connection. By default,
* the mode is {@link SecurityMode#enabled}.
*
* @param securityMode the security mode.
* @return a reference to this builder.
*/
public B setSecurityMode(SecurityMode securityMode) {
this.securityMode = securityMode;
return getThis();
}
/**
* Sets the path to the keystore file. The key store file contains the
* certificates that may be used to authenticate the client to the server,
* in the event the server requests or requires it.
*
* @param keystorePath the path to the keystore file.
* @return a reference to this builder.
*/
public B setKeystorePath(String keystorePath) {
this.keystorePath = keystorePath;
return getThis();
}
/**
* Sets the keystore type.
*
* @param keystoreType the keystore type.
* @return a reference to this builder.
*/
public B setKeystoreType(String keystoreType) {
this.keystoreType = keystoreType;
return getThis();
}
/**
* Sets the PKCS11 library file location, needed when the
* Keystore type is PKCS11
*
* @param pkcs11Library the path to the PKCS11 library file.
* @return a reference to this builder.
*/
public B setPKCS11Library(String pkcs11Library) {
this.pkcs11Library = pkcs11Library;
return getThis();
}
/**
* Sets a custom SSLContext for creating SSL sockets.
* <p>
* For more information on how to create a SSLContext see <a href=
* "http://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#X509TrustManager"
* >Java Secure Socket Extension (JSEE) Reference Guide: Creating Your Own X509TrustManager</a>
*
* @param context the custom SSLContext for new sockets.
* @return a reference to this builder.
*/
public B setCustomSSLContext(SSLContext context) {
this.customSSLContext = context;
return getThis();
}
/**
* Set the enabled SSL/TLS protocols.
*
* @param enabledSSLProtocols
* @return a reference to this builder.
*/
public B setEnabledSSLProtocols(String[] enabledSSLProtocols) {
this.enabledSSLProtocols = enabledSSLProtocols;
return getThis();
}
/**
* Set the enabled SSL/TLS ciphers.
*
* @param enabledSSLCiphers the enabled SSL/TLS ciphers
* @return a reference to this builder.
*/
public B setEnabledSSLCiphers(String[] enabledSSLCiphers) {
this.enabledSSLCiphers = enabledSSLCiphers;
return getThis();
}
/**
* Set the HostnameVerifier used to verify the hostname of SSLSockets used by XMPP connections
* created with this ConnectionConfiguration.
*
* @param verifier
* @return a reference to this builder.
*/
public B setHostnameVerifier(HostnameVerifier verifier) {
hostnameVerifier = verifier;
return getThis();
}
/**
* Sets if a {@link Session} will be requested on login if the server supports
* it. Although this was mandatory on RFC 3921, RFC 6120/6121 don't even
* mention this part of the protocol.
*
* @param legacySessionDisabled if a session has to be requested when logging in.
* @return a reference to this builder.
*/
public B setLegacySessionDisabled(boolean legacySessionDisabled) {
this.legacySessionDisabled = legacySessionDisabled;
return getThis();
}
/**
* Sets if the roster will be loaded from the server when logging in. This
* is the common behaviour for clients but sometimes clients may want to differ this
* or just never do it if not interested in rosters.
*
* @param rosterLoadedAtLogin if the roster will be loaded from the server when logging in.
* @return a reference to this builder.
*/
public B setRosterLoadedAtLogin(boolean rosterLoadedAtLogin) {
this.rosterLoadedAtLogin = rosterLoadedAtLogin;
return getThis();
}
/**
* Sets if an initial available presence will be sent to the server. By default
* an available presence will be sent to the server indicating that this presence
* is not online and available to receive messages. If you want to log in without
* being 'noticed' then pass a <tt>false</tt> value.
*
* @param sendPresence true if an initial available presence will be sent while logging in.
* @return a reference to this builder.
*/
public B setSendPresence(boolean sendPresence) {
this.sendPresence = sendPresence;
return getThis();
}
/**
* Set the permanent roster store.
*
* @return a reference to this builder.
*/
public B setRosterStore(RosterStore store) {
rosterStore = store;
return getThis();
}
/**
* Sets if the new connection about to be establish is going to be debugged. By
* default the value of {@link SmackConfiguration#DEBUG_ENABLED} is used.
*
* @param debuggerEnabled if the new connection about to be establish is going to be debugged.
* @return a reference to this builder.
*/
public B setDebuggerEnabled(boolean debuggerEnabled) {
this.debuggerEnabled = debuggerEnabled;
return getThis();
}
/**
* Sets the socket factory used to create new xmppConnection sockets.
* This is useful when connecting through SOCKS5 proxies.
*
* @param socketFactory used to create new sockets.
* @return a reference to this builder.
*/
public B setSocketFactory(SocketFactory socketFactory) {
this.socketFactory = socketFactory;
return getThis();
}
public abstract C build();
protected abstract B getThis();
}
}

View File

@ -28,6 +28,7 @@ import java.util.Set;
import javax.net.ssl.HostnameVerifier;
import org.jivesoftware.smack.ConnectionConfiguration.ConnectionConfigurationBuilder;
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory;
import org.jivesoftware.smack.debugger.SmackDebugger;
@ -267,7 +268,7 @@ public final class SmackConfiguration {
* Set the default HostnameVerifier that will be used by XMPP connections to verify the hostname
* of a TLS certificate. XMPP connections are able to overwrite this settings by supplying a
* HostnameVerifier in their ConnecitonConfiguration with
* {@link ConnectionConfiguration#setHostnameVerifier(HostnameVerifier)}.
* {@link ConnectionConfigurationBuilder#setHostnameVerifier(HostnameVerifier)}.
*/
public static void setDefaultHostnameVerifier(HostnameVerifier verifier) {
defaultHostnameVerififer = verifier;

View File

@ -30,7 +30,7 @@ import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.ConnectionConfigurationBuilder;
import org.jivesoftware.smack.SmackException.SecurityNotPossibleException;
@ -53,10 +53,11 @@ public class TLSUtils {
* This method requires the underlying OS to support all of TLSv1.2 , 1.1 and 1.0.
* </p>
*
* @param conf the configuration to apply this setting to
* @param builder the configuration builder to apply this setting to
*/
public static void setTLSOnly(ConnectionConfiguration conf) {
conf.setEnabledSSLProtocols(new String[] { PROTO_TLSV1_2, PROTO_TLSV1_1, PROTO_TLSV1 });
public static <B extends ConnectionConfigurationBuilder<B,?>> B setTLSOnly(B builder) {
builder.setEnabledSSLProtocols(new String[] { PROTO_TLSV1_2, PROTO_TLSV1_1, PROTO_TLSV1 });
return builder;
}
/**
@ -69,10 +70,11 @@ public class TLSUtils {
* TLSv1.1.
* </p>
*
* @param conf the configuration to apply this setting to
* @param builder the configuration builder to apply this setting to
*/
public static void setSSLv3AndTLSOnly(ConnectionConfiguration conf) {
conf.setEnabledSSLProtocols(new String[] { PROTO_TLSV1_2, PROTO_TLSV1_1, PROTO_TLSV1, PROTO_SSL3 });
public static <B extends ConnectionConfigurationBuilder<B,?>> B setSSLv3AndTLSOnly(B builder) {
builder.setEnabledSSLProtocols(new String[] { PROTO_TLSV1_2, PROTO_TLSV1_1, PROTO_TLSV1, PROTO_SSL3 });
return builder;
}
/**
@ -82,14 +84,15 @@ public class TLSUtils {
* {@link AcceptAllTrustManager}. Only use this method if you understand the implications.
* </p>
*
* @param conf
* @param builder
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
*/
public static void acceptAllCertificates(ConnectionConfiguration conf) throws NoSuchAlgorithmException, KeyManagementException {
public static <B extends ConnectionConfigurationBuilder<B,?>> B acceptAllCertificates(B builder) throws NoSuchAlgorithmException, KeyManagementException {
SSLContext context = SSLContext.getInstance(TLS);
context.init(null, new TrustManager[] { new AcceptAllTrustManager() }, new SecureRandom());
conf.setCustomSSLContext(context);
builder.setCustomSSLContext(context);
return builder;
}
public static void setEnabledProtocolsAndCiphers(final SSLSocket sslSocket,

View File

@ -354,7 +354,7 @@ public class ChatConnectionTest {
try {
con.connect();
con.login("me", "secret");
con.login();
} catch (Exception e) {
// No need for handling in a dummy connection.
}

View File

@ -23,6 +23,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.jivesoftware.smack.ConnectionConfiguration.ConnectionConfigurationBuilder;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PlainStreamElement;
import org.jivesoftware.smack.packet.TopLevelStreamElement;
@ -53,8 +54,13 @@ public class DummyConnection extends AbstractXMPPConnection {
private final BlockingQueue<TopLevelStreamElement> queue = new LinkedBlockingQueue<TopLevelStreamElement>();
public static ConnectionConfigurationBuilder<?,?> getDummyConfigurationBuilder() {
return DummyConnectionConfiguration.builder().setServiceName("example.org").setUsernameAndPassword("dummy",
"dummypass");
}
public DummyConnection() {
this(new ConnectionConfiguration("example.com"));
this(getDummyConfigurationBuilder().build());
}
public DummyConnection(ConnectionConfiguration configuration) {
@ -63,12 +69,16 @@ public class DummyConnection extends AbstractXMPPConnection {
for (ConnectionCreationListener listener : XMPPConnectionRegistry.getConnectionCreationListeners()) {
listener.connectionCreated(this);
}
connected = true;
user = "dummy@" + config.getServiceName() + "/Test";
user = config.getUsername()
+ "@"
+ config.getServiceName()
+ "/"
+ (config.getResource() != null ? config.getResource() : "Test");
}
@Override
protected void connectInternal() {
connected = true;
connectionID = "dummy-" + new Random(new Date().getTime()).nextInt();
if (reconnect) {
@ -130,19 +140,13 @@ public class DummyConnection extends AbstractXMPPConnection {
}
@Override
public void login(String username, String password, String resource)
protected void loginNonAnonymously()
throws XMPPException {
if (!isConnected()) {
throw new IllegalStateException("Not connected to server.");
}
if (isAuthenticated()) {
throw new IllegalStateException("Already logged in to server.");
}
user = (username != null ? username : "dummy")
user = config.getUsername()
+ "@"
+ config.getServiceName()
+ "/"
+ (resource != null ? resource : "Test");
+ (config.getResource() != null ? config.getResource() : "Test");
roster = new Roster(this);
anonymous = false;
authenticated = true;
@ -226,4 +230,32 @@ public class DummyConnection extends AbstractXMPPConnection {
invokePacketCollectorsAndNotifyRecvListeners(packet);
}
public static class DummyConnectionConfiguration extends ConnectionConfiguration {
protected DummyConnectionConfiguration(DummyConnectionConfigurationBuilder builder) {
super(builder);
}
public static DummyConnectionConfigurationBuilder builder() {
return new DummyConnectionConfigurationBuilder();
}
public static class DummyConnectionConfigurationBuilder
extends
ConnectionConfigurationBuilder<DummyConnectionConfigurationBuilder, DummyConnectionConfiguration> {
private DummyConnectionConfigurationBuilder() {
}
@Override
public DummyConnectionConfiguration build() {
return new DummyConnectionConfiguration(this);
}
@Override
protected DummyConnectionConfigurationBuilder getThis() {
return this;
}
}
}
}

View File

@ -61,7 +61,7 @@ public class RosterTest {
connection = new DummyConnection();
connection.connect();
connection.login("rostertest", "secret");
connection.login();
rosterListener = new TestRosterListener();
connection.getRoster().addRosterListener(rosterListener);
}

View File

@ -26,6 +26,7 @@ import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import org.jivesoftware.smack.ConnectionConfiguration.ConnectionConfigurationBuilder;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smack.packet.Packet;
@ -64,12 +65,12 @@ public class RosterVersioningTest {
DirectoryRosterStore store = DirectoryRosterStore.init(tmpFolder.newFolder("store"));
populateStore(store);
ConnectionConfiguration conf = new ConnectionConfiguration("dummy");
conf.setRosterStore(store);
connection = new DummyConnection(conf);
ConnectionConfigurationBuilder<?, ?> builder = DummyConnection.getDummyConfigurationBuilder();
builder.setRosterStore(store);
connection = new DummyConnection(builder.build());
connection.connect();
connection.login("rostertest", "secret");
connection.login();
}
@After

View File

@ -36,7 +36,7 @@ public class FileTransferNegotiatorTest {
connection = new DummyConnection();
connection.connect();
connection.login("me", "secret");
connection.login();
ServiceDiscoveryManager.getInstanceFor(connection);
}

View File

@ -42,6 +42,7 @@ public class LastActivityTest extends InitExtensions {
.namespace(LastActivity.NAMESPACE);
DummyConnection c = new DummyConnection();
c.connect();
IQ lastRequest = (IQ) PacketParserUtils.parseStanza(xml.asString());
assertTrue(lastRequest instanceof LastActivity);

View File

@ -35,6 +35,7 @@ public class VersionTest {
+ "</iq>";
// @formatter:on
DummyConnection con = new DummyConnection();
con.connect();
// Enable version replys for this connection
VersionManager.setAutoAppendSmackVersion(false);

View File

@ -53,7 +53,7 @@ public class PingTest extends InitExtensions {
+ "</iq>";
// @formatter:on
DummyConnection con = new DummyConnection();
con.connect();
// Enable ping for this connection
PingManager.getInstanceFor(con);
IQ pingRequest = (IQ) PacketParserUtils.parseStanza(control);
@ -236,7 +236,7 @@ public class PingTest extends InitExtensions {
private static ThreadedDummyConnection getAuthentiactedDummyConnection() throws SmackException, IOException, XMPPException {
ThreadedDummyConnection connection = new ThreadedDummyConnection();
connection.connect();
connection.login("foo", "bar");
connection.login();
return connection;
}
@ -252,7 +252,7 @@ public class PingTest extends InitExtensions {
DummyConnection con = new DummyConnection();
con.setPacketReplyTimeout(500);
con.connect();
con.login("foo", "bar");
con.login();
return con;
}
}

View File

@ -47,7 +47,7 @@ public class ItemValidationTest extends InitExtensions {
connection = new ThreadedDummyConnection();
connection.connect();
connection.login("me", "secret");
connection.login();
}
@After

View File

@ -70,6 +70,7 @@ public class DeliveryReceiptTest extends InitExtensions {
@Test
public void receiptManagerListenerTest() throws Exception {
DummyConnection c = new DummyConnection();
c.connect();
// Ensure SDM is created for this connection
ServiceDiscoveryManager.getInstanceFor(c);
DeliveryReceiptManager drm = DeliveryReceiptManager.getInstanceFor(c);
@ -101,6 +102,7 @@ public class DeliveryReceiptTest extends InitExtensions {
@Test
public void receiptManagerAutoReplyTest() throws Exception {
DummyConnection c = new DummyConnection();
c.connect();
// Ensure SDM is created for this connection
ServiceDiscoveryManager.getInstanceFor(c);
DeliveryReceiptManager drm = DeliveryReceiptManager.getInstanceFor(c);

View File

@ -86,7 +86,6 @@ import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.PasswordCallback;
import java.io.BufferedReader;
@ -115,7 +114,6 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
@ -256,81 +254,36 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
*/
private final Set<PacketFilter> requestAckPredicates = new LinkedHashSet<PacketFilter>();
private final XMPPTCPConnectionConfiguration config;
/**
* Creates a new connection to the specified XMPP server. A DNS SRV lookup will be
* performed to determine the IP address and port corresponding to the
* service name; if that lookup fails, it's assumed that server resides at
* <tt>serviceName</tt> with the default port of 5222. Encrypted connections (TLS)
* will be used if available, stream compression is disabled, and standard SASL
* mechanisms will be used for authentication.<p>
* <p/>
* Creates a new XMPP connection over TCP (optionally using proxies).
* <p>
* Note that XMPPTCPConnection constructors do not establish a connection to the server
* and you must call {@link #connect()}.
* </p>
*
* @param config the connection configuration.
*/
public XMPPTCPConnection(XMPPTCPConnectionConfiguration config) {
super(config);
this.config = config;
}
/**
* Creates a new XMPP connection over TCP.
* <p>
* This is the simplest constructor for connecting to an XMPP server. Alternatively,
* you can get fine-grained control over connection settings using the
* {@link #XMPPTCPConnection(ConnectionConfiguration)} constructor.<p>
* <p/>
* Note that XMPPTCPConnection constructors do not establish a connection to the server
* and you must call {@link #connect()}.<p>
* <p/>
* The CallbackHandler will only be used if the connection requires the client provide
* an SSL certificate to the server. The CallbackHandler must handle the PasswordCallback
* to prompt for a password to unlock the keystore containing the SSL certificate.
*
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>example.com</tt>.
* @param callbackHandler the CallbackHandler used to prompt for the password to the keystore.
* {@link #XMPPTCPConnection(XMPPTCPConnectionConfiguration)} constructor.
* </p>
* @param username
* @param password
* @param serviceName
*/
public XMPPTCPConnection(String serviceName, CallbackHandler callbackHandler) {
// Create the configuration for this new connection
super(new ConnectionConfiguration(serviceName));
config.setCallbackHandler(callbackHandler);
}
/**
* Creates a new XMPP connection in the same way {@link #XMPPTCPConnection(String,CallbackHandler)} does, but
* with no callback handler for password prompting of the keystore. This will work
* in most cases, provided the client is not required to provide a certificate to
* the server.
*
* @param serviceName the name of the XMPP server to connect to; e.g. <tt>example.com</tt>.
*/
public XMPPTCPConnection(String serviceName) {
// Create the configuration for this new connection
super(new ConnectionConfiguration(serviceName));
}
/**
* Creates a new XMPP connection in the same way {@link #XMPPTCPConnection(ConnectionConfiguration,CallbackHandler)} does, but
* with no callback handler for password prompting of the keystore. This will work
* in most cases, provided the client is not required to provide a certificate to
* the server.
*
*
* @param config the connection configuration.
*/
public XMPPTCPConnection(ConnectionConfiguration config) {
super(config);
}
/**
* Creates a new XMPP connection using the specified connection configuration.<p>
* <p/>
* Manually specifying connection configuration information is suitable for
* advanced users of the API. In many cases, using the
* {@link #XMPPTCPConnection(String)} constructor is a better approach.<p>
* <p/>
* Note that XMPPTCPConnection constructors do not establish a connection to the server
* and you must call {@link #connect()}.<p>
* <p/>
*
* The CallbackHandler will only be used if the connection requires the client provide
* an SSL certificate to the server. The CallbackHandler must handle the PasswordCallback
* to prompt for a password to unlock the keystore containing the SSL certificate.
*
* @param config the connection configuration.
* @param callbackHandler the CallbackHandler used to prompt for the password to the keystore.
*/
public XMPPTCPConnection(ConnectionConfiguration config, CallbackHandler callbackHandler) {
super(config);
config.setCallbackHandler(callbackHandler);
public XMPPTCPConnection(String username, String password, String serviceName) {
this(XMPPTCPConnectionConfiguration.builder().setUsernameAndPassword(username, password).setServiceName(
serviceName).build());
}
@Override
@ -361,19 +314,36 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
@Override
public synchronized void login(String username, String password, String resource) throws XMPPException, SmackException, IOException {
if (!isConnected()) {
throw new NotConnectedException();
protected void throwNotConnectedExceptionIfAppropriate() throws NotConnectedException {
packetWriter.throwNotConnectedExceptionIfDoneAndResumptionNotPossible();
}
@Override
protected void throwAlreadyConnectedExceptionIfAppropriate() throws AlreadyConnectedException {
if (isConnected() && !disconnectedButResumeable) {
throw new AlreadyConnectedException();
}
if (authenticated && !disconnectedButResumeable) {
}
@Override
protected void throwAlreadyLoggedInExceptionIfAppropriate() throws AlreadyLoggedInException {
if (isAuthenticated() && !disconnectedButResumeable) {
throw new AlreadyLoggedInException();
}
}
// Do partial version of nameprep on the username.
if (username != null) {
username = username.toLowerCase(Locale.US).trim();
}
@Override
protected void afterSuccessfulLogin(final boolean resumed) throws NotConnectedException {
// Reset the flag in case it was set
disconnectedButResumeable = false;
super.afterSuccessfulLogin(resumed);
}
@Override
protected synchronized void loginNonAnonymously() throws XMPPException, SmackException, IOException {
String password = config.getPassword();
String resource = config.getResource();
String username = config.getUsername();
if (saslAuthentication.hasNonAnonymousAuthentication()) {
// Authenticate using SASL
if (password != null) {
@ -396,7 +366,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
smResumedSyncPoint.sendAndWaitForResponse(new Resume(clientHandledStanzasCount, smSessionId));
if (smResumedSyncPoint.wasSuccessful()) {
// We successfully resumed the stream, be done here
afterSuccessfulLogin(false, true);
afterSuccessfulLogin(true);
return;
}
// SM resumption failed, what Smack does here is to report success of
@ -435,20 +405,11 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
sendPacketInternal(stanza);
}
// Stores the authentication for future reconnection
setLoginInfo(username, password, resource);
afterSuccessfulLogin(false, false);
afterSuccessfulLogin(false);
}
@Override
public synchronized void loginAnonymously() throws XMPPException, SmackException, IOException {
if (!isConnected()) {
throw new NotConnectedException();
}
if (authenticated) {
throw new AlreadyLoggedInException();
}
// Wait with SASL auth until the SASL mechanisms have been received
saslFeatureReceived.checkIfSuccessOrWaitOrThrow();
@ -466,7 +427,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
bindResourceAndEstablishSession(null);
afterSuccessfulLogin(true, false);
afterSuccessfulLogin(false);
}
@Override
@ -499,11 +460,14 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
/**
* Performs an unclean disconnect and shutdown of the connection. Does not send a closing stream stanza.
*/
public void instantShutdown() {
public synchronized void instantShutdown() {
shutdown(true);
}
private void shutdown(boolean instant) {
if (disconnectedButResumeable) {
return;
}
if (packetReader != null) {
packetReader.shutdown();
}
@ -522,7 +486,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
LOGGER.log(Level.WARNING, "shutdown", e);
}
setWasAuthenticated(authenticated);
setWasAuthenticated();
// If we are able to resume the stream, then don't set
// connected/authenticated/usingTLS to false since we like behave like we are still
// connected (e.g. sendPacket should not throw a NotConnectedException).
@ -563,12 +527,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
private void connectUsingConfiguration(ConnectionConfiguration config) throws SmackException, IOException {
try {
maybeResolveDns();
populateHostAddresses();
}
catch (Exception e) {
throw new SmackException(e);
}
Iterator<HostAddress> it = config.getHostAddresses().iterator();
Iterator<HostAddress> it = hostAddresses.iterator();
List<HostAddress> failedAddresses = new LinkedList<HostAddress>();
while (it.hasNext()) {
Exception exception = null;
@ -853,9 +817,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
*/
@Override
protected void connectInternal() throws SmackException, IOException, XMPPException {
if (connected && !disconnectedButResumeable) {
throw new AlreadyConnectedException();
}
throwAlreadyConnectedExceptionIfAppropriate();
// Establishes the connection, readers and writers
connectUsingConfiguration(config);
@ -869,14 +831,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
// Automatically makes the login if the user was previously connected successfully
// to the server and the connection was terminated abruptly
if (wasAuthenticated) {
// Make the login
if (isAnonymous()) {
// Make the anonymous login
loginAnonymously();
}
else {
login(config.getUsername(), config.getPassword(), config.getResource());
}
login();
notifyReconnection();
}
}
@ -1052,21 +1007,9 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
case "stream":
// We found an opening stream.
if ("jabber:client".equals(parser.getNamespace(null))) {
// Get the connection id.
for (int i=0; i<parser.getAttributeCount(); i++) {
if (parser.getAttributeName(i).equals("id")) {
// Save the connectionID
connectionID = parser.getAttributeValue(i);
}
// According to RFC 6120 4.7.1 response
// stream headers in c2s and s2s of the
// receiving entity MUST include the 'from'
// attribute.
else if (parser.getAttributeName(i).equals("from")) {
// Use the server name that the server says that it is.
setServiceName(parser.getAttributeValue(i));
}
}
connectionID = parser.getAttributeValue("", "id");
String reportedServiceName = parser.getAttributeValue("", "from");
assert(reportedServiceName.equals(config.getServiceName()));
}
break;
case "error":
@ -1290,7 +1233,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
return shutdownTimestamp != null;
}
private void throwNotConnectedExceptionIfDoneAndResumptionNotPossible() throws NotConnectedException {
protected void throwNotConnectedExceptionIfDoneAndResumptionNotPossible() throws NotConnectedException {
if (done() && !isSmResumptionPossible()) {
// Don't throw a NotConnectedException is there is an resumable stream available
throw new NotConnectedException();

View File

@ -0,0 +1,76 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* 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 org.jivesoftware.smack.tcp;
import org.jivesoftware.smack.ConnectionConfiguration;
public class XMPPTCPConnectionConfiguration extends ConnectionConfiguration {
private final boolean compressionEnabled;
private XMPPTCPConnectionConfiguration(XMPPTCPConnectionConfigurationBuilder builder) {
super(builder);
compressionEnabled = builder.compressionEnabled;
}
/**
* Returns true if the connection is going to use stream compression. Stream compression
* will be requested after TLS was established (if TLS was enabled) and only if the server
* offered stream compression. With stream compression network traffic can be reduced
* up to 90%. By default compression is disabled.
*
* @return true if the connection is going to use stream compression.
*/
@Override
public boolean isCompressionEnabled() {
return compressionEnabled;
}
public static XMPPTCPConnectionConfigurationBuilder builder() {
return new XMPPTCPConnectionConfigurationBuilder();
}
public static class XMPPTCPConnectionConfigurationBuilder extends ConnectionConfigurationBuilder<XMPPTCPConnectionConfigurationBuilder, XMPPTCPConnectionConfiguration> {
private boolean compressionEnabled = false;
private XMPPTCPConnectionConfigurationBuilder() {
}
/**
* Sets if the connection is going to use stream compression. Stream compression
* will be requested after TLS was established (if TLS was enabled) and only if the server
* offered stream compression. With stream compression network traffic can be reduced
* up to 90%. By default compression is disabled.
*
* @param compressionEnabled if the connection is going to use stream compression.
*/
public XMPPTCPConnectionConfigurationBuilder setCompressionEnabled(boolean compressionEnabled) {
this.compressionEnabled = compressionEnabled;
return this;
}
@Override
protected XMPPTCPConnectionConfigurationBuilder getThis() {
return this;
}
@Override
public XMPPTCPConnectionConfiguration build() {
return new XMPPTCPConnectionConfiguration(this);
}
}
}

View File

@ -45,7 +45,7 @@ public class PacketWriterTest {
@SuppressWarnings("javadoc")
@Test
public void shouldBlockAndUnblockTest() throws InterruptedException, BrokenBarrierException, NotConnectedException {
XMPPTCPConnection connection = new XMPPTCPConnection("foobar.com");
XMPPTCPConnection connection = new XMPPTCPConnection("user", "pass", "example.org");
final PacketWriter pw = connection.new PacketWriter();
connection.packetWriter = pw;
connection.packetReader = connection.new PacketReader();

View File

@ -38,7 +38,7 @@ public class RosterOfflineTest {
@Before
public void setup() throws XMPPException, SmackException {
this.connection = new XMPPTCPConnection("localhost");
this.connection = new XMPPTCPConnection("user", "pass", "example.org");
assertFalse(connection.isConnected());
roster = connection.getRoster();