(Arrays.asList(filters));
- }
-
- /**
- * Adds a filter to the filter list for the AND operation. A packet
- * will pass the filter if all of the filters in the list accept it.
- *
- * @param filter a filter to add to the filter list.
- */
- public void addFilter(PacketFilter filter) {
- Objects.requireNonNull(filter, "Parameter must not be null.");
- filters.add(filter);
+ super(filters);
}
public boolean accept(Stanza packet) {
@@ -78,7 +53,4 @@ public class AndFilter implements PacketFilter {
return true;
}
- public String toString() {
- return filters.toString();
- }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/FlexiblePacketTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/FlexiblePacketTypeFilter.java
index 54e49c2fe..454d8caa3 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/FlexiblePacketTypeFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/FlexiblePacketTypeFilter.java
@@ -20,6 +20,7 @@ package org.jivesoftware.smack.filter;
import java.lang.reflect.ParameterizedType;
import org.jivesoftware.smack.packet.Stanza;
+import org.jivesoftware.smack.util.Objects;
/**
* Filters for packets of a particular type and allows a custom method to further filter the packets.
@@ -31,7 +32,7 @@ public abstract class FlexiblePacketTypeFilter implements Pack
protected final Class
packetType;
public FlexiblePacketTypeFilter(Class
packetType) {
- this.packetType = packetType;
+ this.packetType = Objects.requireNonNull(packetType, "Type must not be null");
}
@SuppressWarnings("unchecked")
@@ -49,4 +50,12 @@ public abstract class FlexiblePacketTypeFilter
implements Pack
}
protected abstract boolean acceptSpecific(P packet);
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" (" + packetType.toString() + ')');
+ return sb.toString();
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/FromMatchesFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/FromMatchesFilter.java
index 78af6cdca..654fa051f 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/FromMatchesFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/FromMatchesFilter.java
@@ -106,6 +106,6 @@ public class FromMatchesFilter implements PacketFilter {
public String toString() {
String matchMode = ignoreResourcepart ? "ignoreResourcepart" : "full";
- return "FromMatchesFilter (" +matchMode + "): " + address;
+ return getClass().getSimpleName() + " (" + matchMode + "): " + address;
}
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/IQReplyFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/IQReplyFilter.java
index 499029563..b8f491863 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/IQReplyFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/IQReplyFilter.java
@@ -95,7 +95,7 @@ public class IQReplyFilter implements PacketFilter {
packetId = iqPacket.getStanzaId();
PacketFilter iqFilter = new OrFilter(IQTypeFilter.ERROR, IQTypeFilter.RESULT);
- PacketFilter idFilter = new PacketIDFilter(iqPacket);
+ PacketFilter idFilter = new StanzaIdFilter(iqPacket);
iqAndIdFilter = new AndFilter(iqFilter, idFilter);
fromFilter = new OrFilter();
fromFilter.addFilter(FromMatchesFilter.createFull(to));
@@ -126,4 +126,12 @@ public class IQReplyFilter implements PacketFilter {
}
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(": iqAndIdFilter (").append(iqAndIdFilter.toString()).append("), ");
+ sb.append(": fromFilter (").append(fromFilter.toString()).append(')');
+ return sb.toString();
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/IQResultReplyFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/IQResultReplyFilter.java
index c77539f56..a8225dcf4 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/IQResultReplyFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/IQResultReplyFilter.java
@@ -38,4 +38,11 @@ public class IQResultReplyFilter extends IQReplyFilter {
return IQTypeFilter.RESULT.accept(packet);
}
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" (" + super.toString() + ')');
+ return sb.toString();
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/IQTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/IQTypeFilter.java
index f0cccb245..dc2c38b10 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/IQTypeFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/IQTypeFilter.java
@@ -18,6 +18,7 @@ package org.jivesoftware.smack.filter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
+import org.jivesoftware.smack.util.Objects;
/**
* A filter for IQ packet types. Returns true only if the packet is an IQ packet
@@ -38,11 +39,16 @@ public class IQTypeFilter extends FlexiblePacketTypeFilter {
private IQTypeFilter(IQ.Type type) {
super(IQ.class);
- this.type = type;
+ this.type = Objects.requireNonNull(type, "Type must not be null");
}
@Override
protected boolean acceptSpecific(IQ iq) {
return iq.getType() == type;
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": type=" + type;
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageTypeFilter.java
index c7eaa5275..74df7bfed 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageTypeFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageTypeFilter.java
@@ -55,4 +55,8 @@ public class MessageTypeFilter extends FlexiblePacketTypeFilter {
return message.getType() == type;
}
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": type=" + type;
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithBodiesFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithBodiesFilter.java
index a8f796622..201e5546d 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithBodiesFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithBodiesFilter.java
@@ -36,4 +36,8 @@ public class MessageWithBodiesFilter extends FlexiblePacketTypeFilter {
return !message.getBodies().isEmpty();
}
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java
index fa29ec497..c484aa2e8 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/MessageWithSubjectFilter.java
@@ -36,4 +36,8 @@ public class MessageWithSubjectFilter extends FlexiblePacketTypeFilter
return message.getSubject() != null;
}
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/NotFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/NotFilter.java
index 3dd76a7f0..76d63ce9c 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/NotFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/NotFilter.java
@@ -18,6 +18,7 @@
package org.jivesoftware.smack.filter;
import org.jivesoftware.smack.packet.Stanza;
+import org.jivesoftware.smack.util.Objects;
/**
* Implements the logical NOT operation on a packet filter. In other words, packets
@@ -35,10 +36,7 @@ public class NotFilter implements PacketFilter {
* @param filter the filter.
*/
public NotFilter(PacketFilter filter) {
- if (filter == null) {
- throw new IllegalArgumentException("Parameter must not be null.");
- }
- this.filter = filter;
+ this.filter = Objects.requireNonNull(filter, "Parameter must not be null.");
}
public boolean accept(Stanza packet) {
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/OrFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/OrFilter.java
index db583c076..b1d96eeef 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/OrFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/OrFilter.java
@@ -17,12 +17,7 @@
package org.jivesoftware.smack.filter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
import org.jivesoftware.smack.packet.Stanza;
-import org.jivesoftware.smack.util.Objects;
/**
* Implements the logical OR operation over two or more packet filters. In
@@ -30,19 +25,14 @@ import org.jivesoftware.smack.util.Objects;
*
* @author Matt Tucker
*/
-public class OrFilter implements PacketFilter {
-
- /**
- * The list of filters.
- */
- private final List filters;
+public class OrFilter extends AbstractListFilter implements PacketFilter {
/**
* Creates an empty OR filter. Filters should be added using the
* {@link #addFilter(PacketFilter)} method.
*/
public OrFilter() {
- filters = new ArrayList();
+ super();
}
/**
@@ -51,24 +41,10 @@ public class OrFilter implements PacketFilter {
* @param filters the filters to add.
*/
public OrFilter(PacketFilter... filters) {
- Objects.requireNonNull(filters, "Parameter must not be null.");
- for(PacketFilter filter : filters) {
- Objects.requireNonNull(filter, "Parameter must not be null.");
- }
- this.filters = new ArrayList(Arrays.asList(filters));
- }
-
- /**
- * Adds a filter to the filter list for the OR operation. A packet
- * will pass the filter if any filter in the list accepts it.
- *
- * @param filter a filter to add to the filter list.
- */
- public void addFilter(PacketFilter filter) {
- Objects.requireNonNull(filter, "Parameter must not be null.");
- filters.add(filter);
+ super(filters);
}
+ @Override
public boolean accept(Stanza packet) {
for (PacketFilter filter : filters) {
if (filter.accept(packet)) {
@@ -78,7 +54,4 @@ public class OrFilter implements PacketFilter {
return false;
}
- public String toString() {
- return filters.toString();
- }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketExtensionFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketExtensionFilter.java
index 0ba17386f..c0deb6183 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketExtensionFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketExtensionFilter.java
@@ -68,4 +68,9 @@ public class PacketExtensionFilter implements PacketFilter {
public boolean accept(Stanza packet) {
return packet.hasExtension(elementName, namespace);
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": element=" + elementName + " namespace=" + namespace;
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketFilter.java
index c71cbe3fe..5aecfa2a2 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketFilter.java
@@ -28,7 +28,7 @@ import org.jivesoftware.smack.packet.Stanza;
* packet filtering by using the {@link org.jivesoftware.smack.filter.AndFilter AndFilter} and
* {@link org.jivesoftware.smack.filter.OrFilter OrFilter} filters. It's also possible to define
* your own filters by implementing this interface. The code example below creates a trivial filter
- * for packets with a specific ID (real code should use {@link PacketIDFilter} instead).
+ * for packets with a specific ID (real code should use {@link StanzaIdFilter} instead).
*
*
* // Use an anonymous inner class to define a packet filter that returns
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketIDFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketIDFilter.java
index 82a2ea904..11796a0ab 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketIDFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketIDFilter.java
@@ -24,7 +24,9 @@ import org.jivesoftware.smack.util.StringUtils;
* Filters for packets with a particular packet ID.
*
* @author Matt Tucker
+ * @deprecated use {@link StanzaIdFilter} instead.
*/
+@Deprecated
public class PacketIDFilter implements PacketFilter {
private final String packetID;
@@ -33,7 +35,9 @@ public class PacketIDFilter implements PacketFilter {
* Creates a new packet ID filter using the specified packet's ID.
*
* @param packet the packet which the ID is taken from.
+ * @deprecated use {@link StanzaIdfilter(Stanza)} instead.
*/
+ @Deprecated
public PacketIDFilter(Stanza packet) {
this(packet.getStanzaId());
}
@@ -42,7 +46,9 @@ public class PacketIDFilter implements PacketFilter {
* Creates a new packet ID filter using the specified packet ID.
*
* @param packetID the packet ID to filter for.
+ * @deprecated use {@link StanzaIdFilter(String)} instead.
*/
+ @Deprecated
public PacketIDFilter(String packetID) {
StringUtils.requireNotNullOrEmpty(packetID, "Packet ID must not be null or empty.");
this.packetID = packetID;
@@ -53,6 +59,6 @@ public class PacketIDFilter implements PacketFilter {
}
public String toString() {
- return "PacketIDFilter by id: " + packetID;
+ return getClass().getSimpleName() + ": id=" + packetID;
}
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java
index 6c57a4071..5a32e784c 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/PacketTypeFilter.java
@@ -53,7 +53,8 @@ public class PacketTypeFilter implements PacketFilter {
return packetType.isInstance(packet);
}
+ @Override
public String toString() {
- return "PacketTypeFilter: " + packetType.getName();
+ return getClass().getSimpleName() + ": " + packetType.getName();
}
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/PresenceTypeFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/PresenceTypeFilter.java
index 045cd2bf8..d67635609 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/PresenceTypeFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/PresenceTypeFilter.java
@@ -18,6 +18,7 @@ package org.jivesoftware.smack.filter;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Presence.Type;
+import org.jivesoftware.smack.util.Objects;
/**
* A filter for Presence types. Returns true only if the stanza is an Presence packet and it matches the type provided in the
@@ -38,11 +39,16 @@ public class PresenceTypeFilter extends FlexiblePacketTypeFilter {
private PresenceTypeFilter(Presence.Type type) {
super(Presence.class);
- this.type = type;
+ this.type = Objects.requireNonNull(type, "type must not be null");
}
@Override
protected boolean acceptSpecific(Presence presence) {
return presence.getType() == type;
}
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": type=" + type;
+ }
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/StanzaIdFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/StanzaIdFilter.java
new file mode 100644
index 000000000..bf123726b
--- /dev/null
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/StanzaIdFilter.java
@@ -0,0 +1,57 @@
+/**
+ *
+ * Copyright 2003-2007 Jive Software.
+ *
+ * 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.filter;
+
+import org.jivesoftware.smack.packet.Stanza;
+import org.jivesoftware.smack.util.StringUtils;
+
+/**
+ * Filters for Stanzas with a particular stanza ID.
+ *
+ * @author Matt Tucker
+ */
+public class StanzaIdFilter implements PacketFilter {
+
+ private final String stanzaId;
+
+ /**
+ * Creates a new stanza ID filter using the specified stanza's ID.
+ *
+ * @param stanza the stanza which the ID is taken from.
+ */
+ public StanzaIdFilter(Stanza stanza) {
+ this(stanza.getStanzaId());
+ }
+
+ /**
+ * Creates a new stanza ID filter using the specified stanza ID.
+ *
+ * @param stanzaID the stanza ID to filter for.
+ */
+ public StanzaIdFilter(String stanzaID) {
+ this.stanzaId = StringUtils.requireNotNullOrEmpty(stanzaID, "Stanza ID must not be null or empty.");
+ }
+
+ public boolean accept(Stanza stanza) {
+ return stanzaId.equals(stanza.getStanzaId());
+ }
+
+ public String toString() {
+ return getClass().getSimpleName() + ": id=" + stanzaId;
+ }
+}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/ThreadFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/ThreadFilter.java
index e053d364b..da1c3d7dd 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/ThreadFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/ThreadFilter.java
@@ -17,7 +17,6 @@
package org.jivesoftware.smack.filter;
-import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.StringUtils;
@@ -26,7 +25,7 @@ import org.jivesoftware.smack.util.StringUtils;
*
* @author Matt Tucker
*/
-public class ThreadFilter implements PacketFilter {
+public class ThreadFilter extends FlexiblePacketTypeFilter implements PacketFilter {
private final String thread;
@@ -40,7 +39,13 @@ public class ThreadFilter implements PacketFilter {
this.thread = thread;
}
- public boolean accept(Stanza packet) {
- return packet instanceof Message && thread.equals(((Message) packet).getThread());
+ @Override
+ protected boolean acceptSpecific(Message message) {
+ return thread.equals(message.getThread());
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": thread=" + thread;
}
}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/filter/ToFilter.java b/smack-core/src/main/java/org/jivesoftware/smack/filter/ToFilter.java
index e0fd2f900..cdbfccaf4 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/filter/ToFilter.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/filter/ToFilter.java
@@ -36,4 +36,8 @@ public class ToFilter implements PacketFilter {
return packetTo.equals(to);
}
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + ": to=" + to;
+ }
}
diff --git a/smack-debug-slf4j/build.gradle b/smack-debug-slf4j/build.gradle
index 4e5a2a65f..43f430dbb 100644
--- a/smack-debug-slf4j/build.gradle
+++ b/smack-debug-slf4j/build.gradle
@@ -5,6 +5,6 @@ Connect your favourite slf4j backend of choice to get output inside of it"""
dependencies {
compile project(':smack-core')
- compile 'org.slf4j:slf4j-api:(1.7,1.8]'
+ compile 'org.slf4j:slf4j-api:[1.7,1.8)'
testCompile project(':smack-core').sourceSets.test.runtimeClasspath
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FaultTolerantNegotiator.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FaultTolerantNegotiator.java
index adae5be86..031092dd9 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FaultTolerantNegotiator.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/FaultTolerantNegotiator.java
@@ -176,11 +176,8 @@ public class FaultTolerantNegotiator extends StreamNegotiator {
this.collector = collector;
}
- public InputStream call() throws XMPPErrorException, InterruptedException, SmackException {
- Stanza streamInitiation = collector.nextResult();
- if (streamInitiation == null) {
- throw new NoResponseException(connection);
- }
+ public InputStream call() throws XMPPErrorException, InterruptedException, NoResponseException, SmackException {
+ Stanza streamInitiation = collector.nextResultOrThrow();
StreamNegotiator negotiator = determineNegotiator(streamInitiation);
return negotiator.negotiateIncomingStream(streamInitiation);
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java
index 1ebf2d614..d574060cd 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/filetransfer/Socks5TransferNegotiator.java
@@ -32,6 +32,7 @@ import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Stanza;
+import org.jivesoftware.smack.util.Objects;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest;
import org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamSession;
@@ -128,14 +129,11 @@ public class Socks5TransferNegotiator extends StreamNegotiator {
*/
private static class BytestreamSIDFilter extends PacketTypeFilter {
- private String sessionID;
+ private final String sessionID;
public BytestreamSIDFilter(String sessionID) {
super(Bytestream.class);
- if (sessionID == null) {
- throw new IllegalArgumentException("StreamID cannot be null");
- }
- this.sessionID = sessionID;
+ this.sessionID = Objects.requireNonNull(sessionID, "SessionID cannot be null");
}
@Override
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java
index d673f9753..c7424949d 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqregister/AccountManager.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.logging.Logger;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.PacketCollector;
@@ -31,7 +32,7 @@ import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
-import org.jivesoftware.smack.filter.PacketIDFilter;
+import org.jivesoftware.smack.filter.StanzaIdFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.iqregister.packet.Registration;
@@ -41,6 +42,9 @@ import org.jivesoftware.smackx.iqregister.packet.Registration;
* @author Matt Tucker
*/
public class AccountManager extends Manager {
+
+ private static final Logger LOGGER = Logger.getLogger(AccountManager.class.getName());
+
private static final Map INSTANCES = new WeakHashMap();
/**
@@ -58,6 +62,35 @@ public class AccountManager extends Manager {
return accountManager;
}
+ private static boolean allowSensitiveOperationOverInsecureConnectionDefault = false;
+
+ /**
+ * The default value used by new account managers for allowSensitiveOperationOverInsecureConnection
.
+ *
+ * @param allow
+ * @see #sensitiveOperationOverInsecureConnection(boolean)
+ * @since 4.1
+ */
+ public static void sensitiveOperationOverInsecureConnectionDefault(boolean allow) {
+ AccountManager.allowSensitiveOperationOverInsecureConnectionDefault = allow;
+ }
+
+ private boolean allowSensitiveOperationOverInsecureConnection = allowSensitiveOperationOverInsecureConnectionDefault;
+
+ /**
+ * Set to true
to allow sensitive operation over insecure connection.
+ *
+ * Set to true to allow sensitive operations like account creation or password changes over an insecure (e.g.
+ * unencrypted) connections.
+ *
+ *
+ * @param allow
+ * @since 4.1
+ */
+ public void sensitiveOperationOverInsecureConnection(boolean allow) {
+ this.allowSensitiveOperationOverInsecureConnection = allow;
+ }
+
private Registration info = null;
/**
@@ -231,6 +264,11 @@ public class AccountManager extends Manager {
*/
public void createAccount(String username, String password, Map attributes)
throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
+ if (!connection().isSecureConnection() && !allowSensitiveOperationOverInsecureConnection) {
+ // TODO throw exception in newer Smack versions
+ LOGGER.warning("Creating account over insecure connection. "
+ + "This will throw an exception in future versions of Smack if AccountManager.sensitiveOperationOverInsecureConnection(true) is not set");
+ }
attributes.put("username", username);
attributes.put("password", password);
Registration reg = new Registration(attributes);
@@ -251,6 +289,11 @@ public class AccountManager extends Manager {
* @throws InterruptedException
*/
public void changePassword(String newPassword) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
+ if (!connection().isSecureConnection() && !allowSensitiveOperationOverInsecureConnection) {
+ // TODO throw exception in newer Smack versions
+ LOGGER.warning("Changing password over insecure connection. "
+ + "This will throw an exception in future versions of Smack if AccountManager.sensitiveOperationOverInsecureConnection(true) is not set");
+ }
Map map = new HashMap();
map.put("username", connection().getUser().getLocalpart().toString());
map.put("password",newPassword);
@@ -298,7 +341,7 @@ public class AccountManager extends Manager {
}
private PacketCollector createPacketCollectorAndSend(IQ req) throws NotConnectedException, InterruptedException {
- PacketCollector collector = connection().createPacketCollectorAndSend(new PacketIDFilter(req.getStanzaId()), req);
+ PacketCollector collector = connection().createPacketCollectorAndSend(new StanzaIdFilter(req.getStanzaId()), req);
return collector;
}
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java
index 6a72a919f..1debbb29a 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqversion/packet/Version.java
@@ -27,26 +27,6 @@ import org.jxmpp.jid.Jid;
* A Version IQ packet, which is used by XMPP clients to discover version information
* about the software running at another entity's JID.
*
- * An example to discover the version of the server:
- *
- * // Request the version from the server.
- * Version versionRequest = new Version();
- * timeRequest.setType(IQ.Type.get);
- * timeRequest.setTo("example.com");
- *
- * // Create a packet collector to listen for a response.
- * PacketCollector collector = con.createPacketCollector(
- * new PacketIDFilter(versionRequest.getStanzaId()));
- *
- * con.sendPacket(versionRequest);
- *
- * // Wait up to 5 seconds for a result.
- * IQ result = (IQ)collector.nextResult(5000);
- * if (result != null && result.getType() == IQ.Type.result) {
- * Version versionResult = (Version)result;
- * // Do something with result...
- * }
- *
* @author Gaston Dombiak
*/
public class Version extends IQ {
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
index 42d961faa..17a170cb1 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
@@ -57,14 +57,15 @@ public class ItemProvider extends PacketExtensionProvider-
String payloadElemName = parser.getName();
String payloadNS = parser.getNamespace();
- if (ProviderManager.getExtensionProvider(payloadElemName, payloadNS) == null)
+ final PacketExtensionProvider extensionProvider = ProviderManager.getExtensionProvider(payloadElemName, payloadNS);
+ if (extensionProvider == null)
{
CharSequence payloadText = PacketParserUtils.parseElement(parser, true);
return new PayloadItem(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText));
}
else
{
- return new PayloadItem(id, node, PacketParserUtils.parsePacketExtension(payloadElemName, payloadNS, parser));
+ return new PayloadItem(id, node, extensionProvider.parse(parser));
}
}
}
diff --git a/smack-extensions/src/test/java/org/jivesoftware/util/Protocol.java b/smack-extensions/src/test/java/org/jivesoftware/util/Protocol.java
index 71fdbc33a..75acff249 100644
--- a/smack-extensions/src/test/java/org/jivesoftware/util/Protocol.java
+++ b/smack-extensions/src/test/java/org/jivesoftware/util/Protocol.java
@@ -51,7 +51,7 @@ import org.jivesoftware.smack.packet.Stanza;
*
* public void methodToTest() {
* Packet packet = new Packet(); // create an XMPP packet
- * PacketCollector collector = connection.createPacketCollector(new PacketIDFilter());
+ * PacketCollector collector = connection.createPacketCollector(new StanzaIdFilter());
* connection.sendPacket(packet);
* Packet reply = collector.nextResult();
* }
diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java
index 13e767f05..64accea3f 100644
--- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java
+++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java
@@ -142,6 +142,11 @@ public class Roster extends Manager {
*/
private final Map> presenceMap = new ConcurrentHashMap<>();
+ /**
+ * Listeners called when the Roster was loaded.
+ */
+ private final Set rosterLoadedListeners = new LinkedHashSet<>();
+
/**
* Mutually exclude roster listener invocation and changing the {@link entries} map. Also used
* to synchronize access to either the roster listeners or the entries map.
@@ -391,6 +396,34 @@ public class Roster extends Manager {
}
}
+ /**
+ * Add a roster loaded listener.
+ *
+ * @param rosterLoadedListener the listener to add.
+ * @return true if the listener was not already added.
+ * @see RosterLoadedListener
+ * @since 4.1
+ */
+ public boolean addRosterLoadedListener(RosterLoadedListener rosterLoadedListener) {
+ synchronized (rosterLoadedListener) {
+ return rosterLoadedListeners.add(rosterLoadedListener);
+ }
+ }
+
+ /**
+ * Remove a roster loaded listener.
+ *
+ * @param rosterLoadedListener the listener to remove.
+ * @return true if the listener was active and got removed.
+ * @see RosterLoadedListener
+ * @since 4.1
+ */
+ public boolean removeRosterLoadedListener(RosterLoadedListener rosterLoadedListener) {
+ synchronized (rosterLoadedListener) {
+ return rosterLoadedListeners.remove(rosterLoadedListener);
+ }
+ }
+
/**
* Creates a new group.
*
@@ -1331,6 +1364,22 @@ public class Roster extends Manager {
}
// Fire event for roster listeners.
fireRosterChangedEvent(addedEntries, updatedEntries, deletedEntries);
+
+ // Call the roster loaded listeners after the roster events have been fired. This is
+ // imporant because the user may call getEntriesAndAddListener() in onRosterLoaded(),
+ // and if the order would be the other way around, the roster listener added by
+ // getEntriesAndAddListener() would be invoked with information that was already
+ // available at the time getEntriesAndAddListenr() was called.
+ try {
+ synchronized (rosterLoadedListeners) {
+ for (RosterLoadedListener rosterLoadedListener : rosterLoadedListeners) {
+ rosterLoadedListener.onRosterLoaded(Roster.this);
+ }
+ }
+ }
+ catch (Exception e) {
+ LOGGER.log(Level.WARNING, "RosterLoadedListener threw exception", e);
+ }
}
}
diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterLoadedListener.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterLoadedListener.java
new file mode 100644
index 000000000..94f08f094
--- /dev/null
+++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterLoadedListener.java
@@ -0,0 +1,38 @@
+/**
+ *
+ * Copyright 2015 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.roster;
+
+/**
+ * Roster loaded listeners are invoked once the {@link Roster} was successfully loaded.
+ *
+ * A common approach is to call
+ * {@link Roster#getEntriesAndAddListener(RosterListener, RosterEntries)} within
+ * {@link #onRosterLoaded(Roster)}, to initialize or update your UI components with the current
+ * roster state.
+ *
+ */
+public interface RosterLoadedListener {
+
+ /**
+ * Called when the Roster was loaded successfully.
+ *
+ * @param roster the Roster that was loaded successfully.
+ */
+ public void onRosterLoaded(Roster roster);
+
+}
diff --git a/smack-resolver-dnsjava/build.gradle b/smack-resolver-dnsjava/build.gradle
index 2e46948bc..9de83e1f5 100644
--- a/smack-resolver-dnsjava/build.gradle
+++ b/smack-resolver-dnsjava/build.gradle
@@ -5,5 +5,5 @@ javax.naming API (e.g. Android)."""
dependencies {
compile project(path: ':smack-core')
- compile 'dnsjava:dnsjava:(2.1,2.2]'
+ compile 'dnsjava:dnsjava:[2.1,2.2)'
}
diff --git a/smack-resolver-minidns/build.gradle b/smack-resolver-minidns/build.gradle
index 49438ee95..812fe8c4b 100644
--- a/smack-resolver-minidns/build.gradle
+++ b/smack-resolver-minidns/build.gradle
@@ -5,6 +5,6 @@ javax.naming API (e.g. Android)."""
dependencies {
compile project(path: ':smack-core')
- compile 'de.measite.minidns:minidns:(0.1,0.2]'
+ compile 'de.measite.minidns:minidns:[0.1,0.2)'
compile "org.jxmpp:jxmpp-util-cache:$jxmppVersion"
}
diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java b/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java
index 95278f3af..43684e299 100644
--- a/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java
+++ b/smack-tcp/src/main/java/org/jivesoftware/smack/sm/StreamManagementException.java
@@ -16,7 +16,11 @@
*/
package org.jivesoftware.smack.sm;
+import java.util.Collections;
+import java.util.List;
+
import org.jivesoftware.smack.SmackException;
+import org.jivesoftware.smack.packet.Stanza;
public abstract class StreamManagementException extends SmackException {
@@ -52,5 +56,59 @@ public abstract class StreamManagementException extends SmackException {
super("Stream IDs do not match. Expected '" + expected + "', but got '" + got + "'");
}
}
+
+ public static class StreamManagementCounterError extends StreamManagementException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ private final long handledCount;
+ private final long previousServerHandledCount;
+ private final long ackedStanzaCount;
+ private final int outstandingStanzasCount;
+ private final List ackedStanzas;
+
+ public StreamManagementCounterError(long handledCount, long previousServerHandlerCount,
+ long ackedStanzaCount,
+ List ackedStanzas) {
+ super(
+ "There was an error regarding the Stream Mangement counters. Server reported "
+ + handledCount
+ + " handled stanzas, which means that the "
+ + ackedStanzaCount
+ + " recently send stanzas by client are now acked by the server. But Smack had only "
+ + ackedStanzas.size()
+ + " to acknowledge. The stanza id of the last acked outstanding stanza is "
+ + (ackedStanzas.isEmpty() ? ""
+ : ackedStanzas.get(ackedStanzas.size() - 1).getStanzaId()));
+ this.handledCount = handledCount;
+ this.previousServerHandledCount = previousServerHandlerCount;
+ this.ackedStanzaCount = ackedStanzaCount;
+ this.outstandingStanzasCount = ackedStanzas.size();
+ this.ackedStanzas = Collections.unmodifiableList(ackedStanzas);
+ }
+
+ public long getHandledCount() {
+ return handledCount;
+ }
+
+ public long getPreviousServerHandledCount() {
+ return previousServerHandledCount;
+ }
+
+ public long getAckedStanzaCount() {
+ return ackedStanzaCount;
+ }
+
+ public int getOutstandingStanzasCount() {
+ return outstandingStanzasCount;
+ }
+
+ public List getAckedStanzas() {
+ return ackedStanzas;
+ }
+ }
}
diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/BundleAndDefer.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/BundleAndDefer.java
new file mode 100644
index 000000000..ad899f9e5
--- /dev/null
+++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/BundleAndDefer.java
@@ -0,0 +1,39 @@
+/**
+ *
+ * Copyright 2015 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 java.util.concurrent.atomic.AtomicBoolean;
+
+
+public class BundleAndDefer {
+
+ private final AtomicBoolean isStopped;
+
+ BundleAndDefer(AtomicBoolean isStopped) {
+ this.isStopped = isStopped;
+ }
+
+ public void stopCurrentBundleAndDefer() {
+ synchronized (isStopped) {
+ if (isStopped.get()) {
+ return;
+ }
+ isStopped.set(true);
+ isStopped.notify();
+ }
+ }
+}
diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/BundleAndDeferCallback.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/BundleAndDeferCallback.java
new file mode 100644
index 000000000..5102b0019
--- /dev/null
+++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/BundleAndDeferCallback.java
@@ -0,0 +1,49 @@
+/**
+ *
+ * Copyright 2015 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;
+
+/**
+ * This callback is used to get the current value of the period in which Smack does bundle and defer
+ * outgoing stanzas.
+ *
+ * Smack will bundle and defer stanzas if the connection is authenticated, the send queue is empty
+ * and if a bundle and defer callback is set, either via
+ * {@link XMPPTCPConnection#setDefaultBundleAndDeferCallback(BundleAndDeferCallback)} or
+ * {@link XMPPTCPConnection#setBundleandDeferCallback(BundleAndDeferCallback)}, and
+ * {@link #getBundleAndDeferMillis(BundleAndDefer)} returns a positive value. In a mobile environment, bundling
+ * and deferring outgoing stanzas may reduce battery consumption. It heavily depends on the
+ * environment, but recommend values for the bundle and defer period range from 20-60 seconds. But
+ * keep in mind that longer periods decrease the realtime aspect of Smack.
+ *
+ *
+ * Smack will invoke the callback when it needs to know the length of the bundle and defer period.
+ * If {@link #getBundleAndDeferMillis(BundleAndDefer)} returns 0 or a negative value, then the
+ * stanzas will send immediately. You can also prematurely abort the bundling of stanzas by calling
+ * {@link BundleAndDefer#stopCurrentBundleAndDefer()}.
+ *
+ */
+public interface BundleAndDeferCallback {
+
+ /**
+ * Return the bundle and defer period used by Smack in milliseconds.
+ *
+ * @param bundleAndDefer used to premature abort bundle and defer.
+ * @return the bundle and defer period in milliseconds.
+ */
+ public int getBundleAndDeferMillis(BundleAndDefer bundleAndDefer);
+
+}
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 7add86c4b..03e580dcd 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
@@ -54,6 +54,7 @@ import org.jivesoftware.smack.sasl.packet.SaslStreamElements.Success;
import org.jivesoftware.smack.sm.SMUtils;
import org.jivesoftware.smack.sm.StreamManagementException;
import org.jivesoftware.smack.sm.StreamManagementException.StreamIdDoesNotMatchException;
+import org.jivesoftware.smack.sm.StreamManagementException.StreamManagementCounterError;
import org.jivesoftware.smack.sm.StreamManagementException.StreamManagementNotEnabledException;
import org.jivesoftware.smack.sm.packet.StreamManagement;
import org.jivesoftware.smack.sm.packet.StreamManagement.AckAnswer;
@@ -126,6 +127,7 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -185,6 +187,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
private final SynchronizationPoint compressSyncPoint = new SynchronizationPoint(
this);
+ private static BundleAndDeferCallback defaultBundleAndDeferCallback;
+
+ private BundleAndDeferCallback bundleAndDeferCallback = defaultBundleAndDeferCallback;
+
private static boolean useSmDefault = false;
private static boolean useSmResumptionDefault = true;
@@ -719,7 +725,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
Socket plain = socket;
// Secure the plain connection
socket = context.getSocketFactory().createSocket(plain,
- plain.getInetAddress().getHostAddress(), plain.getPort(), true);
+ host, plain.getPort(), true);
// Initialize the reader and writer with the new secured version
initReaderAndWriter();
@@ -1272,6 +1278,30 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
if (element == null) {
continue;
}
+
+ // Get a local version of the bundle and defer callback, in case it's unset
+ // between the null check and the method invocation
+ final BundleAndDeferCallback localBundleAndDeferCallback = bundleAndDeferCallback;
+ // If the preconditions are given (e.g. bundleAndDefer callback is set, queue is
+ // empty), then we could wait a bit for further stanzas attempting to decrease
+ // our energy consumption
+ if (localBundleAndDeferCallback != null && isAuthenticated() && queue.isEmpty()) {
+ final AtomicBoolean bundlingAndDeferringStopped = new AtomicBoolean();
+ final int bundleAndDeferMillis = localBundleAndDeferCallback.getBundleAndDeferMillis(new BundleAndDefer(
+ bundlingAndDeferringStopped));
+ if (bundleAndDeferMillis > 0) {
+ long remainingWait = bundleAndDeferMillis;
+ final long waitStart = System.currentTimeMillis();
+ synchronized (bundlingAndDeferringStopped) {
+ while (!bundlingAndDeferringStopped.get() && remainingWait > 0) {
+ bundlingAndDeferringStopped.wait(remainingWait);
+ remainingWait = bundleAndDeferMillis
+ - (System.currentTimeMillis() - waitStart);
+ }
+ }
+ }
+ }
+
Stanza packet = null;
if (element instanceof Stanza) {
packet = (Stanza) element;
@@ -1288,6 +1318,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
writer.flush();
}
try {
+ // It is important the we put the stanza in the unacknowledged stanza
+ // queue before we put it on the wire
unacknowledgedStanzas.put(packet);
}
catch (InterruptedException e) {
@@ -1646,7 +1678,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
return Math.min(clientResumptionTime, serverResumptionTime);
}
- private void processHandledCount(long handledCount) throws NotConnectedException {
+ private void processHandledCount(long handledCount) throws NotConnectedException, StreamManagementCounterError {
long ackedStanzasCount = SMUtils.calculateDelta(handledCount, serverHandledStanzasCount);
final List ackedStanzas = new ArrayList(
handledCount <= Integer.MAX_VALUE ? (int) handledCount
@@ -1655,7 +1687,10 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
Stanza ackedStanza = unacknowledgedStanzas.poll();
// If the server ack'ed a stanza, then it must be in the
// unacknowledged stanza queue. There can be no exception.
- assert(ackedStanza != null);
+ if (ackedStanza == null) {
+ throw new StreamManagementCounterError(handledCount, serverHandledStanzasCount,
+ ackedStanzasCount, ackedStanzas);
+ }
ackedStanzas.add(ackedStanza);
}
@@ -1691,7 +1726,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
String id = ackedStanza.getStanzaId();
if (StringUtils.isNullOrEmpty(id)) {
- return;
+ continue;
}
PacketListener listener = stanzaIdAcknowledgedListeners.remove(id);
if (listener != null) {
@@ -1709,4 +1744,31 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
serverHandledStanzasCount = handledCount;
}
+
+ /**
+ * Set the default bundle and defer callback used for new connections.
+ *
+ * @param defaultBundleAndDeferCallback
+ * @see BundleAndDeferCallback
+ * @since 4.1
+ */
+ public static void setDefaultBundleAndDeferCallback(BundleAndDeferCallback defaultBundleAndDeferCallback) {
+ XMPPTCPConnection.defaultBundleAndDeferCallback = defaultBundleAndDeferCallback;
+ }
+
+ /**
+ * Set the bundle and defer callback used for this connection.
+ *
+ * You can use null
as argument to reset the callback. Outgoing stanzas will then
+ * no longer get deferred.
+ *
+ *
+ * @param bundleAndDeferCallback the callback or null
.
+ * @see BundleAndDeferCallback
+ * @since 4.1
+ */
+ public void setBundleandDeferCallback(BundleAndDeferCallback bundleAndDeferCallback) {
+ this.bundleAndDeferCallback = bundleAndDeferCallback;
+ }
+
}