From e3ec422071d2503f69ab852fdd3a49944a6fc755 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 12 Jun 2019 22:30:56 +0200 Subject: [PATCH 01/14] Try to lookup QNAME first in XmppElementUtil.getQNameFor() --- .../smack/util/XmppElementUtil.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java index caabf8e89..492b551c6 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/XmppElementUtil.java @@ -16,13 +16,30 @@ */ package org.jivesoftware.smack.util; +import java.util.logging.Logger; + import javax.xml.namespace.QName; import org.jivesoftware.smack.packet.FullyQualifiedElement; public class XmppElementUtil { + public static final Logger LOGGER = Logger.getLogger(XmppElementUtil.class.getName()); + public static QName getQNameFor(Class fullyQualifiedElement) { + try { + Object qnameObject = fullyQualifiedElement.getField("QNAME").get(null); + if (QName.class.isAssignableFrom(qnameObject.getClass())) { + return (QName) qnameObject; + } + LOGGER.warning("The QNAME field of " + fullyQualifiedElement + " is not of type QNAME."); + } catch (NoSuchFieldException e) { + LOGGER.finer("The class " + fullyQualifiedElement + " has no static QNAME field. Consider adding one."); + // Proceed to fallback strategy. + } catch (IllegalArgumentException | IllegalAccessException | SecurityException e) { + throw new IllegalArgumentException(e); + } + String element, namespace; try { element = (String) fullyQualifiedElement.getField("ELEMENT").get(null); From ef88bb17d0cbd5e0cb7b38d618e08230e3ce2179 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 12 Jun 2019 22:31:29 +0200 Subject: [PATCH 02/14] Disallow empty string as node in DiscoverInfo --- .../java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java index 374f8bdbb..d5b814fd1 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/disco/packet/DiscoverInfo.java @@ -203,7 +203,7 @@ public class DiscoverInfo extends IQ implements TypedCloneable { * @param node the node attribute that supplements the 'jid' attribute */ public void setNode(String node) { - this.node = node; + this.node = StringUtils.requireNullOrNotEmpty(node, "The node can not be the empty string"); } /** From a3f6fa65a4061d03348d98712f5f14610ff4f87c Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 12 Jun 2019 22:31:55 +0200 Subject: [PATCH 03/14] Disallow null or empty string in PubSubManager.getNode(String) --- .../main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java index 2904e0392..a65872cae 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/PubSubManager.java @@ -37,6 +37,7 @@ import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.StanzaError; import org.jivesoftware.smack.packet.StanzaError.Condition; +import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.packet.DiscoverInfo; @@ -268,6 +269,7 @@ public final class PubSubManager extends Manager { * @throws NotAPubSubNodeException */ public Node getNode(String id) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotAPubSubNodeException { + StringUtils.requireNotNullNorEmpty(id, "The node ID can not be null or the empty string"); Node node = nodeMap.get(id); if (node == null) { From 01289e96829ffb034e3dff45c0a77e7617945e7a Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 12 Jun 2019 22:32:24 +0200 Subject: [PATCH 04/14] Add support for XEP-0315: Data Forms XML Element Fixes SMACK-872. --- documentation/extensions/index.md | 1 + .../DataFormsXmlElementManager.java | 28 +++++++ .../element/DataFormsXmlElement.java | 74 +++++++++++++++++++ .../xmlelement/element/package-info.java | 21 ++++++ .../smackx/xmlelement/package-info.java | 21 ++++++ .../provider/DataFormsXmlElementProvider.java | 54 ++++++++++++++ .../xmlelement/provider/package-info.java | 21 ++++++ .../experimental.xml | 1 + 8 files changed, 221 insertions(+) create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/DataFormsXmlElementManager.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/DataFormsXmlElement.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/package-info.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/package-info.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/DataFormsXmlElementProvider.java create mode 100644 smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/package-info.java diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md index 527c0dd10..184026eab 100644 --- a/documentation/extensions/index.md +++ b/documentation/extensions/index.md @@ -86,6 +86,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental |-----------------------------------------------------------|--------------------------------------------------------|-----------|-------------------------------------------------------------------------------------------------------------------------| | Message Carbons | [XEP-0280](https://xmpp.org/extensions/xep-0280.html) | n/a | Keep all IM clients for a user engaged in a conversation, by carbon-copy outbound messages to all interested resources. | | [Message Archive Management](mam.md) | [XEP-0313](https://xmpp.org/extensions/xep-0313.html) | n/a | Query and control an archive of messages stored on a server. | +| Data Forms XML Element | [XEP-0315](https://xmpp.org/extensions/xep-0315.html) | n/a | Allows to include XML-data in XEP-0004 data forms. | | [Internet of Things - Sensor Data](iot.md) | [XEP-0323](https://xmpp.org/extensions/xep-0323.html) | n/a | Sensor data interchange over XMPP. | | [Internet of Things - Provisioning](iot.md) | [XEP-0324](https://xmpp.org/extensions/xep-0324.html) | n/a | Provisioning, access rights and user privileges for the Internet of Things. | | [Internet of Things - Control](iot.md) | [XEP-0325](https://xmpp.org/extensions/xep-0325.html) | n/a | Describes how to control devices or actuators in an XMPP-based sensor network. | diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/DataFormsXmlElementManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/DataFormsXmlElementManager.java new file mode 100644 index 000000000..35f9e0c43 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/DataFormsXmlElementManager.java @@ -0,0 +1,28 @@ +/** + * + * 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.smackx.xmlelement; + +import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProviderManager; +import org.jivesoftware.smackx.xmlelement.provider.DataFormsXmlElementProvider; + +public class DataFormsXmlElementManager { + + static { + FormFieldChildElementProviderManager.addFormFieldChildElementProvider(new DataFormsXmlElementProvider()); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/DataFormsXmlElement.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/DataFormsXmlElement.java new file mode 100644 index 000000000..a23296e9c --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/DataFormsXmlElement.java @@ -0,0 +1,74 @@ +/** + * + * 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.smackx.xmlelement.element; + +import javax.xml.namespace.QName; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.FormFieldChildElement; + +public class DataFormsXmlElement implements FormFieldChildElement { + + public static final String ELEMENT = "wrapper"; + + public static final String NAMESPACE = "urn:xmpp:xml-element"; + + public static final QName QNAME = new QName(NAMESPACE, ELEMENT); + + private final StandardExtensionElement payload; + + public DataFormsXmlElement(StandardExtensionElement payload) { + this.payload = payload; + } + + @Override + public QName getQName() { + return QNAME; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public String getNamespace() { + return NAMESPACE; + } + + @Override + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment); + if (payload == null) { + return xml.closeEmptyElement(); + } + + xml.rightAngleBracket(); + + xml.append(payload.toXML()); + + xml.closeElement(this); + return xml; + } + + public static DataFormsXmlElement from(FormField formField) { + return (DataFormsXmlElement) formField.getFormFieldChildElement(QNAME); + } +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/package-info.java new file mode 100644 index 000000000..f053e6f17 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/element/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Element classes for XEP-0315: Data Forms XML Element. + */ +package org.jivesoftware.smackx.xmlelement.element; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/package-info.java new file mode 100644 index 000000000..0dcf542d5 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Smacks implementation of XEP-0315: Data Forms XML Element. + */ +package org.jivesoftware.smackx.xmlelement; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/DataFormsXmlElementProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/DataFormsXmlElementProvider.java new file mode 100644 index 000000000..4de486db2 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/DataFormsXmlElementProvider.java @@ -0,0 +1,54 @@ +/** + * + * 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.smackx.xmlelement.provider; + +import java.io.IOException; + +import javax.xml.namespace.QName; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.parsing.SmackParsingException; +import org.jivesoftware.smack.parsing.StandardExtensionElementProvider; +import org.jivesoftware.smack.xml.XmlPullParser; +import org.jivesoftware.smack.xml.XmlPullParserException; +import org.jivesoftware.smackx.xdata.provider.FormFieldChildElementProvider; +import org.jivesoftware.smackx.xmlelement.element.DataFormsXmlElement; + +public class DataFormsXmlElementProvider extends FormFieldChildElementProvider { + + @Override + public QName getQName() { + return DataFormsXmlElement.QNAME; + } + + @Override + public DataFormsXmlElement parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment) + throws IOException, XmlPullParserException, SmackParsingException { + XmlPullParser.TagEvent tagEvent = parser.nextTag(); + + final StandardExtensionElement standardExtensionElement; + if (tagEvent == XmlPullParser.TagEvent.START_ELEMENT) { + standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); + } else { + standardExtensionElement = null; + } + + return new DataFormsXmlElement(standardExtensionElement); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/package-info.java new file mode 100644 index 000000000..a41a0ae11 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/xmlelement/provider/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Provider classes for XEP-0315: Data Forms XML Element. + */ +package org.jivesoftware.smackx.xmlelement.provider; diff --git a/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.xml b/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.xml index 8a73c804f..347a698f3 100644 --- a/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.xml +++ b/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.xml @@ -7,5 +7,6 @@ org.jivesoftware.smackx.httpfileupload.HttpFileUploadManager org.jivesoftware.smackx.eme.ExplicitMessageEncryptionManager org.jivesoftware.smackx.sid.StableUniqueStanzaIdManager + org.jivesoftware.smackx.xmlelement.DataFormsXmlElementManager From 870e6c674a2a8a1a70160317f1093572ab342731 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 4 Jul 2019 15:47:46 +0200 Subject: [PATCH 05/14] Make ExceptionUtil.getStackTrace(Throwable) null safe --- .../main/java/org/jivesoftware/smack/util/ExceptionUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/ExceptionUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/ExceptionUtil.java index 1c282381a..70f82a0b6 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/util/ExceptionUtil.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/ExceptionUtil.java @@ -22,6 +22,10 @@ import java.io.StringWriter; public class ExceptionUtil { public static String getStackTrace(Throwable throwable) { + if (throwable == null) { + return null; + } + StringWriter stringWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(stringWriter); From 1b5a264d52a24a7a60b42963e1c6eafb0cf5e9df Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 4 Jul 2019 15:48:07 +0200 Subject: [PATCH 06/14] Add assert to IQ.initializeAsResultFor(IQ) This method is not meant to be used to be invoked with the identity. --- smack-core/src/main/java/org/jivesoftware/smack/packet/IQ.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/packet/IQ.java b/smack-core/src/main/java/org/jivesoftware/smack/packet/IQ.java index 322890fa7..aeb835351 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/packet/IQ.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/packet/IQ.java @@ -261,6 +261,8 @@ public abstract class IQ extends Stanza { } protected final void initializeAsResultFor(IQ request) { + assert this != request; + if (!(request.getType() == Type.get || request.getType() == Type.set)) { throw new IllegalArgumentException( "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML()); From f3b856c80bd04bc088d91d369be89e0ef964cad8 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 4 Jul 2019 15:49:47 +0200 Subject: [PATCH 07/14] Improve shouldFailIfInitiatorCannotConnectToSocks5Proxy() unit test If run in parallel with other unit tests, especially onces that open up a proxy, this test could fail, because another unit test actually had an proxy running on the very address this unit test assumes to be no proxy running. We now use an IP address from RFC 5737's TEST-NET-1 address block, which should never be available. --- .../socks5/Socks5ByteStreamManagerTest.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ByteStreamManagerTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ByteStreamManagerTest.java index 0564f29f2..0b297c1ad 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ByteStreamManagerTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/bytestreams/socks5/Socks5ByteStreamManagerTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.mock; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.ConnectException; import java.net.InetAddress; import java.net.ServerSocket; import java.util.List; @@ -521,17 +520,24 @@ public class Socks5ByteStreamManagerTest { * @throws InterruptedException * @throws SmackException * @throws XMPPException + * @throws XmppStringprepException */ @Test public void shouldFailIfInitiatorCannotConnectToSocks5Proxy() - throws SmackException, InterruptedException, XMPPException { + throws SmackException, InterruptedException, XMPPException, XmppStringprepException { final Protocol protocol = new Protocol(); final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID); final String sessionID = "session_id_shouldFailIfInitiatorCannotConnectToSocks5Proxy"; + // TODO: The following two variables should be named initatorProxyJid and initiatorProxyAddress. + final DomainBareJid proxyJID = JidCreate.domainBareFrom("s5b-proxy.initiator.org"); + // Use an TEST-NET-1 address from RFC 5737 to act as black hole. + final String proxyAddress = "192.0.2.1"; + // get Socks5ByteStreamManager for connection Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection); byteStreamManager.setAnnounceLocalStreamHost(false); + byteStreamManager.setProxyConnectionTimeout(3000); /** * create responses in the order they should be queried specified by the XEP-0065 @@ -602,8 +608,9 @@ public class Socks5ByteStreamManagerTest { // initiator can't connect to proxy because it is not running protocol.verifyAll(); - Throwable actualCause = e.getCause().getCause(); - assertEquals("Unexpected throwable: " + actualCause + '.' + ExceptionUtil.getStackTrace(actualCause), ConnectException.class, actualCause.getClass()); + Throwable actualCause = e.getCause(); + assertEquals("Unexpected throwable: " + actualCause + '.' + ExceptionUtil.getStackTrace(actualCause), + TimeoutException.class, actualCause.getClass()); } /** From df5899e72bbbdc83513a4570cb0ff04763303938 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 4 Jul 2019 15:51:28 +0200 Subject: [PATCH 08/14] Introduce SmackConfiguration.SMACK_URL(_STRING) --- .../org/jivesoftware/smack/SmackConfiguration.java | 14 ++++++++++++++ .../java/org/jivesoftware/smack/packet/TestIQ.java | 4 +++- .../smackx/caps/EntityCapsManager.java | 3 ++- .../smackx/iqprivate/PrivateDataManager.java | 3 ++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java index 6f06e4d33..f7957cccb 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java @@ -17,6 +17,8 @@ package org.jivesoftware.smack; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -50,6 +52,18 @@ import org.jivesoftware.smack.util.Objects; */ public final class SmackConfiguration { + public static final String SMACK_URL_STRING = "https://igniterealtime.org/projects/smack"; + + public static final URL SMACK_URL; + + static { + try { + SMACK_URL = new URL(SMACK_URL_STRING); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } + } + private static int defaultPacketReplyTimeout = 5000; private static int packetCollectorSize = 5000; diff --git a/smack-core/src/test/java/org/jivesoftware/smack/packet/TestIQ.java b/smack-core/src/test/java/org/jivesoftware/smack/packet/TestIQ.java index 84aed089d..c222035e1 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/packet/TestIQ.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/packet/TestIQ.java @@ -16,10 +16,12 @@ */ package org.jivesoftware.smack.packet; +import org.jivesoftware.smack.SmackConfiguration; + public class TestIQ extends SimpleIQ { public TestIQ() { - this("https://igniterealtime.org/projects/smack", "test-iq"); + this(SmackConfiguration.SMACK_URL_STRING, "test-iq"); } public TestIQ(String element, String namespace) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java index d75cb7036..5fe1e0260 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java @@ -36,6 +36,7 @@ import java.util.logging.Logger; import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.StanzaListener; @@ -92,7 +93,7 @@ public final class EntityCapsManager extends Manager { */ private static final String DEFAULT_HASH = StringUtils.SHA1; - private static String DEFAULT_ENTITY_NODE = "http://www.igniterealtime.org/projects/smack"; + private static String DEFAULT_ENTITY_NODE = SmackConfiguration.SMACK_URL_STRING; protected static EntityCapsPersistentCache persistentCache; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/PrivateDataManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/PrivateDataManager.java index a4a758e93..7a1149ea6 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/PrivateDataManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/iqprivate/PrivateDataManager.java @@ -25,6 +25,7 @@ import java.util.WeakHashMap; import javax.xml.namespace.QName; import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPConnection; @@ -193,7 +194,7 @@ public final class PrivateDataManager extends Manager { @Override public String getNamespace() { - return "https://igniterealtime.org/projects/smack/"; + return SmackConfiguration.SMACK_URL_STRING; } @Override From aec648c34b81ba39baa57ac8b75936ef2a41ba4f Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 4 Jul 2019 16:45:28 +0200 Subject: [PATCH 09/14] Improve PubSubIntegrationTest Ensuring that the node has no items in transientNotificationOnlyNodeWithoutItemTest() is not right. An implementation is free to create an item with an ID and return it. The item is just not guaranteed to be persistent. Also add a dummy payload to transientNotificationOnlyNodeWithItemTest(). --- smack-integration-test/build.gradle | 2 ++ .../smackx/pubsub/PubSubIntegrationTest.java | 31 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/smack-integration-test/build.gradle b/smack-integration-test/build.gradle index aa6ade5ed..9be816aaf 100644 --- a/smack-integration-test/build.gradle +++ b/smack-integration-test/build.gradle @@ -23,6 +23,8 @@ dependencies { // (ab)uses @Before from org.junit compile "org.junit.vintage:junit-vintage-engine:$junitVersion" compile 'junit:junit:4.12' + // Add Junit 5 API for e.g. assertThrows() + implementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testCompile "org.jxmpp:jxmpp-jid:$jxmppVersion:tests" } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java index 92ca0c643..8b7e04e86 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java @@ -18,14 +18,13 @@ package org.jivesoftware.smackx.pubsub; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.List; +import static org.junit.jupiter.api.Assertions.assertThrows; +import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.packet.StandardExtensionElement; import org.jivesoftware.smack.packet.StanzaError; import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; @@ -69,8 +68,6 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest { try { LeafNode leafNode = (LeafNode) node; leafNode.publish(); - List items = leafNode.getItems(); - assertTrue(items.isEmpty()); } finally { pubSubManagerOne.deleteNode(nodename); @@ -95,6 +92,7 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest { public void transientNotificationOnlyNodeWithItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-transient-notificationonly-withitem-nodename-" + testRunId; final String itemId = "sinttest-transient-notificationonly-withitem-itemid-" + testRunId; + ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); // Configure the node as "Notification-Only Node". @@ -102,12 +100,23 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest { // Configure the node as "transient" (set persistent_items to 'false') config.setPersistentItems(false); Node node = pubSubManagerOne.createNode(nodename, config); + + // Add a dummy payload. If there is no payload, but just an item ID, then ejabberd will *not* return an error, + // which I believe to be non-compliant behavior (although, granted, the XEP is not very clear about this). A user + // which sends an empty item with ID to an node that is configured to be notification-only and transient probably + // does something wrong, as the item's ID will never appear anywhere. Hence it would be nice if the user would be + // made aware of this issue by returning an error. Sadly ejabberd does not do so. + // See also https://github.com/processone/ejabberd/issues/2864#issuecomment-500741915 + final StandardExtensionElement dummyPayload = StandardExtensionElement.builder("dummy-payload", + SmackConfiguration.SMACK_URL_STRING).setText(testRunId).build(); + try { - LeafNode leafNode = (LeafNode) node; - leafNode.publish(new Item(itemId)); - fail("An exception should have been thrown."); - } - catch (XMPPErrorException e) { + XMPPErrorException e = assertThrows(XMPPErrorException.class, () -> { + LeafNode leafNode = (LeafNode) node; + + Item item = new PayloadItem<>(itemId, dummyPayload); + leafNode.publish(item); + }); assertEquals(StanzaError.Type.MODIFY, e.getStanzaError().getType()); assertNotNull(e.getStanzaError().getExtension("item-forbidden", "http://jabber.org/protocol/pubsub#errors")); } From 60c7e0ab76fc13b874432911bf7939ef921d69e3 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 29 May 2019 11:49:16 +0200 Subject: [PATCH 10/14] Fix typo in XmppNioTcpConnection: s/Therfore/Therefore/ --- .../java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java index 31b8f35a8..8cc7287df 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java @@ -1116,7 +1116,7 @@ public class XmppNioTcpConnection extends AbstractXmppNioConnection { // remote hostname information, in which case peerHost needs to be specified." that A should be used. TLS // session resumption may would need or at least benefit from B. Variant A would also be required if the // String is used for certificate verification. And it appears at least likely that TLS session resumption - // would not be hurt by using variant A. Therfore we currently use variant A. + // would not be hurt by using variant A. Therefore we currently use variant A. engine = smackTlsContext.sslContext.createSSLEngine(config.getXMPPServiceDomain().toString(), remoteAddress.getPort()); engine.setUseClientMode(true); From 89b64fbf0c3c2a609ede89ee2093a05227e0bbc9 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 29 May 2019 11:50:25 +0200 Subject: [PATCH 11/14] Add TODO comment to XmppNioTcpConnection --- .../java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java index 8cc7287df..d0ae8d351 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppNioTcpConnection.java @@ -1117,6 +1117,8 @@ public class XmppNioTcpConnection extends AbstractXmppNioConnection { // session resumption may would need or at least benefit from B. Variant A would also be required if the // String is used for certificate verification. And it appears at least likely that TLS session resumption // would not be hurt by using variant A. Therefore we currently use variant A. + // TODO: Should we use the ACE representation of the XMPP service domain? Compare with f60e4055ec529f0b8160acedf13275592ab10a4b + // If yes, then we should probably introduce getXmppServiceDomainAceEncodedIfPossible(). engine = smackTlsContext.sslContext.createSSLEngine(config.getXMPPServiceDomain().toString(), remoteAddress.getPort()); engine.setUseClientMode(true); From 9c0da3ed0756ef89ccac42a2d16c7bf5f6f909b3 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 5 Jul 2019 11:24:02 +0200 Subject: [PATCH 12/14] Change SubscribeExtension's jid field type from String to Jid and make it final. --- .../org/jivesoftware/smackx/pubsub/Node.java | 77 ++++++++++++++++++- .../smackx/pubsub/SubscribeExtension.java | 10 ++- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Node.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Node.java index 879abb640..05def395b 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Node.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/Node.java @@ -46,6 +46,10 @@ import org.jivesoftware.smackx.shim.packet.Header; import org.jivesoftware.smackx.shim.packet.HeadersExtension; import org.jivesoftware.smackx.xdata.Form; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; + public abstract class Node { protected final PubSubManager pubSubManager; protected final String id; @@ -386,12 +390,45 @@ public abstract class Node { * @throws NotConnectedException * @throws InterruptedException */ - public Subscription subscribe(String jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public Subscription subscribe(Jid jid) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { PubSub pubSub = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId())); PubSub reply = sendPubsubPacket(pubSub); return reply.getExtension(PubSubElementType.SUBSCRIPTION); } + /** + * The user subscribes to the node using the supplied jid. The + * bare jid portion of this one must match the jid for the connection. + * + * Please note that the {@link Subscription.State} should be checked + * on return since more actions may be required by the caller. + * {@link Subscription.State#pending} - The owner must approve the subscription + * request before messages will be received. + * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true, + * the caller must configure the subscription before messages will be received. If it is false + * the caller can configure it but is not required to do so. + * + * @param jidString The jid to subscribe as. + * @return The subscription + * @throws XMPPErrorException + * @throws NoResponseException + * @throws NotConnectedException + * @throws InterruptedException + * @throws IllegalArgumentException if the provided string is not a valid JID. + * @deprecated use {@link #subscribe(Jid)} instead. + */ + @Deprecated + // TODO: Remove in Smack 4.5. + public Subscription subscribe(String jidString) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + Jid jid; + try { + jid = JidCreate.from(jidString); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + return subscribe(jid); + } + /** * The user subscribes to the node using the supplied jid and subscription * options. The bare jid portion of this one must match the jid for the @@ -414,13 +451,49 @@ public abstract class Node { * @throws NotConnectedException * @throws InterruptedException */ - public Subscription subscribe(String jid, SubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public Subscription subscribe(Jid jid, SubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { PubSub request = createPubsubPacket(Type.set, new SubscribeExtension(jid, getId())); request.addExtension(new FormNode(FormNodeType.OPTIONS, subForm)); PubSub reply = sendPubsubPacket(request); return reply.getExtension(PubSubElementType.SUBSCRIPTION); } + /** + * The user subscribes to the node using the supplied jid and subscription + * options. The bare jid portion of this one must match the jid for the + * connection. + * + * Please note that the {@link Subscription.State} should be checked + * on return since more actions may be required by the caller. + * {@link Subscription.State#pending} - The owner must approve the subscription + * request before messages will be received. + * {@link Subscription.State#unconfigured} - If the {@link Subscription#isConfigRequired()} is true, + * the caller must configure the subscription before messages will be received. If it is false + * the caller can configure it but is not required to do so. + * + * @param jidString The jid to subscribe as. + * @param subForm + * + * @return The subscription + * @throws XMPPErrorException + * @throws NoResponseException + * @throws NotConnectedException + * @throws InterruptedException + * @throws IllegalArgumentException if the provided string is not a valid JID. + * @deprecated use {@link #subscribe(Jid, SubscribeForm)} instead. + */ + @Deprecated + // TODO: Remove in Smack 4.5. + public Subscription subscribe(String jidString, SubscribeForm subForm) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + Jid jid; + try { + jid = JidCreate.from(jidString); + } catch (XmppStringprepException e) { + throw new IllegalArgumentException(e); + } + return subscribe(jid, subForm); + } + /** * Remove the subscription related to the specified JID. This will only * work if there is only 1 subscription. If there are multiple subscriptions, diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java index 92e6c0b37..b17db0af0 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java @@ -16,25 +16,27 @@ */ package org.jivesoftware.smackx.pubsub; +import org.jxmpp.jid.Jid; + /** * Represents a request to subscribe to a node. * * @author Robin Collier */ public class SubscribeExtension extends NodeExtension { - protected String jid; + protected final Jid jid; - public SubscribeExtension(String subscribeJid) { + public SubscribeExtension(Jid subscribeJid) { super(PubSubElementType.SUBSCRIBE); jid = subscribeJid; } - public SubscribeExtension(String subscribeJid, String nodeId) { + public SubscribeExtension(Jid subscribeJid, String nodeId) { super(PubSubElementType.SUBSCRIBE, nodeId); jid = subscribeJid; } - public String getJid() { + public Jid getJid() { return jid; } From fda9408cf39ca59765c6813ea42115a2ce96cc30 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 5 Jul 2019 11:31:12 +0200 Subject: [PATCH 13/14] Use XmlStringBuilder in PubSub's SubscribeExtension --- .../smackx/pubsub/SubscribeExtension.java | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java index b17db0af0..9c4a55b10 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/SubscribeExtension.java @@ -16,6 +16,9 @@ */ package org.jivesoftware.smackx.pubsub; +import org.jivesoftware.smack.packet.XmlEnvironment; +import org.jivesoftware.smack.util.XmlStringBuilder; + import org.jxmpp.jid.Jid; /** @@ -41,19 +44,11 @@ public class SubscribeExtension extends NodeExtension { } @Override - public String toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { - StringBuilder builder = new StringBuilder("<"); - builder.append(getElementName()); - - if (getNode() != null) { - builder.append(" node='"); - builder.append(getNode()); - builder.append('\''); - } - builder.append(" jid='"); - builder.append(getJid()); - builder.append("'/>"); - - return builder.toString(); + public XmlStringBuilder toXML(XmlEnvironment xmlEnvironment) { + XmlStringBuilder xml = new XmlStringBuilder(this, xmlEnvironment); + xml.optAttribute("node", getNode()); + xml.attribute("jid", getJid()); + xml.closeEmptyElement(); + return xml; } } From 658905e1ba90fb402352de79bf146f8d6faac157 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 5 Jul 2019 17:40:45 +0200 Subject: [PATCH 14/14] Do not check exception message in PacketParserUtilsTest as it may be localized. This also makes PacketParserUtilsTest to use Junit5. Fixes SMACK-874. --- .../smack/util/PacketParserUtilsTest.java | 75 +++++++------------ 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/smack-core/src/test/java/org/jivesoftware/smack/util/PacketParserUtilsTest.java b/smack-core/src/test/java/org/jivesoftware/smack/util/PacketParserUtilsTest.java index a186582f0..5a1a274b4 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/util/PacketParserUtilsTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/util/PacketParserUtilsTest.java @@ -22,15 +22,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; -import java.util.function.Supplier; -import java.util.stream.Stream; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; @@ -50,8 +48,9 @@ import org.jivesoftware.smack.xml.XmlPullParser; import org.jivesoftware.smack.xml.XmlPullParserException; import com.jamesmurty.utils.XMLBuilder; -import org.junit.Ignore; -import org.junit.Test; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.xml.sax.SAXException; @@ -428,7 +427,7 @@ public class PacketParserUtilsTest { } // TODO: Re-enable once we throw an exception on duplicate body elements. - @Ignore + @Disabled @Test public void duplicateMessageBodiesTest() throws FactoryConfigurationError, XmlPullParserException, IOException, Exception { @@ -460,7 +459,7 @@ public class PacketParserUtilsTest { assertXmlNotSimilar(control, message.toXML().toString()); } - @Ignore + @Disabled @Test public void duplicateMessageBodiesTest2() throws FactoryConfigurationError, XmlPullParserException, IOException, Exception { @@ -679,7 +678,7 @@ public class PacketParserUtilsTest { * * @throws Exception */ - @Test(expected = XmlPullParserException.class) + @Test public void invalidMessageBodyContainingTagTest() throws Exception { String control = XMLBuilder.create("message") .namespace(StreamOpen.CLIENT_NAMESPACE) @@ -695,14 +694,14 @@ public class PacketParserUtilsTest { .t("Bad Message Body") .asString(outputProperties); - Message message = PacketParserUtils.parseMessage(TestUtils.getMessageParser(control)); - - fail("Should throw exception. Instead got message: " + message.toXML().toString()); + assertThrows(XmlPullParserException.class, () -> + PacketParserUtils.parseMessage(TestUtils.getMessageParser(control)) + ); } @Test public void invalidXMLInMessageBody() throws Exception { - String validControl = XMLBuilder.create("message") + final String validControl = XMLBuilder.create("message") .namespace(StreamOpen.CLIENT_NAMESPACE) .a("from", "romeo@montague.lit/orchard") .a("to", "juliet@capulet.lit/balcony") @@ -713,41 +712,20 @@ public class PacketParserUtilsTest { .t("Good Message Body") .asString(outputProperties); - // XPP3 writes "end tag", StAX writes "end-tag". - Supplier> expectedContentOfExceptionMessage = () -> Stream.of("end tag", "end-tag"); - - String invalidControl = validControl.replace("Good Message Body", "Bad Body"); - - try { + assertThrows(XmlPullParserException.class, () -> { + String invalidControl = validControl.replace("Good Message Body", "Bad Body"); PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl)); - fail("Exception should be thrown"); - } catch (XmlPullParserException e) { - String exceptionMessage = e.getMessage(); - boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected)); - assertTrue(expectedContentFound); - } + }); - invalidControl = validControl.replace("Good Message Body", "Bad Body"); - - try { + assertThrows(XmlPullParserException.class, () -> { + String invalidControl = validControl.replace("Good Message Body", "Bad Body"); PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl)); - fail("Exception should be thrown"); - } catch (XmlPullParserException e) { - String exceptionMessage = e.getMessage(); - boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected)); - assertTrue(expectedContentFound); - } + }); - invalidControl = validControl.replace("Good Message Body", "Bad Body"); - - try { + assertThrows(XmlPullParserException.class, () -> { + String invalidControl = validControl.replace("Good Message Body", "Bad Body"); PacketParserUtils.parseMessage(PacketParserUtils.getParserFor(invalidControl)); - fail("Exception should be thrown"); - } catch (XmlPullParserException e) { - String exceptionMessage = e.getMessage(); - boolean expectedContentFound = expectedContentOfExceptionMessage.get().anyMatch((expected) -> exceptionMessage.contains(expected)); - assertTrue(expectedContentFound); - } + }); } @Test @@ -891,15 +869,18 @@ public class PacketParserUtilsTest { return otherLanguage; } - @Test(expected = IllegalArgumentException.class) + @Test public void descriptiveTextNullLangPassedMap() throws Exception { final String text = "Dummy descriptive text"; Map texts = new HashMap<>(); texts.put(null, text); - StanzaError - .getBuilder(StanzaError.Condition.internal_server_error) - .setDescriptiveTexts(texts) - .build(); + + assertThrows(IllegalArgumentException.class, () -> + StanzaError + .getBuilder(StanzaError.Condition.internal_server_error) + .setDescriptiveTexts(texts) + .build() + ); } @Test