diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md
index f0816bf66..a65ebe861 100644
--- a/documentation/extensions/index.md
+++ b/documentation/extensions/index.md
@@ -36,6 +36,7 @@ Smack Extensions and currently supported XEPs by Smack (smack-extensions)
| Ad-Hoc Commands | [XEP-0050](http://xmpp.org/extensions/xep-0049.html) | Advertising and executing application-specific commands. |
| vcard-temp | [XEP-0054](http://xmpp.org/extensions/xep-0049.html) | The vCard-XML format currently in use. |
| Jabber Search | [XEP-0055](http://xmpp.org/extensions/xep-0055.html) | Search information repositories on the XMPP network. |
+| Result Set Management | [XEP-0059](http://xmpp.org/extensions/xep-0059.html) | Page through and otherwise manage the receipt of large result sets |
| [PubSub](pubsub.html) | [XEP-0060](http://xmpp.org/extensions/xep-0060.html) | Generic publish and subscribe functionality. |
| SOCKS5 Bytestrams | [XEP-0065](http://xmpp.org/extensions/xep-0065.html) | Out-of-band bytestream between any two XMPP entities. |
| [XHTML-IM](xhtml.html) | [XEP-0071](http://xmpp.org/extensions/xep-0071.html) | Allows send and receiving formatted messages using XHTML. |
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/Packet.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/Packet.java
index 4311dcf32..3a88e0a16 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/packet/Packet.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/Packet.java
@@ -17,6 +17,7 @@
package org.jivesoftware.smack.packet;
+import org.jivesoftware.smack.util.PacketUtil;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.XmlStringBuilder;
@@ -232,19 +233,11 @@ public abstract class Packet extends TopLevelStreamElement {
* @param namespace the XML element namespace of the packet extension.
* @return the extension, or null if it doesn't exist.
*/
- @SuppressWarnings("unchecked")
public PE getExtension(String elementName, String namespace) {
if (namespace == null) {
return null;
}
- for (PacketExtension ext : packetExtensions) {
- if ((elementName == null || elementName.equals(ext.getElementName()))
- && namespace.equals(ext.getNamespace()))
- {
- return (PE) ext;
- }
- }
- return null;
+ return PacketUtil.packetExtensionfromCollection(packetExtensions, elementName, namespace);
}
/**
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java
new file mode 100644
index 000000000..854d30d34
--- /dev/null
+++ b/smack-core/src/main/java/org/jivesoftware/smack/util/PacketUtil.java
@@ -0,0 +1,38 @@
+/**
+ *
+ * Copyright © 2014 Florian Schmaus
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smack.util;
+
+import java.util.Collection;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+
+public class PacketUtil {
+
+ @SuppressWarnings("unchecked")
+ public static PE packetExtensionfromCollection(
+ Collection collection, String element,
+ String namespace) {
+ for (PacketExtension packetExtension : collection) {
+ if ((element == null || packetExtension.getElementName().equals(
+ element))
+ && packetExtension.getNamespace().equals(namespace)) {
+ return (PE) packetExtension;
+ }
+ }
+ return null;
+ }
+}
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java
index b804c7031..0264abbda 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/util/ParserUtils.java
@@ -16,6 +16,7 @@
*/
package org.jivesoftware.smack.util;
+import java.io.IOException;
import java.util.Locale;
import org.xmlpull.v1.XmlPullParser;
@@ -77,6 +78,11 @@ public class ParserUtils {
}
}
+ public static int getIntegerFromNextText(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String intString = parser.nextText();
+ return Integer.valueOf(intString);
+ }
+
public static Long getLongAttribute(XmlPullParser parser, String name) {
String valueString = parser.getAttributeValue("", name);
if (valueString == null)
diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java
index 88227e67a..aed38f9cc 100644
--- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java
+++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmlStringBuilder.java
@@ -86,6 +86,13 @@ public class XmlStringBuilder implements Appendable, CharSequence {
return this;
}
+ public XmlStringBuilder optIntElement(String name, int value) {
+ if (value >= 0) {
+ element(name, String.valueOf(value));
+ }
+ return this;
+ }
+
public XmlStringBuilder halfOpenElement(String name) {
sb.append('<').append(name);
return this;
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java
index b4b565703..b667729a0 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/PubSubProvider.java
@@ -45,7 +45,7 @@ public class PubSubProvider implements IQProvider
if (eventType == XmlPullParser.START_TAG)
{
- PacketExtension ext = PacketParserUtils.parsePacketExtension(parser.getName(), namespace, parser);
+ PacketExtension ext = PacketParserUtils.parsePacketExtension(parser.getName(), parser.getNamespace(), parser);
if (ext != null)
{
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java
new file mode 100644
index 000000000..afbd614f7
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/RSMManager.java
@@ -0,0 +1,57 @@
+/**
+ *
+ * Copyright © 2014 Florian Schmaus
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smackx.rsm;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.PacketUtil;
+import org.jivesoftware.smackx.rsm.packet.RSMSet;
+import org.jivesoftware.smackx.rsm.packet.RSMSet.PageDirection;
+
+public class RSMManager {
+
+ Collection page(int max) {
+ List packetExtensions = new LinkedList();
+ packetExtensions.add(new RSMSet(max));
+ return packetExtensions;
+ }
+
+ Collection contiunePage(int max, Collection returnedExtensions) {
+ return continuePage(max, returnedExtensions, null);
+ }
+
+ Collection continuePage(int max,
+ Collection returnedExtensions,
+ Collection additionalExtensions) {
+ if (returnedExtensions == null) {
+ throw new IllegalArgumentException("returnedExtensions must no be null");
+ }
+ if (additionalExtensions == null) {
+ additionalExtensions = new LinkedList();
+ }
+ RSMSet resultRsmSet = PacketUtil.packetExtensionfromCollection(returnedExtensions, RSMSet.ELEMENT, RSMSet.NAMESPACE);
+ if (resultRsmSet == null) {
+ throw new IllegalArgumentException("returnedExtensions did not contain a RSMset");
+ }
+ RSMSet continePageRsmSet = new RSMSet(max, resultRsmSet.getLast(), PageDirection.after);
+ additionalExtensions.add(continePageRsmSet);
+ return additionalExtensions;
+ }
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/packet/RSMSet.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/packet/RSMSet.java
new file mode 100644
index 000000000..8c9f88c18
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/packet/RSMSet.java
@@ -0,0 +1,145 @@
+/**
+ *
+ * Copyright © 2014 Florian Schmaus
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smackx.rsm.packet;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.util.XmlStringBuilder;
+
+public class RSMSet implements PacketExtension {
+
+ public static final String ELEMENT = "set";
+ public static final String NAMESPACE = "http://jabber.org/protocol/rsm";
+
+ private final String after;
+ private final String before;
+ private final int count;
+ private final int index;
+ private final String last;
+ private final int max;
+ private final String firstString;
+ private final int firstIndex;
+
+ public static enum PageDirection {
+ before,
+ after;
+ }
+
+ public RSMSet(int max) {
+ this(max, -1);
+ }
+
+ public RSMSet(int max, int index) {
+ this(null, null, -1, index, null, max, null, -1);
+ }
+
+ public RSMSet(int max, String item, PageDirection pageDirection) {
+ switch (pageDirection) {
+ case before:
+ this.before = item;
+ this.after = null;
+ break;
+ case after:
+ this.before = null;
+ this.after = item;
+ break;
+ default:
+ throw new AssertionError();
+ }
+ this.count = -1;
+ this.index = -1;
+ this.last = null;
+ this.max = max;
+ this.firstString = null;
+ this.firstIndex = -1;
+ }
+
+ public RSMSet(String after, String before, int count, int index,
+ String last, int max, String firstString, int firstIndex) {
+ this.after = after;
+ this.before = before;
+ this.count = count;
+ this.index = index;
+ this.last = last;
+ this.max = max;
+ this.firstString = firstString;
+ this.firstIndex = firstIndex;
+ }
+
+ public String getAfter() {
+ return after;
+ }
+
+ public String getBefore() {
+ return before;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public String getLast() {
+ return last;
+ }
+
+ public int getMax() {
+ return max;
+ }
+
+ public String getFirst() {
+ return firstString;
+ }
+
+ public int getFirstIndex() {
+ return firstIndex;
+ }
+
+ @Override
+ public String getElementName() {
+ return ELEMENT;
+ }
+
+ @Override
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ @Override
+ public XmlStringBuilder toXML() {
+ XmlStringBuilder xml = new XmlStringBuilder(this);
+ xml.rightAngleBracket();
+ xml.optElement("after", after);
+ xml.optElement("before", before);
+ xml.optIntElement("count", count);
+ if (firstString != null) {
+ xml.halfOpenElement("first");
+ xml.optIntAttribute("index", firstIndex);
+ xml.rightAngleBracket();
+ xml.append(firstString);
+ xml.closeElement("first");
+ }
+ xml.optIntElement("index", index);
+ xml.optElement("last", last);
+ xml.optIntElement("max", max);
+ xml.closeElement(this);
+ return xml;
+ }
+
+}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/provider/RSMSetProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/provider/RSMSetProvider.java
new file mode 100644
index 000000000..1a57f33bd
--- /dev/null
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/rsm/provider/RSMSetProvider.java
@@ -0,0 +1,82 @@
+/**
+ *
+ * Copyright © 2014 Florian Schmaus
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smackx.rsm.provider;
+
+import org.jivesoftware.smack.packet.PacketExtension;
+import org.jivesoftware.smack.provider.PacketExtensionProvider;
+import org.jivesoftware.smack.util.ParserUtils;
+import org.jivesoftware.smackx.rsm.packet.RSMSet;
+import org.xmlpull.v1.XmlPullParser;
+
+public class RSMSetProvider implements PacketExtensionProvider {
+
+ @Override
+ public PacketExtension parseExtension(XmlPullParser parser)
+ throws Exception {
+ int initialDepth = parser.getDepth();
+
+ String after = null;
+ String before = null;
+ int count = -1;
+ int index = -1;
+ String last = null;
+ int max = -1;
+ String firstString = null;
+ int firstIndex = -1;
+
+ outerloop: while (true) {
+ int event = parser.next();
+ switch (event) {
+ case XmlPullParser.START_TAG:
+ String name = parser.getName();
+ switch (name) {
+ case "after":
+ after = parser.nextText();
+ break;
+ case "before":
+ before = parser.nextText();
+ break;
+ case "count":
+ count = ParserUtils.getIntegerFromNextText(parser);
+ break;
+ case "first":
+ firstIndex = ParserUtils.getIntegerAttribute(parser,
+ "index", -1);
+ firstString = parser.nextText();
+ break;
+ case "index":
+ index = ParserUtils.getIntegerFromNextText(parser);
+ break;
+ case "last":
+ last = parser.nextText();
+ break;
+ case "max":
+ max = ParserUtils.getIntegerFromNextText(parser);
+ break;
+ }
+ break;
+ case XmlPullParser.END_TAG:
+ if (parser.getDepth() == initialDepth) {
+ break outerloop;
+ }
+ }
+ }
+ return new RSMSet(after, before, count, index, last, max, firstString,
+ firstIndex);
+ }
+
+}
diff --git a/smack-extensions/src/main/resources/org.jivesoftware.smackx/extensions.providers b/smack-extensions/src/main/resources/org.jivesoftware.smackx/extensions.providers
index 1eb277f5e..2d4d08994 100644
--- a/smack-extensions/src/main/resources/org.jivesoftware.smackx/extensions.providers
+++ b/smack-extensions/src/main/resources/org.jivesoftware.smackx/extensions.providers
@@ -474,4 +474,11 @@
http://jabber.org/features/iq-register
org.jivesoftware.smackx.iqregister.provider.RegistrationStreamFeatureProvider
+
+
+
+ set
+ http://jabber.org/protocol/rsm
+ org.jivesoftware.smackx.rsm.provider.RSMSetProvider
+
diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/rsm/provider/RSMSetProviderTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/rsm/provider/RSMSetProviderTest.java
new file mode 100644
index 000000000..417cacf0f
--- /dev/null
+++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/rsm/provider/RSMSetProviderTest.java
@@ -0,0 +1,61 @@
+/**
+ *
+ * Copyright © 2014 Florian Schmaus
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smackx.rsm.provider;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.jivesoftware.smack.packet.IQ;
+import org.jivesoftware.smack.util.PacketParserUtils;
+import org.jivesoftware.smackx.InitExtensions;
+import org.jivesoftware.smackx.rsm.packet.RSMSet;
+import org.junit.Test;
+
+public class RSMSetProviderTest extends InitExtensions {
+
+ @Test
+ public void testRsmSetProvider() throws Exception {
+ // @formatter:off
+ final String rsmset =
+ ""
+ + ""
+ + ""
+ + "aftervalue"
+ + "beforevalue"
+ + "1"
+ + "foo@bar.com"
+ + "3"
+ + "lastvalue"
+ + "4"
+ + ""
+ + ""
+ + "";
+ // @formatter:on
+
+ IQ iqWithRsm = (IQ) PacketParserUtils.parseStanza(rsmset);
+ RSMSet rsm = (RSMSet) iqWithRsm.getExtension(RSMSet.ELEMENT, RSMSet.NAMESPACE);
+ assertNotNull(rsm);
+ assertEquals("aftervalue", rsm.getAfter());
+ assertEquals("beforevalue", rsm.getBefore());
+ assertEquals(1, rsm.getCount());
+ assertEquals(2, rsm.getFirstIndex());
+ assertEquals("foo@bar.com", rsm.getFirst());
+ assertEquals(3, rsm.getIndex());
+ assertEquals("lastvalue", rsm.getLast());
+ assertEquals(4, rsm.getMax());
+ }
+}