This is an automated email from the ASF dual-hosted git repository. ralaoui pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mina-vysper.git
The following commit(s) were added to refs/heads/master by this push: new 0a46416 XEP-0059 Result Set Management (#11) 0a46416 is described below commit 0a46416bda4fbb26d111caed055d2b0ecc3f31f2 Author: Réda Housni Alaoui <rala...@apache.org> AuthorDate: Sat Aug 17 09:18:25 2019 +0200 XEP-0059 Result Set Management (#11) --- .../ResultSetManagementModule.java | 57 +++++ .../xep0059_result_set_management/Set.java | 240 +++++++++++++++++++++ .../apache/vysper/xmpp/protocol/NamespaceURIs.java | 2 + .../org/apache/vysper/xmpp/server/XMPPServer.java | 2 + .../ResultSetManagementTest.java | 49 +++++ 5 files changed, 350 insertions(+) diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/ResultSetManagementModule.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/ResultSetManagementModule.java new file mode 100644 index 0000000..eba188e --- /dev/null +++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/ResultSetManagementModule.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.vysper.xmpp.modules.extension.xep0059_result_set_management; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.vysper.xmpp.modules.DefaultDiscoAwareModule; +import org.apache.vysper.xmpp.modules.servicediscovery.management.Feature; +import org.apache.vysper.xmpp.modules.servicediscovery.management.InfoElement; +import org.apache.vysper.xmpp.modules.servicediscovery.management.InfoRequest; +import org.apache.vysper.xmpp.modules.servicediscovery.management.ServerInfoRequestListener; +import org.apache.vysper.xmpp.protocol.NamespaceURIs; + +/** + * @author Réda Housni Alaoui + */ +public class ResultSetManagementModule extends DefaultDiscoAwareModule implements ServerInfoRequestListener { + @Override + public String getName() { + return "XEP-0059 Result Set Management"; + } + + @Override + public String getVersion() { + return "1.0"; + } + + @Override + public List<InfoElement> getServerInfosFor(InfoRequest request) { + if (StringUtils.isNotEmpty(request.getNode())) { + return null; + } + + List<InfoElement> infoElements = new ArrayList<>(); + infoElements.add(new Feature(NamespaceURIs.XEP0059_RESULT_SET_MANAGEMENT)); + return infoElements; + } +} diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/Set.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/Set.java new file mode 100644 index 0000000..680ce68 --- /dev/null +++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/Set.java @@ -0,0 +1,240 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.vysper.xmpp.modules.extension.xep0059_result_set_management; + +import static java.util.Objects.requireNonNull; +import static java.util.Optional.ofNullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; + +import org.apache.vysper.xml.fragment.Attribute; +import org.apache.vysper.xml.fragment.XMLElement; +import org.apache.vysper.xml.fragment.XMLFragment; +import org.apache.vysper.xml.fragment.XMLSemanticError; +import org.apache.vysper.xml.fragment.XMLText; +import org.apache.vysper.xmpp.protocol.NamespaceURIs; + +/** + * The Set element as defined by + * <a href="https://xmpp.org/extensions/xep-0059.html#schema">XEP-0059 Result + * Set Management</a> + * + * @author Réda Housni Alaoui + */ +public class Set { + + private static final String ELEMENT_NAME = "set"; + + private static final String FIRST = "first"; + + private static final String INDEX = "index"; + + private final XMLElement element; + + public Set(XMLElement element) { + if (!ELEMENT_NAME.equals(element.getName())) { + throw new IllegalArgumentException("ResultSetManagement element must be named '" + ELEMENT_NAME + + "' instead of '" + element.getName() + "'"); + } + if (!NamespaceURIs.XEP0059_RESULT_SET_MANAGEMENT.equals(element.getNamespaceURI())) { + throw new IllegalArgumentException("ResultSetManagement element must be bound to namespace uri '" + + NamespaceURIs.XEP0059_RESULT_SET_MANAGEMENT + "' instead of '" + element.getNamespaceURI() + "'"); + } + this.element = element; + } + + public static Builder builder() { + return new Builder(); + } + + public Optional<String> getAfter() throws XMLSemanticError { + return getElementText("after"); + } + + public Optional<String> getBefore() throws XMLSemanticError { + return getElementText("before"); + } + + public OptionalInt getCount() throws XMLSemanticError { + return getElementInt("count"); + } + + public Optional<First> getFirst() throws XMLSemanticError { + return ofNullable(element.getSingleInnerElementsNamed(FIRST)).map(First::new); + } + + public OptionalInt getIndex() throws XMLSemanticError { + return getElementInt(INDEX); + } + + public Optional<String> getLast() throws XMLSemanticError { + return getElementText("last"); + } + + public OptionalInt getMax() throws XMLSemanticError { + return getElementInt("max"); + } + + private Optional<String> getElementText(String elementName) throws XMLSemanticError { + return ofNullable(element.getSingleInnerElementsNamed(elementName)).map(XMLElement::getInnerText) + .map(XMLText::getText); + } + + private OptionalInt getElementInt(String elementName) throws XMLSemanticError { + return getElementText(elementName).map(Integer::parseInt).map(OptionalInt::of).orElse(OptionalInt.empty()); + } + + public static class First { + + private final XMLElement element; + + private First(XMLElement element) { + this.element = element; + } + + private XMLElement element() { + return element; + } + + public String getValue() { + return element.getInnerText().getText(); + } + + public OptionalInt getIndex() { + return ofNullable(element.getAttributeValue(INDEX)).map(Integer::parseInt).map(OptionalInt::of) + .orElse(OptionalInt.empty()); + } + + } + + public static class Builder { + + private String after; + + private String before; + + private Integer count; + + private First first; + + private Integer index; + + private String last; + + private Integer max; + + private Builder() { + + } + + public Builder after(String after) { + this.after = after; + return this; + } + + public Builder before(String before) { + this.before = before; + return this; + } + + public Builder count(Integer count) { + this.count = count; + return this; + } + + public FirstBuilder startFirst() { + return new FirstBuilder(this); + } + + public Builder index(Integer index) { + this.index = index; + return this; + } + + public Builder last(String last) { + this.last = last; + return this; + } + + public Builder max(Integer max) { + this.max = max; + return this; + } + + private XMLFragment createElement(String name, Object innerValue) { + return new XMLElement(null, name, null, Collections.emptyList(), + Collections.singletonList(new XMLText(String.valueOf(innerValue)))); + } + + public Set build() { + List<XMLFragment> innerFragments = new ArrayList<>(); + ofNullable(after).map(innerValue -> createElement("after", innerValue)).ifPresent(innerFragments::add); + ofNullable(before).map(innerValue -> createElement("before", innerValue)).ifPresent(innerFragments::add); + ofNullable(count).map(innerValue -> createElement("count", innerValue)).ifPresent(innerFragments::add); + ofNullable(first).map(First::element).ifPresent(innerFragments::add); + ofNullable(index).map(innerValue -> createElement("index", innerValue)).ifPresent(innerFragments::add); + ofNullable(last).map(innerValue -> createElement("last", innerValue)).ifPresent(innerFragments::add); + ofNullable(max).map(innerValue -> createElement("max", innerValue)).ifPresent(innerFragments::add); + + return new Set(new XMLElement(NamespaceURIs.XEP0059_RESULT_SET_MANAGEMENT, ELEMENT_NAME, null, + Collections.emptyList(), innerFragments)); + } + + } + + public static class FirstBuilder { + + private final Builder builder; + + private String value; + + private Integer index; + + private FirstBuilder(Builder builder) { + this.builder = requireNonNull(builder); + } + + public FirstBuilder value(String value) { + this.value = value; + return this; + } + + public FirstBuilder index(Integer index) { + this.index = index; + return this; + } + + public Builder endFirst() { + List<Attribute> attributes = new ArrayList<>(); + ofNullable(index).map(value -> new Attribute(INDEX, String.valueOf(index))).ifPresent(attributes::add); + List<XMLFragment> innerFragments = new ArrayList<>(); + ofNullable(value).map(XMLText::new).ifPresent(innerFragments::add); + + builder.first = new First(new XMLElement(null, FIRST, null, attributes, innerFragments)); + return builder; + } + + } + +} diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java index 551a99e..56bc78c 100644 --- a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java +++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java @@ -109,4 +109,6 @@ public class NamespaceURIs { public static final String XEP0124_BOSH = "http://jabber.org/protocol/httpbind"; public static final String XEP0133_SERVICE_ADMIN = "http://jabber.org/protocol/admin"; + + public static final String XEP0059_RESULT_SET_MANAGEMENT = "http://jabber.org/protocol/rsm"; } diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java b/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java index f22f66b..8f52c4e 100644 --- a/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java +++ b/server/core/src/main/java/org/apache/vysper/xmpp/server/XMPPServer.java @@ -42,6 +42,7 @@ import org.apache.vysper.xmpp.delivery.StanzaRelayBroker; import org.apache.vysper.xmpp.delivery.inbound.DeliveringExternalInboundStanzaRelay; import org.apache.vysper.xmpp.delivery.inbound.DeliveringInternalInboundStanzaRelay; import org.apache.vysper.xmpp.modules.Module; +import org.apache.vysper.xmpp.modules.extension.xep0059_result_set_management.ResultSetManagementModule; import org.apache.vysper.xmpp.modules.extension.xep0160_offline_storage.OfflineStorageProvider; import org.apache.vysper.xmpp.modules.roster.RosterModule; import org.apache.vysper.xmpp.modules.servicediscovery.ServiceDiscoveryModule; @@ -108,6 +109,7 @@ public class XMPPServer { // add default modules initialModules.add(new ServiceDiscoveryModule()); initialModules.add(new RosterModule()); + initialModules.add(new ResultSetManagementModule()); } public void setSASLMechanisms(List<SASLMechanism> validMechanisms) { diff --git a/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/ResultSetManagementTest.java b/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/ResultSetManagementTest.java new file mode 100644 index 0000000..c52dfd6 --- /dev/null +++ b/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0059_result_set_management/ResultSetManagementTest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.vysper.xmpp.modules.extension.xep0059_result_set_management; + +import static org.junit.Assert.assertEquals; + +import org.apache.vysper.xml.fragment.XMLSemanticError; +import org.junit.Test; + +/** + * @author Réda Housni Alaoui + */ +public class ResultSetManagementTest { + + @Test + public void parse() throws XMLSemanticError { + Set tested = Set.builder().after("after-value").before("before-value").count(5) + .index(10).last("last-value").max(15).startFirst().index(20).value("first-value").endFirst().build(); + + assertEquals("after-value", tested.getAfter().get()); + assertEquals("before-value", tested.getBefore().get()); + assertEquals(5, tested.getCount().getAsInt()); + assertEquals(10, tested.getIndex().getAsInt()); + assertEquals("last-value", tested.getLast().get()); + assertEquals(15, tested.getMax().getAsInt()); + + Set.First first = tested.getFirst().get(); + assertEquals("first-value", first.getValue()); + assertEquals(20, first.getIndex().getAsInt()); + } + +} \ No newline at end of file