diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index ae0dcc10b..db44e93a2 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -42,6 +42,7 @@ import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure; import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Success; import org.jivesoftware.smack.util.PacketParserUtils; import org.jxmpp.jid.DomainBareJid; +import org.jxmpp.jid.parts.Resourcepart; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; import org.igniterealtime.jbosh.AbstractBody; @@ -210,7 +211,7 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { } @Override - protected void loginInternal(String username, String password, String resource) throws XMPPException, + protected void loginInternal(String username, String password, Resourcepart resource) throws XMPPException, SmackException, IOException, InterruptedException { // Authenticate using SASL saslAuthentication.authenticate(username, password); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index d6d14aae3..ac1f5020b 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -84,6 +84,7 @@ import org.jivesoftware.smack.util.dns.HostAddress; import org.jxmpp.jid.DomainBareJid; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.Jid; +import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.util.XmppStringUtils; import org.xmlpull.v1.XmlPullParser; @@ -372,7 +373,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { */ protected abstract void connectInternal() throws SmackException, IOException, XMPPException, InterruptedException; - private String usedUsername, usedPassword, usedResource; + private String usedUsername, usedPassword; + + /** + * The resourcepart used for this connection. May not be the resulting resourcepart if it's null or overridden by the XMPP service. + */ + private Resourcepart usedResource; /** * Logs in to the server using the strongest SASL mechanism supported by @@ -402,12 +408,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // ones from the connection configuration CharSequence username = usedUsername != null ? usedUsername : config.getUsername(); String password = usedPassword != null ? usedPassword : config.getPassword(); - String resource = usedResource != null ? usedResource : config.getResource(); + Resourcepart resource = usedResource != null ? usedResource : config.getResource(); login(username, password, resource); } /** - * Same as {@link #login(CharSequence, String, String)}, but takes the resource from the connection + * Same as {@link #login(CharSequence, String, Resourcepart)}, but takes the resource from the connection * configuration. * * @param username @@ -436,7 +442,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { * @throws InterruptedException * @see #login */ - public synchronized void login(CharSequence username, String password, String resource) throws XMPPException, + public synchronized void login(CharSequence username, String password, Resourcepart resource) throws XMPPException, SmackException, IOException, InterruptedException { if (!config.allowNullOrEmptyUsername) { StringUtils.requireNotNullOrEmpty(username, "Username must not be null or empty"); @@ -449,7 +455,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { loginInternal(usedUsername, usedPassword, usedResource); } - protected abstract void loginInternal(String username, String password, String resource) + protected abstract void loginInternal(String username, String password, Resourcepart resource) throws XMPPException, SmackException, IOException, InterruptedException; @Override @@ -475,7 +481,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { return streamId; } - protected void bindResourceAndEstablishSession(String resource) throws XMPPErrorException, + protected void bindResourceAndEstablishSession(Resourcepart resource) throws XMPPErrorException, SmackException, InterruptedException { // Wait until either: diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java index 92779be5d..4b91bc710 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java @@ -22,6 +22,8 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import org.jivesoftware.smack.packet.Session; import org.jivesoftware.smack.proxy.ProxyInfo; @@ -31,6 +33,8 @@ import org.jivesoftware.smack.util.CollectionUtil; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smack.util.StringUtils; import org.jxmpp.jid.DomainBareJid; +import org.jxmpp.jid.parts.Resourcepart; +import org.jxmpp.stringprep.XmppStringprepException; import javax.net.SocketFactory; import javax.net.ssl.HostnameVerifier; @@ -50,6 +54,8 @@ public abstract class ConnectionConfiguration { SmackConfiguration.getVersion(); } + private static final Logger LOGGER = Logger.getLogger(ConnectionConfiguration.class.getName()); + /** * Hostname of the XMPP server. Usually servers use the same service name as the name * of the server. However, there are some servers like google where host would be @@ -76,7 +82,7 @@ public abstract class ConnectionConfiguration { private final CharSequence username; private final String password; - private final String resource; + private final Resourcepart resource; /** * Initial presence as of RFC 6121 ยง 4.2 @@ -341,7 +347,7 @@ public abstract class ConnectionConfiguration { * * @return the resource to use when trying to reconnect to the server. */ - public String getResource() { + public Resourcepart getResource() { return resource; } @@ -401,6 +407,19 @@ public abstract class ConnectionConfiguration { * @param the resulting connection configuration type parameter. */ public static abstract class Builder, C extends ConnectionConfiguration> { + private static final Resourcepart DEFAULT_RESOURCE; + + static { + Resourcepart resourcepart = null; + try { + resourcepart = Resourcepart.from("Smack"); + } + catch (XmppStringprepException e) { + LOGGER.log(Level.WARNING, "Could not create default resourcepart", e); + } + DEFAULT_RESOURCE = resourcepart; + } + private SecurityMode securityMode = SecurityMode.ifpossible; private String keystorePath = System.getProperty("javax.net.ssl.keyStore"); private String keystoreType = "jks"; @@ -411,7 +430,7 @@ public abstract class ConnectionConfiguration { private HostnameVerifier hostnameVerifier; private CharSequence username; private String password; - private String resource = "Smack"; + private Resourcepart resource = DEFAULT_RESOURCE; private boolean sendPresence = true; private boolean legacySessionDisabled = false; private ProxyInfo proxy; @@ -466,11 +485,24 @@ public abstract class ConnectionConfiguration { * @param resource the resource to use. * @return a reference to this builder. */ - public B setResource(String resource) { + public B setResource(Resourcepart resource) { this.resource = resource; return getThis(); } + /** + * Set the resource to use. + * + * @param resource the non-null CharSequence to use a resource. + * @return a reference ot this builder. + * @throws XmppStringprepException if the CharSequence is not a valid resourcepart. + * @see setResource(Resourcepart) + */ + public B setResource(CharSequence resource) throws XmppStringprepException { + Objects.requireNonNull(resource, "resource must not be null"); + return setResource(Resourcepart.from(resource.toString())); + } + public B setHost(String host) { this.host = host; return getThis(); diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/Bind.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/Bind.java index 1b3252695..0ade03fd1 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/Bind.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/Bind.java @@ -18,6 +18,7 @@ package org.jivesoftware.smack.packet; import org.jxmpp.jid.FullJid; +import org.jxmpp.jid.parts.Resourcepart; /** * IQ stanza(/packet) used by Smack to bind a resource and to obtain the jid assigned by the server. @@ -35,16 +36,16 @@ public class Bind extends IQ { public static final String ELEMENT = "bind"; public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-bind"; - private final String resource; + private final Resourcepart resource; private final FullJid jid; - public Bind(String resource, FullJid jid) { + public Bind(Resourcepart resource, FullJid jid) { super(ELEMENT, NAMESPACE); this.resource = resource; this.jid = jid; } - public String getResource() { + public Resourcepart getResource() { return resource; } @@ -52,7 +53,7 @@ public class Bind extends IQ { return jid; } - public static Bind newSet(String resource) { + public static Bind newSet(Resourcepart resource) { Bind bind = new Bind(resource, null); bind.setType(IQ.Type.set); return bind; diff --git a/smack-core/src/main/java/org/jivesoftware/smack/provider/BindIQProvider.java b/smack-core/src/main/java/org/jivesoftware/smack/provider/BindIQProvider.java index 031d130be..bd383d352 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/provider/BindIQProvider.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/provider/BindIQProvider.java @@ -22,6 +22,7 @@ import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.packet.Bind; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Resourcepart; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -39,7 +40,8 @@ public class BindIQProvider extends IQProvider { name = parser.getName(); switch (name) { case "resource": - bind = Bind.newSet(parser.nextText()); + String resourceString = parser.nextText(); + bind = Bind.newSet(Resourcepart.from(resourceString)); break; case "jid": FullJid fullJid = JidCreate.fullFrom(parser.nextText()); diff --git a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java index 94238c971..4d7970304 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/DummyConnection.java @@ -31,6 +31,7 @@ import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jxmpp.jid.FullJid; import org.jxmpp.jid.JidTestUtil; import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; /** @@ -116,7 +117,7 @@ public class DummyConnection extends AbstractXMPPConnection { } @Override - protected void loginInternal(String username, String password, String resource) + protected void loginInternal(String username, String password, Resourcepart resource) throws XMPPException { user = getUserJid(); authenticated = true; diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index 1db54dfd1..d56e574aa 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -75,6 +75,7 @@ import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.TLSUtils; import org.jivesoftware.smack.util.dns.HostAddress; import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; import org.jxmpp.util.XmppStringUtils; import org.xmlpull.v1.XmlPullParser; @@ -361,7 +362,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { } @Override - protected synchronized void loginInternal(String username, String password, String resource) throws XMPPException, + protected synchronized void loginInternal(String username, String password, Resourcepart resource) throws XMPPException, SmackException, IOException, InterruptedException { // Authenticate using SASL saslAuthentication.authenticate(username, password);