mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2025-09-09 18:29:45 +02:00
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:
parent
69f387b344
commit
c81cd34561
24 changed files with 760 additions and 708 deletions
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue