From 30bbdf9fdbb1f0774a4079f7148b236d8dbb83be Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Sat, 5 Oct 2019 12:16:41 +0200
Subject: [PATCH 01/10] Remove deprecated methods from Stanza class
---
.../org/jivesoftware/smack/packet/Stanza.java | 75 +------------------
.../smackx/jingleold/nat/RTPBridge.java | 31 ++++++--
.../smackx/jingleold/nat/STUN.java | 13 +++-
3 files changed, 37 insertions(+), 82 deletions(-)
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java
index d4906ff91..2a8a534e5 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java
@@ -31,8 +31,6 @@ import org.jivesoftware.smack.util.PacketUtil;
import org.jivesoftware.smack.util.XmlStringBuilder;
import org.jxmpp.jid.Jid;
-import org.jxmpp.jid.impl.JidCreate;
-import org.jxmpp.stringprep.XmppStringprepException;
/**
* Base class for XMPP Stanzas, which are called Stanza in older versions of Smack (i.e. < 4.1).
@@ -47,6 +45,7 @@ import org.jxmpp.stringprep.XmppStringprepException;
*
*
* @author Matt Tucker
+ * @author Florian Schmaus
* @see RFC 6120 ยง 8. XML Stanzas
*/
public abstract class Stanza implements TopLevelStreamElement {
@@ -109,16 +108,6 @@ public abstract class Stanza implements TopLevelStreamElement {
return id;
}
- /**
- * Get the Stanza ID.
- * @return the stanza id.
- * @deprecated use {@link #getStanzaId()} instead.
- */
- @Deprecated
- public String getPacketID() {
- return getStanzaId();
- }
-
/**
* Sets the unique ID of the packet. To indicate that a stanza has no id
* pass null as the packet's id value.
@@ -132,16 +121,6 @@ public abstract class Stanza implements TopLevelStreamElement {
this.id = id;
}
- /**
- * Set the stanza ID.
- * @param packetID TODO javadoc me please
- * @deprecated use {@link #setStanzaId(String)} instead.
- */
- @Deprecated
- public void setPacketID(String packetID) {
- setStanzaId(packetID);
- }
-
/**
* Check if this stanza has an ID set.
*
@@ -179,26 +158,6 @@ public abstract class Stanza implements TopLevelStreamElement {
return to;
}
- /**
- * Sets who the stanza is being sent "to". The XMPP protocol often makes
- * the "to" attribute optional, so it does not always need to be set.
- *
- * @param to who the stanza is being sent to.
- * @throws IllegalArgumentException if to is not a valid JID String.
- * @deprecated use {@link #setTo(Jid)} instead.
- */
- @Deprecated
- public void setTo(String to) {
- Jid jid;
- try {
- jid = JidCreate.from(to);
- }
- catch (XmppStringprepException e) {
- throw new IllegalArgumentException(e);
- }
- setTo(jid);
- }
-
/**
* Sets who the packet is being sent "to". The XMPP protocol often makes
* the "to" attribute optional, so it does not always need to be set.
@@ -221,27 +180,6 @@ public abstract class Stanza implements TopLevelStreamElement {
return from;
}
- /**
- * Sets who the stanza is being sent "from". The XMPP protocol often
- * makes the "from" attribute optional, so it does not always need to
- * be set.
- *
- * @param from who the stanza is being sent to.
- * @throws IllegalArgumentException if from is not a valid JID String.
- * @deprecated use {@link #setFrom(Jid)} instead.
- */
- @Deprecated
- public void setFrom(String from) {
- Jid jid;
- try {
- jid = JidCreate.from(from);
- }
- catch (XmppStringprepException e) {
- throw new IllegalArgumentException(e);
- }
- setFrom(jid);
- }
-
/**
* Sets who the packet is being sent "from". The XMPP protocol often
* makes the "from" attribute optional, so it does not always need to
@@ -263,17 +201,6 @@ public abstract class Stanza implements TopLevelStreamElement {
return error;
}
- /**
- * Sets the error for this packet.
- *
- * @param error the error to associate with this packet.
- * @deprecated use {@link #setError(org.jivesoftware.smack.packet.StanzaError.Builder)} instead.
- */
- @Deprecated
- public void setError(StanzaError error) {
- this.error = error;
- }
-
/**
* Sets the error for this stanza.
*
diff --git a/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/RTPBridge.java b/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/RTPBridge.java
index 04668e6ba..bee715507 100644
--- a/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/RTPBridge.java
+++ b/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/RTPBridge.java
@@ -40,6 +40,10 @@ import org.jivesoftware.smack.xml.XmlPullParserException;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
+import org.jxmpp.jid.DomainBareJid;
+import org.jxmpp.jid.impl.JidCreate;
+import org.jxmpp.stringprep.XmppStringprepException;
+
/**
* RTPBridge IQ Stanza used to request and retrieve a RTPBridge Candidates that can be used for a Jingle Media Transmission between two parties that are behind NAT.
* This Jingle Bridge has all the needed information to establish a full UDP Channel (Send and Receive) between two parties.
@@ -397,7 +401,6 @@ public class RTPBridge extends IQ {
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
*/
- @SuppressWarnings("deprecation")
public static RTPBridge getRTPBridge(XMPPConnection connection, String sessionID) throws NotConnectedException, InterruptedException {
if (!connection.isConnected()) {
@@ -405,7 +408,13 @@ public class RTPBridge extends IQ {
}
RTPBridge rtpPacket = new RTPBridge(sessionID);
- rtpPacket.setTo(RTPBridge.NAME + "." + connection.getXMPPServiceDomain());
+ DomainBareJid jid;
+ try {
+ jid = JidCreate.domainBareFrom(RTPBridge.NAME + "." + connection.getXMPPServiceDomain());
+ } catch (XmppStringprepException e) {
+ throw new AssertionError(e);
+ }
+ rtpPacket.setTo(jid);
StanzaCollector collector = connection.createStanzaCollectorAndSend(rtpPacket);
@@ -469,7 +478,6 @@ public class RTPBridge extends IQ {
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
*/
- @SuppressWarnings("deprecation")
public static RTPBridge relaySession(XMPPConnection connection, String sessionID, String pass, TransportCandidate proxyCandidate, TransportCandidate localCandidate) throws NotConnectedException, InterruptedException {
if (!connection.isConnected()) {
@@ -477,7 +485,13 @@ public class RTPBridge extends IQ {
}
RTPBridge rtpPacket = new RTPBridge(sessionID, RTPBridge.BridgeAction.change);
- rtpPacket.setTo(RTPBridge.NAME + "." + connection.getXMPPServiceDomain());
+ DomainBareJid jid;
+ try {
+ jid = JidCreate.domainBareFrom(RTPBridge.NAME + "." + connection.getXMPPServiceDomain());
+ } catch (XmppStringprepException e) {
+ throw new AssertionError(e);
+ }
+ rtpPacket.setTo(jid);
rtpPacket.setType(Type.set);
rtpPacket.setPass(pass);
@@ -506,7 +520,6 @@ public class RTPBridge extends IQ {
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
*/
- @SuppressWarnings("deprecation")
public static String getPublicIP(XMPPConnection xmppConnection) throws NotConnectedException, InterruptedException {
if (!xmppConnection.isConnected()) {
@@ -514,7 +527,13 @@ public class RTPBridge extends IQ {
}
RTPBridge rtpPacket = new RTPBridge(RTPBridge.BridgeAction.publicip);
- rtpPacket.setTo(RTPBridge.NAME + "." + xmppConnection.getXMPPServiceDomain());
+ DomainBareJid jid;
+ try {
+ jid = JidCreate.domainBareFrom(RTPBridge.NAME + "." + xmppConnection.getXMPPServiceDomain());
+ } catch (XmppStringprepException e) {
+ throw new AssertionError(e);
+ }
+ rtpPacket.setTo(jid);
rtpPacket.setType(Type.set);
// LOGGER.debug("Relayed to: " + candidate.getIp() + ":" + candidate.getPort());
diff --git a/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/STUN.java b/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/STUN.java
index cd32d7381..ec1080f47 100644
--- a/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/STUN.java
+++ b/smack-jingle-old/src/main/java/org/jivesoftware/smackx/jingleold/nat/STUN.java
@@ -37,6 +37,10 @@ import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
+import org.jxmpp.jid.DomainBareJid;
+import org.jxmpp.jid.impl.JidCreate;
+import org.jxmpp.stringprep.XmppStringprepException;
+
/**
* STUN IQ Stanza used to request and retrieve a STUN server and port to make p2p connections easier. STUN is usually used by Jingle Media Transmission between two parties that are behind NAT.
*
@@ -177,7 +181,6 @@ public class STUN extends SimpleIQ {
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws InterruptedException if the calling thread was interrupted.
*/
- @SuppressWarnings("deprecation")
public static STUN getSTUNServer(XMPPConnection connection) throws NotConnectedException, InterruptedException {
if (!connection.isConnected()) {
@@ -185,7 +188,13 @@ public class STUN extends SimpleIQ {
}
STUN stunPacket = new STUN();
- stunPacket.setTo(DOMAIN + "." + connection.getXMPPServiceDomain());
+ DomainBareJid jid;
+ try {
+ jid = JidCreate.domainBareFrom(DOMAIN + "." + connection.getXMPPServiceDomain());
+ } catch (XmppStringprepException e) {
+ throw new AssertionError(e);
+ }
+ stunPacket.setTo(jid);
StanzaCollector collector = connection.createStanzaCollectorAndSend(stunPacket);
From 133ee29150e31731e63561a31d0ca8bd76f0f0e1 Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Sat, 5 Oct 2019 23:01:03 +0200
Subject: [PATCH 02/10] Add XmlStringBuilderTest
---
.../smack/util/XmlStringBuilderTest.java | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 smack-core/src/test/java/org/jivesoftware/smack/util/XmlStringBuilderTest.java
diff --git a/smack-core/src/test/java/org/jivesoftware/smack/util/XmlStringBuilderTest.java b/smack-core/src/test/java/org/jivesoftware/smack/util/XmlStringBuilderTest.java
new file mode 100644
index 000000000..8436a4dd2
--- /dev/null
+++ b/smack-core/src/test/java/org/jivesoftware/smack/util/XmlStringBuilderTest.java
@@ -0,0 +1,47 @@
+/**
+ *
+ * Copyright 2019 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.util;
+
+import org.jivesoftware.smack.packet.StandardExtensionElement;
+import org.jivesoftware.smack.packet.XmlEnvironment;
+import org.jivesoftware.smack.test.util.XmlUnitUtils;
+
+import org.junit.jupiter.api.Test;
+
+public class XmlStringBuilderTest {
+
+ /**
+ * Test that {@link XmlStringBuilder} does not omit the second inner namespace declaration.
+ */
+ @Test
+ public void equalInnerNamespaceTest() {
+ StandardExtensionElement innerOne = StandardExtensionElement.builder("inner", "inner-namespace").build();
+ StandardExtensionElement innerTwo = StandardExtensionElement.builder("inner", "inner-namespace").build();
+
+ StandardExtensionElement outer = StandardExtensionElement.builder("outer", "outer-namespace").addElement(
+ innerOne).addElement(innerTwo).build();
+
+ String expectedXml = "";
+ XmlStringBuilder actualXml = outer.toXML(XmlEnvironment.EMPTY);
+
+ XmlUnitUtils.assertXmlSimilar(expectedXml, actualXml);
+
+ StringBuilder actualXmlTwo = actualXml.toXML(XmlEnvironment.EMPTY);
+
+ XmlUnitUtils.assertXmlSimilar(expectedXml, actualXmlTwo);
+ }
+}
From e23babf1472f02dd3316a502fca157d192011d3b Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Sat, 5 Oct 2019 23:14:41 +0200
Subject: [PATCH 03/10] Add Stanza.setNewStanzaId() and ensureStanzaIdSet()
Also deprecate setStanzaId() since it was not clear if this would
create a new stanza ID or just ensure that one is set.
---
.../org/jivesoftware/smack/packet/Stanza.java | 36 ++++++++++++++++++-
.../receipts/DeliveryReceiptRequest.java | 5 +--
.../smackx/vcardtemp/VCardManager.java | 5 ++-
.../smackx/mam/MamIntegrationTest.java | 2 +-
4 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java
index 2a8a534e5..9d93f8b14 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/Stanza.java
@@ -138,9 +138,43 @@ public abstract class Stanza implements TopLevelStreamElement {
*
* @return the stanza id.
* @since 4.2
+ * @deprecated use {@link #setNewStanzaId()} instead.
*/
+ @Deprecated
+ // TODO: Remove in Smack 4.5.
public String setStanzaId() {
- if (!hasStanzaIdSet()) {
+ return ensureStanzaIdSet();
+ }
+
+ /**
+ * Set a new stanza ID even if there is already one set.
+ *
+ * @return the stanza id.
+ * @since 4.4
+ */
+ public String setNewStanzaId() {
+ return ensureStanzaIdSet(true);
+ }
+
+ /**
+ * Ensure a stanza id is set.
+ *
+ * @return the stanza id.
+ * @since 4.4
+ */
+ public String ensureStanzaIdSet() {
+ return ensureStanzaIdSet(false);
+ }
+
+ /**
+ * Ensure that a stanza ID is set.
+ *
+ * @param forceNew force a new ID even if there is already one set.
+ * @return the stanza ID.
+ * @since 4.4
+ */
+ private String ensureStanzaIdSet(boolean forceNew) {
+ if (forceNew || !hasStanzaIdSet()) {
setStanzaId(StanzaIdUtil.newStanzaId());
}
return getStanzaId();
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java
index 0ecef64f7..23a129e24 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/receipts/DeliveryReceiptRequest.java
@@ -22,7 +22,6 @@ import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.XmlEnvironment;
-import org.jivesoftware.smack.packet.id.StanzaIdUtil;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
@@ -83,9 +82,7 @@ public class DeliveryReceiptRequest implements ExtensionElement {
* @return the Message ID which will be used as receipt ID
*/
public static String addTo(Message message) {
- if (message.getStanzaId() == null) {
- message.setStanzaId(StanzaIdUtil.newStanzaId());
- }
+ message.ensureStanzaIdSet();
message.addExtension(new DeliveryReceiptRequest());
return message.getStanzaId();
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/vcardtemp/VCardManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/vcardtemp/VCardManager.java
index 28e126d7f..45c16f506 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/vcardtemp/VCardManager.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/vcardtemp/VCardManager.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2014 Florian Schmaus
+ * Copyright 2014-2019 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@ import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.packet.IQ;
-import org.jivesoftware.smack.packet.id.StanzaIdUtil;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
@@ -105,7 +104,7 @@ public final class VCardManager extends Manager {
vcard.setType(IQ.Type.set);
// Also make sure to generate a new stanza id (the given vcard could be a vcard result), in which case we don't
// want to use the same stanza id again (although it wouldn't break if we did)
- vcard.setStanzaId(StanzaIdUtil.newStanzaId());
+ vcard.setNewStanzaId();
connection().createStanzaCollectorAndSend(vcard).nextResultOrThrow();
}
diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java
index a7ac44581..f09832b25 100644
--- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java
+++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java
@@ -67,7 +67,7 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
EntityBareJid userTwo = conTwo.getUser().asEntityBareJid();
Message message = new Message(userTwo);
- String messageId = message.setStanzaId();
+ String messageId = message.ensureStanzaIdSet();
final String messageBody = "Test MAM message (" + testRunId + ')';
message.setBody(messageBody);
From 05c920ab56701ef9c058fe0e3957142b68aa1584 Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Sat, 12 Oct 2019 10:14:17 +0200
Subject: [PATCH 04/10] Fix typo in comment
---
.../src/main/java/org/jivesoftware/smack/SmackReactor.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java
index 342f4694a..230b0ea16 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java
@@ -216,7 +216,7 @@ public class SmackReactor {
}
if (selectWait < 0) {
- // A scheduled action was just released and become ready to execute.
+ // A scheduled action was just released and became ready to execute.
return;
}
From b510d373b5476e88014388294d74b911eb9d4983 Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Sat, 12 Oct 2019 10:22:31 +0200
Subject: [PATCH 05/10] reactor: have synchronized block include peeking at
scheduled actions
If we do not peek at the scheduled actions in the reactors
synchronized block, then there is a kind of lost-update problem. While
Ractor.schedule() will call wakeup() on the selector, a thread could
have already determined the value of selectWait, while being blocked
at the start of the synchronized reactor section. Once it is able to
enter the section, it will use an outdated selectWait value.
This leads to scheduled actions not being executed on time.
Thanks to Eng ChongMeng for reporting this and suggesting the fix.
---
.../org/jivesoftware/smack/SmackReactor.java | 32 +++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java
index 230b0ea16..1c2477789 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackReactor.java
@@ -204,25 +204,25 @@ public class SmackReactor {
return;
}
- ScheduledAction nextScheduledAction = scheduledActions.peek();
-
- long selectWait;
- if (nextScheduledAction == null) {
- // There is no next scheduled action, wait indefinitely in select() or until another thread invokes
- // selector.wakeup().
- selectWait = 0;
- } else {
- selectWait = nextScheduledAction.getTimeToDueMillis();
- }
-
- if (selectWait < 0) {
- // A scheduled action was just released and became ready to execute.
- return;
- }
-
int newSelectedKeysCount = 0;
List selectedKeys;
synchronized (selector) {
+ ScheduledAction nextScheduledAction = scheduledActions.peek();
+
+ long selectWait;
+ if (nextScheduledAction == null) {
+ // There is no next scheduled action, wait indefinitely in select() or until another thread invokes
+ // selector.wakeup().
+ selectWait = 0;
+ } else {
+ selectWait = nextScheduledAction.getTimeToDueMillis();
+ }
+
+ if (selectWait < 0) {
+ // A scheduled action was just released and became ready to execute.
+ return;
+ }
+
// Before we call select, we handle the pending the interest Ops. This will not block since no other
// thread is currently in select() at this time.
// Note: This was put deliberately before the registration lock. It may cause more synchronization but
From 7a5886279473c06d361d2903ee60f8b0eb0d13f9 Mon Sep 17 00:00:00 2001
From: John Haubrich
Date: Thu, 10 Oct 2019 08:46:47 -0400
Subject: [PATCH 06/10] gradle: Ensure git command is run projectDir rather
than CWD.
The assert on line 659 was causing my build to fail. Two issues caused
gitCommit to be empty.
1. The cmd 'git describe --always --tags --dirty=+' was not given
enough time to complete and had not exited which meant no text in
proc.text
2. The two git commands on lines 653 and 658 were run from the
CWD of my Eclipse IDE, not the $projectDir which caused git to return
an error 128.
To solve the two issues I added a waitForOrKill method call to
proc (like the srCmd had) and I set the execute to run in $projectDir
which I think was the intent/assumption in the original code.
Also add waitFor on git describe command.
---
build.gradle | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index d705a0cd2..0ae894a8c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -650,13 +650,16 @@ def getGitCommit() {
def dotGit = new File("$projectDir/.git")
if (!dotGit.isDirectory()) return 'non-git build'
+ def projectDir = dotGit.getParentFile()
def cmd = 'git describe --always --tags --dirty=+'
- def proc = cmd.execute()
+ def proc = cmd.execute(null, projectDir)
+ proc.waitForOrKill(10 * 1000)
+
def gitCommit = proc.text.trim()
assert !gitCommit.isEmpty()
def srCmd = 'git symbolic-ref --short HEAD'
- def srProc = srCmd.execute()
+ def srProc = srCmd.execute(null, projectDir)
srProc.waitForOrKill(10 * 1000)
if (srProc.exitValue() == 0) {
// Only add the information if the git command was
From db150a850ad0bf0d285f16aad6484be873d4fec4 Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Sun, 13 Oct 2019 23:02:53 +0200
Subject: [PATCH 07/10] Fix order of 'actual' and 'expected' in XmlUnitUtils
---
.../java/org/jivesoftware/smack/test/util/XmlUnitUtils.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/smack-core/src/test/java/org/jivesoftware/smack/test/util/XmlUnitUtils.java b/smack-core/src/test/java/org/jivesoftware/smack/test/util/XmlUnitUtils.java
index 18404f70f..3d9b5ba0f 100644
--- a/smack-core/src/test/java/org/jivesoftware/smack/test/util/XmlUnitUtils.java
+++ b/smack-core/src/test/java/org/jivesoftware/smack/test/util/XmlUnitUtils.java
@@ -43,7 +43,7 @@ public class XmlUnitUtils {
NormalizedSource expected = new NormalizedSource(new StreamSource(new StringReader(expectedString)));
NormalizedSource actual = new NormalizedSource(new StreamSource(new StringReader(actualString)));
- return XmlAssert.assertThat(expected).and(actual)
+ return XmlAssert.assertThat(actual).and(expected)
.ignoreChildNodesOrder()
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndAllAttributes, ElementSelectors.byNameAndText))
.normalizeWhitespace();
From 8f371c5381e3654083b657e9594c69efc33484ca Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Thu, 17 Oct 2019 12:08:20 +0200
Subject: [PATCH 08/10] Fix datatype.Scalar equals() and hashCode() methods
The previously used Number.equals() and hashCode() was just delegated
to Object and hence did not behave as expected.
---
.../jivesoftware/smack/datatypes/Scalar.java | 26 +++++++++++++++----
.../jivesoftware/smack/datatypes/UInt16.java | 15 +++++++++++
.../jivesoftware/smack/datatypes/UInt32.java | 16 ++++++++++++
3 files changed, 52 insertions(+), 5 deletions(-)
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/datatypes/Scalar.java b/smack-core/src/main/java/org/jivesoftware/smack/datatypes/Scalar.java
index fe2bca23a..9891c2e42 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/datatypes/Scalar.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/datatypes/Scalar.java
@@ -54,13 +54,29 @@ public abstract class Scalar extends java.lang.Number {
}
@Override
- public final int hashCode() {
- return number.hashCode();
- }
+ public abstract int hashCode();
@Override
- public final boolean equals(Object other) {
- return number.equals(other);
+ public boolean equals(Object other) {
+ if (!(other instanceof Scalar)) {
+ return false;
+ }
+
+ Scalar otherScalar = (Scalar) other;
+
+ if (longValue() == otherScalar.longValue()) {
+ return true;
+ }
+
+ if (doubleValue() == otherScalar.doubleValue()) {
+ return true;
+ }
+
+ if (floatValue() == otherScalar.floatValue()) {
+ return true;
+ }
+
+ return false;
}
@Override
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt16.java b/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt16.java
index 999597401..22dd8cd8d 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt16.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt16.java
@@ -39,4 +39,19 @@ public final class UInt16 extends Scalar {
public static UInt16 from(int number) {
return new UInt16(number);
}
+
+ @Override
+ public int hashCode() {
+ return number;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof UInt16) {
+ UInt16 otherUint16 = (UInt16) other;
+ return number == otherUint16.number;
+ }
+
+ return super.equals(other);
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt32.java b/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt32.java
index cb6c9aa28..e3e6bc670 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt32.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/datatypes/UInt32.java
@@ -39,4 +39,20 @@ public final class UInt32 extends Scalar {
public static UInt32 from(long number) {
return new UInt32(number);
}
+
+ @Override
+ public int hashCode() {
+ // TODO: Use Long.hashCode(number) once Smack's minimum Android SDK level is 24 or higher.
+ return (int) (number ^ (number >>> 32));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof UInt32) {
+ UInt32 otherUint32 = (UInt32) other;
+ return number == otherUint32.number;
+ }
+
+ return super.equals(other);
+ }
}
From 260c5539b55ef2c9186003a42064801c074f96af Mon Sep 17 00:00:00 2001
From: adiaholic
Date: Wed, 1 May 2019 13:29:10 +0530
Subject: [PATCH 09/10] Add support for XEP-0118: UserTune
This commit will enable user to communicate
information about music to which user is listening.
This feature is less of a requirement and more like fun to me.
An attempt at solving SMACK-257.
Incase you see any chances of improvement,
please let me know :)
---
documentation/extensions/index.md | 1 +
.../smackx/usertune/UserTuneListener.java | 27 ++
.../smackx/usertune/UserTuneManager.java | 143 ++++++++++
.../usertune/element/UserTuneElement.java | 267 ++++++++++++++++++
.../smackx/usertune/element/package-info.java | 21 ++
.../smackx/usertune/package-info.java | 21 ++
.../usertune/provider/UserTuneProvider.java | 89 ++++++
.../usertune/provider/package-info.java | 21 ++
.../extensions.providers | 7 +
.../smackx/usertune/UserTuneElementTest.java | 74 +++++
.../smackx/usertune/UserTuneManagerTest.java | 58 ++++
.../usertune/UserTuneIntegrationTest.java | 89 ++++++
.../smackx/usertune/package-info.java | 17 ++
13 files changed, 835 insertions(+)
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneListener.java
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/package-info.java
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/package-info.java
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/UserTuneProvider.java
create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/package-info.java
create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneElementTest.java
create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneManagerTest.java
create mode 100644 smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/UserTuneIntegrationTest.java
create mode 100644 smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/package-info.java
diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md
index b5c279f7d..5043f940d 100644
--- a/documentation/extensions/index.md
+++ b/documentation/extensions/index.md
@@ -56,6 +56,7 @@ Smack Extensions and currently supported XEPs of smack-extensions
| [SI File Transfer](filetransfer.md) | [XEP-0096](https://xmpp.org/extensions/xep-0096.html) | n/a | Transfer files between two users over XMPP. |
| User Mood | [XEP-0107](https://xmpp.org/extensions/xep-0107.html) | 1.2.1 | Communicate the users current mood. |
| [Entity Capabilities](caps.md) | [XEP-0115](https://xmpp.org/extensions/xep-0115.html) | n/a | Broadcasting and dynamic discovery of entity capabilities. |
+| User Tune | [XEP-0118](https://xmpp.org/extensions/xep-0118.html) | n/a | Defines a payload format for communicating information about music to which a user is listening. |
| Data Forms Validation | [XEP-0122](https://xmpp.org/extensions/xep-0122.html) | n/a | Enables an application to specify additional validation guidelines . |
| Service Administration | [XEP-0133](https://xmpp.org/extensions/xep-0133.html) | n/a | Recommended best practices for service-level administration of servers and components using Ad-Hoc Commands. |
| Stream Compression | [XEP-0138](https://xmpp.org/extensions/xep-0138.html) | n/a | Support for optional compression of the XMPP stream.
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneListener.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneListener.java
new file mode 100644
index 000000000..c513579fc
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneListener.java
@@ -0,0 +1,27 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune;
+
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smackx.usertune.element.UserTuneElement;
+
+import org.jxmpp.jid.BareJid;
+
+public interface UserTuneListener {
+
+ void onUserTuneUpdated(BareJid jid, Message message, UserTuneElement userTuneElement);
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java
new file mode 100644
index 000000000..9b158627e
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java
@@ -0,0 +1,143 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.jivesoftware.smack.AsyncButOrdered;
+import org.jivesoftware.smack.Manager;
+import org.jivesoftware.smack.SmackException.NoResponseException;
+import org.jivesoftware.smack.SmackException.NotConnectedException;
+import org.jivesoftware.smack.SmackException.NotLoggedInException;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException.XMPPErrorException;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
+import org.jivesoftware.smackx.pep.PepListener;
+import org.jivesoftware.smackx.pep.PepManager;
+import org.jivesoftware.smackx.pubsub.EventElement;
+import org.jivesoftware.smackx.pubsub.ItemsExtension;
+import org.jivesoftware.smackx.pubsub.PayloadItem;
+import org.jivesoftware.smackx.pubsub.PubSubException.NotALeafNodeException;
+import org.jivesoftware.smackx.usertune.element.UserTuneElement;
+
+import org.jxmpp.jid.BareJid;
+import org.jxmpp.jid.EntityBareJid;
+
+/**
+ * Entry point for Smacks API for XEP-0118: User Tune.
+ *
+ * To publish a UserTune, please use {@link #publishUserTune(UserTuneElement)} method. This will publish the node.
+ *
+ * To stop publishing a UserTune, please use {@link #clearUserTune()} method. This will send a disabling publish signal.
+ *
+ * To add a UserTune listener in order to remain updated with other users UserTune, use {@link #addUserTuneListener(UserTuneListener)} method.
+ *
+ * To link a UserTuneElement with {@link Message}, use 'message.addExtension(userTuneElement)'.
+ *
+ * An example to illustrate is provided inside UserTuneElementTest inside the test package.
+ *
+ * @see
+ * XEP-0118: User Tune
+ */
+public final class UserTuneManager extends Manager {
+
+ public static final String USERTUNE_NODE = "http://jabber.org/protocol/tune";
+ public static final String USERTUNE_NOTIFY = USERTUNE_NODE + "+notify";
+
+ private static final Map INSTANCES = new WeakHashMap<>();
+
+ private final Set userTuneListeners = new HashSet<>();
+ private final AsyncButOrdered asyncButOrdered = new AsyncButOrdered<>();
+ private final PepManager pepManager;
+ private boolean ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT = true;
+
+ public static synchronized UserTuneManager getInstanceFor(XMPPConnection connection) throws NotLoggedInException {
+ UserTuneManager manager = INSTANCES.get(connection);
+ if (manager == null) {
+ manager = new UserTuneManager(connection);
+ INSTANCES.put(connection, manager);
+ }
+ return manager;
+ }
+
+ private UserTuneManager(XMPPConnection connection) throws NotLoggedInException {
+ super(connection);
+ pepManager = PepManager.getInstanceFor(connection);
+ pepManager.addPepListener(new PepListener() {
+ @Override
+ public void eventReceived(EntityBareJid from, EventElement event, Message message) {
+ if (!USERTUNE_NODE.equals(event.getEvent().getNode())) {
+ return;
+ }
+
+ final BareJid contact = from.asBareJid();
+ asyncButOrdered.performAsyncButOrdered(contact, () -> {
+ ItemsExtension items = (ItemsExtension) event.getExtensions().get(0);
+ PayloadItem> payload = (PayloadItem) items.getItems().get(0);
+ UserTuneElement tune = (UserTuneElement) payload.getPayload();
+
+ for (UserTuneListener listener : userTuneListeners) {
+ synchronized (userTuneListeners) {
+ listener.onUserTuneUpdated(contact, message, tune);
+ }
+ }
+ });
+ }
+ });
+ if (ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT) {
+ enableUserTuneNotifications();
+ }
+ }
+
+ public void setUserTuneNotificationsEnabledByDefault(boolean bool) {
+ ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT = bool;
+ }
+
+ public void enableUserTuneNotifications() {
+ ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(USERTUNE_NOTIFY);
+ }
+
+ @SuppressWarnings("unused")
+ private void disableUserTuneNotifications() {
+ ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(USERTUNE_NOTIFY);
+ }
+
+ public void clearUserTune() throws NotLoggedInException, NotALeafNodeException, NoResponseException, NotConnectedException, XMPPErrorException, InterruptedException {
+ publishUserTune(UserTuneElement.EMPTY_USER_TUNE);
+ }
+
+ public void publishUserTune(UserTuneElement userTuneElement) throws NotLoggedInException, NotALeafNodeException, NoResponseException, NotConnectedException, XMPPErrorException, InterruptedException {
+ // TODO: To prevent a large number of updates when a user is skipping through tracks, an implementation SHOULD wait several seconds before publishing new tune information.
+ pepManager.publish(USERTUNE_NODE, new PayloadItem<>(userTuneElement));
+ }
+
+ public void addUserTuneListener(UserTuneListener listener) {
+ synchronized (userTuneListeners) {
+ userTuneListeners.add(listener);
+ }
+ }
+
+ public void removeUserTuneListener(UserTuneListener listener) {
+ synchronized (userTuneListeners) {
+ userTuneListeners.remove(listener);
+ }
+ }
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java
new file mode 100644
index 000000000..6cd1ca271
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java
@@ -0,0 +1,267 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune.element;
+
+import java.net.URI;
+
+import org.jivesoftware.smack.datatypes.UInt16;
+import org.jivesoftware.smack.packet.ExtensionElement;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.XmlEnvironment;
+import org.jivesoftware.smack.util.EqualsUtil;
+import org.jivesoftware.smack.util.HashCode;
+import org.jivesoftware.smack.util.XmlStringBuilder;
+
+/**
+ * {@link ExtensionElement} that contains the UserTune.
+ * Instance of UserTuneElement can be created using {@link Builder#build()}
+ * method.
+ */
+public final class UserTuneElement implements ExtensionElement {
+
+ public static final String NAMESPACE = "http://jabber.org/protocol/tune";
+ public static final String ELEMENT = "tune";
+
+ private final String artist;
+ private final UInt16 length;
+ private final Integer rating;
+ private final String source;
+ private final String title;
+ private final String track;
+ private final URI uri;
+
+ public static final UserTuneElement EMPTY_USER_TUNE = null;
+
+ private UserTuneElement(Builder builder) {
+ this.artist = builder.artist;
+ this.length = builder.length;
+ this.rating = builder.rating;
+ this.source = builder.source;
+ this.title = builder.title;
+ this.track = builder.track;
+ this.uri = builder.uri;
+ }
+
+ @Override
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ @Override
+ public String getElementName() {
+ return ELEMENT;
+ }
+
+ public String getArtist() {
+ return artist;
+ }
+
+ public UInt16 getLength() {
+ return length;
+ }
+
+ public Integer getRating() {
+ return rating;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getTrack() {
+ return track;
+ }
+
+ public URI getUri() {
+ return uri;
+ }
+
+ @Override
+ public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) {
+ XmlStringBuilder xml = new XmlStringBuilder(this);
+ if (isEmptyUserTune()) {
+ return xml.closeEmptyElement();
+ }
+ xml.rightAngleBracket();
+ xml.optElement("artist", artist);
+ xml.optElement("length", length);
+ xml.optElement("rating", rating);
+ xml.optElement("source", source);
+ xml.optElement("title", title);
+ xml.optElement("track", track);
+ xml.optElement("uri", uri);
+ return xml.closeElement(getElementName());
+ }
+
+ private boolean isEmptyUserTune() {
+ return this.equals(EMPTY_USER_TUNE);
+ }
+
+ public static boolean hasUserTuneElement(Message message) {
+ return message.hasExtension(ELEMENT, NAMESPACE);
+ }
+
+ public static UserTuneElement from(Message message) {
+ return message.getExtension(ELEMENT, NAMESPACE);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCode.builder()
+ .append(artist)
+ .append(length)
+ .append(rating)
+ .append(source)
+ .append(title)
+ .append(track)
+ .append(uri).build();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return EqualsUtil
+ .equals(this, obj, (equalsBuilder, otherTune) -> equalsBuilder
+ .append(artist, otherTune.artist)
+ .append(length, otherTune.length)
+ .append(rating, otherTune.rating)
+ .append(source, otherTune.source)
+ .append(title, otherTune.source)
+ .append(title, otherTune.title)
+ .append(track, otherTune.track)
+ .append(uri, otherTune.uri));
+ }
+
+ /**
+ * Returns a new instance of {@link Builder}.
+ * @return Builder
+ */
+ public static Builder getBuilder() {
+ return new Builder();
+ }
+
+ /**
+ * This class defines a Builder class for {@link UserTuneElement}.
+ * {@link UserTuneElement} instance can be obtained using the {@link #build()} method as follows.
+ * UserTuneElement.Builder builder = new UserTuneElement.Builder();
+ * builder.setSource("Yessongs"); builder.setTitle("Heart of the Sunrise");
+ * UserTuneElement userTuneElement = builder.build();
+ * Values such as title, source, artist, length, source, track and uri can be set using their respective setters through {@link Builder}
+ */
+ public static final class Builder {
+ private String artist;
+ private UInt16 length;
+ private Integer rating;
+ private String source;
+ private String title;
+ private String track;
+ private URI uri;
+
+ private Builder() {
+ }
+
+ /**
+ * Artist is an optional element in UserTuneElement.
+ * @param artist.
+ * @return builder.
+ */
+ public Builder setArtist(String artist) {
+ this.artist = artist;
+ return this;
+ }
+
+ /**
+ * Length is an optional element in UserTuneElement.
+ * @param length.
+ * @return builder.
+ */
+ public Builder setLength(int length) {
+ return setLength(UInt16.from(length));
+ }
+
+ /**
+ * Length is an optional element in UserTuneElement.
+ * @param length.
+ * @return builder.
+ */
+ public Builder setLength(UInt16 length) {
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Rating is an optional element in UserTuneElement.
+ * @param rating.
+ * @return builder.
+ */
+ public Builder setRating(int rating) {
+ this.rating = rating;
+ return this;
+ }
+
+ /**
+ * Source is an optional element in UserTuneElement.
+ * @param source.
+ * @return builder.
+ */
+ public Builder setSource(String source) {
+ this.source = source;
+ return this;
+ }
+
+ /**
+ * Title is an optional element in UserTuneElement.
+ * @param title.
+ * @return builder.
+ */
+ public Builder setTitle(String title) {
+ this.title = title;
+ return this;
+ }
+
+ /**
+ * Track is an optional element in UserTuneElement.
+ * @param track.
+ * @return builder.
+ */
+ public Builder setTrack(String track) {
+ this.track = track;
+ return this;
+ }
+
+ /**
+ * URI is an optional element in UserTuneElement.
+ * @param uri.
+ * @return builder.
+ */
+ public Builder setUri(URI uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ /**
+ * This method is called to build a UserTuneElement.
+ * @return UserTuneElement.
+ */
+ public UserTuneElement build() {
+ return new UserTuneElement(this);
+ }
+ }
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/package-info.java
new file mode 100644
index 000000000..06849e26a
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/package-info.java
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar
+ *
+ * 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.
+ */
+
+/**
+ * Smack's API for XEP-0118: User Tune.
+ */
+package org.jivesoftware.smackx.usertune.element;
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/package-info.java
new file mode 100644
index 000000000..182ee237e
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/package-info.java
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar
+ *
+ * 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.
+ */
+
+/**
+ * Smack's API for XEP-0118: User Tune.
+ */
+package org.jivesoftware.smackx.usertune;
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/UserTuneProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/UserTuneProvider.java
new file mode 100644
index 000000000..5b1c423ef
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/UserTuneProvider.java
@@ -0,0 +1,89 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune.provider;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.jivesoftware.smack.packet.XmlEnvironment;
+import org.jivesoftware.smack.parsing.SmackParsingException;
+import org.jivesoftware.smack.provider.ExtensionElementProvider;
+import org.jivesoftware.smack.util.ParserUtils;
+import org.jivesoftware.smack.xml.XmlPullParser;
+import org.jivesoftware.smack.xml.XmlPullParserException;
+import org.jivesoftware.smackx.usertune.element.UserTuneElement;
+
+/**
+ * This is the Provider Class for {@link UserTuneElement}.
+ */
+public class UserTuneProvider extends ExtensionElementProvider {
+
+ public static final UserTuneProvider INSTANCE = new UserTuneProvider();
+
+ @Override
+ public UserTuneElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment)
+ throws XmlPullParserException, IOException, SmackParsingException {
+
+ UserTuneElement.Builder builder = UserTuneElement.getBuilder();
+ XmlPullParser.TagEvent tag = parser.nextTag();
+ outerloop: while (true) {
+ switch (tag) {
+ case START_ELEMENT:
+ String name = parser.getName();
+ String namespace = parser.getNamespace();
+ if (!UserTuneElement.NAMESPACE.equals(namespace)) {
+ continue outerloop;
+ }
+ while (tag == XmlPullParser.TagEvent.START_ELEMENT) {
+ switch (name) {
+ case "artist":
+ builder.setArtist(parser.nextText());
+ break;
+ case "length":
+ builder.setLength(ParserUtils.getIntegerFromNextText(parser));
+ break;
+ case "rating":
+ builder.setRating(ParserUtils.getIntegerFromNextText(parser));
+ break;
+ case "source":
+ builder.setSource(parser.nextText());
+ break;
+ case "title":
+ builder.setTitle(parser.nextText());
+ break;
+ case "track":
+ builder.setTrack(parser.nextText());
+ break;
+ case "uri":
+ URI uri = ParserUtils.getUriFromNextText(parser);
+ builder.setUri(uri);
+ break;
+ }
+ tag = parser.nextTag();
+ name = parser.getName();
+ }
+ break;
+ case END_ELEMENT:
+ if (parser.getDepth() == initialDepth) {
+ break outerloop;
+ }
+ break;
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/package-info.java
new file mode 100644
index 000000000..09bcf2adc
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/provider/package-info.java
@@ -0,0 +1,21 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar
+ *
+ * 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.
+ */
+
+/**
+ * Smack's API for XEP-0118: User Tune.
+ */
+package org.jivesoftware.smackx.usertune.provider;
diff --git a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers
index a34d5435d..c673a9a2f 100644
--- a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers
+++ b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers
@@ -589,4 +589,11 @@
org.jivesoftware.smackx.mood.provider.MoodProvider
+
+
+ tune
+ http://jabber.org/protocol/tune
+ org.jivesoftware.smackx.usertune.provider.UserTuneProvider
+
+
diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneElementTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneElementTest.java
new file mode 100644
index 000000000..9aea03774
--- /dev/null
+++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneElementTest.java
@@ -0,0 +1,74 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune;
+
+import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.jivesoftware.smack.parsing.SmackParsingException;
+import org.jivesoftware.smack.test.util.SmackTestSuite;
+import org.jivesoftware.smack.test.util.SmackTestUtil;
+import org.jivesoftware.smack.test.util.SmackTestUtil.XmlPullParserKind;
+import org.jivesoftware.smack.xml.XmlPullParser;
+import org.jivesoftware.smack.xml.XmlPullParserException;
+import org.jivesoftware.smackx.usertune.element.UserTuneElement;
+import org.jivesoftware.smackx.usertune.provider.UserTuneProvider;
+
+import org.junit.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+public class UserTuneElementTest extends SmackTestSuite {
+
+ private final String xml = "" +
+ "Yes" +
+ "686" +
+ "8" +
+ "Yessongs" +
+ "Heart of the Sunrise" +
+ "" +
+ "http://www.yesworld.com/lyrics/Fragile.html#9" +
+ "";
+
+ @Test
+ public void toXmlTest() throws IOException, XmlPullParserException, SmackParsingException, URISyntaxException {
+
+ URI uri = new URI("http://www.yesworld.com/lyrics/Fragile.html#9");
+
+ UserTuneElement.Builder builder = UserTuneElement.getBuilder();
+ UserTuneElement userTuneElement = builder.setArtist("Yes")
+ .setLength(686)
+ .setRating(8)
+ .setSource("Yessongs")
+ .setTitle("Heart of the Sunrise")
+ .setTrack("3")
+ .setUri(uri)
+ .build();
+ assertXmlSimilar(xml, userTuneElement.toXML().toString());
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = SmackTestUtil.XmlPullParserKind.class)
+ public void userTuneElementProviderTest(XmlPullParserKind parserKind) throws XmlPullParserException, IOException, SmackParsingException {
+ XmlPullParser parser = SmackTestUtil.getParserFor(xml, parserKind);
+ UserTuneElement parsed = UserTuneProvider.INSTANCE.parse(parser);
+ assertXmlSimilar(xml, parsed.toXML().toString());
+ }
+}
diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneManagerTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneManagerTest.java
new file mode 100644
index 000000000..bb21fae84
--- /dev/null
+++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/usertune/UserTuneManagerTest.java
@@ -0,0 +1,58 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.test.util.SmackTestSuite;
+import org.jivesoftware.smackx.usertune.element.UserTuneElement;
+
+import org.junit.Test;
+
+public class UserTuneManagerTest extends SmackTestSuite{
+
+ @Test
+ public void addMessage() throws URISyntaxException {
+
+ UserTuneElement.Builder builder = UserTuneElement.getBuilder();
+ builder.setArtist("Yes");
+ builder.setLength(686);
+ builder.setRating(8);
+ builder.setSource("Yessongs");
+ builder.setTitle("Heart of the Sunrise");
+ builder.setTrack("3");
+ URI uri = new URI("http://www.yesworld.com/lyrics/Fragile.html#9");
+ builder.setUri(uri);
+ UserTuneElement userTuneElement = builder.build();
+
+ Message message = new Message();
+ message.addExtension(userTuneElement);
+
+ assertTrue(message.hasExtension(UserTuneElement.ELEMENT, UserTuneElement.NAMESPACE));
+ assertTrue(UserTuneElement.hasUserTuneElement(message));
+
+ UserTuneElement element = UserTuneElement.from(message);
+ assertNotNull(element);
+ assertEquals(userTuneElement, element);
+ }
+}
diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/UserTuneIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/UserTuneIntegrationTest.java
new file mode 100644
index 000000000..86383a819
--- /dev/null
+++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/UserTuneIntegrationTest.java
@@ -0,0 +1,89 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune;
+
+import java.net.URI;
+
+import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.SmackException.NotLoggedInException;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smackx.usertune.element.UserTuneElement;
+
+import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
+import org.igniterealtime.smack.inttest.SmackIntegrationTest;
+import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
+import org.igniterealtime.smack.inttest.util.IntegrationTestRosterUtil;
+import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint;
+import org.junit.AfterClass;
+
+import org.jxmpp.jid.BareJid;
+
+public class UserTuneIntegrationTest extends AbstractSmackIntegrationTest {
+
+ private final UserTuneManager utm1;
+ private final UserTuneManager utm2;
+
+ public UserTuneIntegrationTest(SmackIntegrationTestEnvironment> environment) throws NotLoggedInException {
+ super(environment);
+ utm1 = UserTuneManager.getInstanceFor(conOne);
+ utm2 = UserTuneManager.getInstanceFor(conTwo);
+ }
+
+ @SmackIntegrationTest
+ public void test() throws Exception {
+ URI uri = new URI("http://www.yesworld.com/lyrics/Fragile.html#9");
+ UserTuneElement.Builder builder = UserTuneElement.getBuilder();
+ UserTuneElement userTuneElement1 = builder.setArtist("Yes")
+ .setLength(686)
+ .setRating(8)
+ .setSource("Yessongs")
+ .setTitle("Heart of the Sunrise")
+ .setTrack("3")
+ .setUri(uri)
+ .build();
+
+ IntegrationTestRosterUtil.ensureBothAccountsAreSubscribedToEachOther(conOne, conTwo, timeout);
+
+ final SimpleResultSyncPoint userTuneReceived = new SimpleResultSyncPoint();
+
+ final UserTuneListener userTuneListener = new UserTuneListener() {
+ @Override
+ public void onUserTuneUpdated(BareJid jid, Message message, UserTuneElement userTuneElement) {
+ if (userTuneElement.equals(userTuneElement1)) {
+ userTuneReceived.signal();
+ }
+ }
+ };
+
+ utm2.addUserTuneListener(userTuneListener);
+
+ try {
+ utm1.publishUserTune(userTuneElement1);
+ userTuneReceived.waitForResult(timeout);
+ } finally {
+ utm2.removeUserTuneListener(userTuneListener);
+ }
+ }
+
+ @AfterClass
+ public void unsubscribe()
+ throws SmackException.NotLoggedInException, XMPPException.XMPPErrorException,
+ SmackException.NotConnectedException, InterruptedException, SmackException.NoResponseException {
+ IntegrationTestRosterUtil.ensureBothAccountsAreNotInEachOthersRoster(conOne, conTwo);
+ }
+}
diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/package-info.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/package-info.java
new file mode 100644
index 000000000..b4fb83a44
--- /dev/null
+++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/usertune/package-info.java
@@ -0,0 +1,17 @@
+/**
+ *
+ * Copyright 2019 Aditya Borikar.
+ *
+ * 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.smackx.usertune;
From 926c5892ad985b9fe5ef11104effa7400226304e Mon Sep 17 00:00:00 2001
From: Florian Schmaus
Date: Thu, 17 Oct 2019 12:25:09 +0200
Subject: [PATCH 10/10] Fix 260c5539b ("Add support for XEP-0118: UserTune")
Fix a bug in the EqualsBuilder usage in UserTuneElement. Properly
synchronize listeners using CopyOnWriteSet. Make methods and fields
static where sensible and possible. Make
disableUserTuneNotifications() public (why was it private?). And a few
other minor fixes.
---
.../smackx/usertune/UserTuneManager.java | 44 +++++++++----------
.../usertune/element/UserTuneElement.java | 1 -
.../extensions.providers | 2 +-
3 files changed, 23 insertions(+), 24 deletions(-)
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java
index 9b158627e..70dd900b1 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/UserTuneManager.java
@@ -16,10 +16,11 @@
*/
package org.jivesoftware.smackx.usertune;
-import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import org.jivesoftware.smack.AsyncButOrdered;
import org.jivesoftware.smack.Manager;
@@ -28,6 +29,7 @@ import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.NotLoggedInException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
+import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.pep.PepListener;
@@ -64,10 +66,12 @@ public final class UserTuneManager extends Manager {
private static final Map INSTANCES = new WeakHashMap<>();
- private final Set userTuneListeners = new HashSet<>();
+ private static boolean ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT = true;
+
+ private final Set userTuneListeners = new CopyOnWriteArraySet<>();
private final AsyncButOrdered asyncButOrdered = new AsyncButOrdered<>();
+ private final ServiceDiscoveryManager serviceDiscoveryManager;
private final PepManager pepManager;
- private boolean ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT = true;
public static synchronized UserTuneManager getInstanceFor(XMPPConnection connection) throws NotLoggedInException {
UserTuneManager manager = INSTANCES.get(connection);
@@ -90,34 +94,34 @@ public final class UserTuneManager extends Manager {
final BareJid contact = from.asBareJid();
asyncButOrdered.performAsyncButOrdered(contact, () -> {
- ItemsExtension items = (ItemsExtension) event.getExtensions().get(0);
- PayloadItem> payload = (PayloadItem) items.getItems().get(0);
- UserTuneElement tune = (UserTuneElement) payload.getPayload();
+ ItemsExtension itemsExtension = (ItemsExtension) event.getEvent();
+ List items = itemsExtension.getExtensions();
+ @SuppressWarnings("unchecked")
+ PayloadItem payload = (PayloadItem) items.get(0);
+ UserTuneElement tune = payload.getPayload();
for (UserTuneListener listener : userTuneListeners) {
- synchronized (userTuneListeners) {
- listener.onUserTuneUpdated(contact, message, tune);
- }
+ listener.onUserTuneUpdated(contact, message, tune);
}
});
}
});
+ serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
if (ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT) {
enableUserTuneNotifications();
}
}
- public void setUserTuneNotificationsEnabledByDefault(boolean bool) {
+ public static void setUserTuneNotificationsEnabledByDefault(boolean bool) {
ENABLE_USER_TUNE_NOTIFICATIONS_BY_DEFAULT = bool;
}
public void enableUserTuneNotifications() {
- ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(USERTUNE_NOTIFY);
+ serviceDiscoveryManager.addFeature(USERTUNE_NOTIFY);
}
- @SuppressWarnings("unused")
- private void disableUserTuneNotifications() {
- ServiceDiscoveryManager.getInstanceFor(connection()).removeFeature(USERTUNE_NOTIFY);
+ public void disableUserTuneNotifications() {
+ serviceDiscoveryManager.removeFeature(USERTUNE_NOTIFY);
}
public void clearUserTune() throws NotLoggedInException, NotALeafNodeException, NoResponseException, NotConnectedException, XMPPErrorException, InterruptedException {
@@ -129,15 +133,11 @@ public final class UserTuneManager extends Manager {
pepManager.publish(USERTUNE_NODE, new PayloadItem<>(userTuneElement));
}
- public void addUserTuneListener(UserTuneListener listener) {
- synchronized (userTuneListeners) {
- userTuneListeners.add(listener);
- }
+ public boolean addUserTuneListener(UserTuneListener listener) {
+ return userTuneListeners.add(listener);
}
- public void removeUserTuneListener(UserTuneListener listener) {
- synchronized (userTuneListeners) {
- userTuneListeners.remove(listener);
- }
+ public boolean removeUserTuneListener(UserTuneListener listener) {
+ return userTuneListeners.remove(listener);
}
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java
index 6cd1ca271..47a7bfd40 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/usertune/element/UserTuneElement.java
@@ -143,7 +143,6 @@ public final class UserTuneElement implements ExtensionElement {
.append(length, otherTune.length)
.append(rating, otherTune.rating)
.append(source, otherTune.source)
- .append(title, otherTune.source)
.append(title, otherTune.title)
.append(track, otherTune.track)
.append(uri, otherTune.uri));
diff --git a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers
index c673a9a2f..62adda545 100644
--- a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers
+++ b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers
@@ -595,5 +595,5 @@
http://jabber.org/protocol/tuneorg.jivesoftware.smackx.usertune.provider.UserTuneProvider
-
+