mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-12-22 18:48:00 +01:00
Merge branch '4.0'
Conflicts: build.gradle smack-core/src/main/java/org/jivesoftware/smack/PacketCollector.java smack-core/src/main/java/org/jivesoftware/smack/packet/XMPPError.java smack-core/src/main/java/org/jivesoftware/smack/util/PacketParserUtils.java smack-core/src/main/java/org/jivesoftware/smack/util/StringUtils.java smack-extensions/src/main/java/org/jivesoftware/smackx/pubsub/provider/ItemProvider.java
This commit is contained in:
commit
34bc13bec7
7 changed files with 110 additions and 21 deletions
|
@ -19,6 +19,8 @@ package org.jivesoftware.smack;
|
||||||
|
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
|
@ -41,6 +43,8 @@ import org.jivesoftware.smack.packet.Packet;
|
||||||
*/
|
*/
|
||||||
public class PacketCollector {
|
public class PacketCollector {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(PacketCollector.class.getName());
|
||||||
|
|
||||||
private PacketFilter packetFilter;
|
private PacketFilter packetFilter;
|
||||||
private ArrayBlockingQueue<Packet> resultQueue;
|
private ArrayBlockingQueue<Packet> resultQueue;
|
||||||
private XMPPConnection connection;
|
private XMPPConnection connection;
|
||||||
|
@ -115,12 +119,16 @@ public class PacketCollector {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <P extends Packet> P nextResultBlockForever() {
|
public <P extends Packet> P nextResultBlockForever() {
|
||||||
try {
|
P res = null;
|
||||||
return (P) resultQueue.take();
|
while (res == null) {
|
||||||
}
|
try {
|
||||||
catch (InterruptedException e) {
|
res = (P) resultQueue.take();
|
||||||
throw new RuntimeException(e);
|
} catch (InterruptedException e) {
|
||||||
|
LOGGER.log(Level.FINE,
|
||||||
|
"nextResultBlockForever was interrupted", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,12 +150,18 @@ public class PacketCollector {
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <P extends Packet> P nextResult(long timeout) {
|
public <P extends Packet> P nextResult(long timeout) {
|
||||||
try {
|
P res = null;
|
||||||
return (P) resultQueue.poll(timeout, TimeUnit.MILLISECONDS);
|
long remainingWait = timeout;
|
||||||
}
|
final long waitStart = System.currentTimeMillis();
|
||||||
catch (InterruptedException e) {
|
while (res == null && remainingWait > 0) {
|
||||||
throw new RuntimeException(e);
|
try {
|
||||||
}
|
res = (P) resultQueue.poll(remainingWait, TimeUnit.MILLISECONDS);
|
||||||
|
remainingWait = timeout - (System.currentTimeMillis() - waitStart);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOGGER.log(Level.FINE, "nextResult was interrupted", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.StringUtils;
|
||||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,6 +60,7 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
* </table>
|
* </table>
|
||||||
*
|
*
|
||||||
* @author Matt Tucker
|
* @author Matt Tucker
|
||||||
|
* @see <a href="http://xmpp.org/rfcs/rfc6120.html#stanzas-error-syntax">RFC 6120 - 8.3.2 Syntax: The Syntax of XMPP error stanzas</a>
|
||||||
*/
|
*/
|
||||||
public class XMPPError {
|
public class XMPPError {
|
||||||
|
|
||||||
|
@ -272,7 +274,7 @@ public class XMPPError {
|
||||||
/**
|
/**
|
||||||
* A class to represent predefined error conditions.
|
* A class to represent predefined error conditions.
|
||||||
*/
|
*/
|
||||||
public static class Condition {
|
public static class Condition implements CharSequence {
|
||||||
|
|
||||||
public static final Condition internal_server_error = new Condition("internal-server-error");
|
public static final Condition internal_server_error = new Condition("internal-server-error");
|
||||||
public static final Condition forbidden = new Condition("forbidden");
|
public static final Condition forbidden = new Condition("forbidden");
|
||||||
|
@ -312,13 +314,35 @@ public class XMPPError {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return toString().equals(other.toString());
|
return toString().equals(other.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean equals(CharSequence other) {
|
||||||
|
return StringUtils.nullSafeCharSequenceEquals(this, other);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return value.hashCode();
|
return value.hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
return value.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char charAt(int index) {
|
||||||
|
return value.charAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence subSequence(int start, int end) {
|
||||||
|
return value.subSequence(start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -297,8 +297,14 @@ public class PacketParserUtils {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static CharSequence parseElement(XmlPullParser parser) throws XmlPullParserException, IOException {
|
public static CharSequence parseElement(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||||
assert(parser.getEventType() == XmlPullParser.START_TAG);
|
return parseElement(parser, false);
|
||||||
return parseContentDepth(parser, parser.getDepth());
|
}
|
||||||
|
|
||||||
|
public static CharSequence parseElement(XmlPullParser parser,
|
||||||
|
boolean fullNamespaces) throws XmlPullParserException,
|
||||||
|
IOException {
|
||||||
|
assert (parser.getEventType() == XmlPullParser.START_TAG);
|
||||||
|
return parseContentDepth(parser, parser.getDepth(), fullNamespaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -325,28 +331,36 @@ public class PacketParserUtils {
|
||||||
}
|
}
|
||||||
// Advance the parser, since we want to parse the content of the current element
|
// Advance the parser, since we want to parse the content of the current element
|
||||||
parser.next();
|
parser.next();
|
||||||
return parseContentDepth(parser, parser.getDepth());
|
return parseContentDepth(parser, parser.getDepth(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CharSequence parseContentDepth(XmlPullParser parser, int depth)
|
||||||
|
throws XmlPullParserException, IOException {
|
||||||
|
return parseContentDepth(parser, depth, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content from the current position of the parser up to the closing tag of the
|
* Returns the content from the current position of the parser up to the closing tag of the
|
||||||
* given depth. Note that only the outermost namespace attributes ("xmlns") will be returned,
|
* given depth. Note that only the outermost namespace attributes ("xmlns") will be returned,
|
||||||
* not nested ones.
|
* not nested ones, if <code>fullNamespaces</code> is false. If it is true, then namespaces of
|
||||||
|
* parent elements will be added to child elements that don't define a different namespace.
|
||||||
* <p>
|
* <p>
|
||||||
* This method is able to parse the content with MX- and KXmlParser. In order to achieve
|
* This method is able to parse the content with MX- and KXmlParser. In order to achieve
|
||||||
* this some trade-off has to be make, because KXmlParser does not support xml-roundtrip (ie.
|
* this some trade-off has to be make, because KXmlParser does not support xml-roundtrip (ie.
|
||||||
* return a String on getText() on START_TAG and END_TAG). We are therefore required to work
|
* return a String on getText() on START_TAG and END_TAG). We are therefore required to work
|
||||||
* around this limitation, which results in only partial support for XML namespaces ("xmlns"):
|
* around this limitation, which results in only partial support for XML namespaces ("xmlns"):
|
||||||
* Only the outermost namespace of elements will be included in the resulting String.
|
* Only the outermost namespace of elements will be included in the resulting String, if
|
||||||
|
* <code>fullNamespaces</code> is set to false.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param parser
|
* @param parser
|
||||||
* @param depth
|
* @param depth
|
||||||
|
* @param fullNamespaces
|
||||||
* @return the content of the current depth
|
* @return the content of the current depth
|
||||||
* @throws XmlPullParserException
|
* @throws XmlPullParserException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public static CharSequence parseContentDepth(XmlPullParser parser, int depth) throws XmlPullParserException, IOException {
|
public static CharSequence parseContentDepth(XmlPullParser parser, int depth, boolean fullNamespaces) throws XmlPullParserException, IOException {
|
||||||
XmlStringBuilder xml = new XmlStringBuilder();
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
int event = parser.getEventType();
|
int event = parser.getEventType();
|
||||||
boolean isEmptyElement = false;
|
boolean isEmptyElement = false;
|
||||||
|
@ -357,7 +371,7 @@ public class PacketParserUtils {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (event == XmlPullParser.START_TAG) {
|
if (event == XmlPullParser.START_TAG) {
|
||||||
xml.halfOpenElement(parser.getName());
|
xml.halfOpenElement(parser.getName());
|
||||||
if (namespaceElement == null) {
|
if (namespaceElement == null || fullNamespaces) {
|
||||||
String namespace = parser.getNamespace();
|
String namespace = parser.getNamespace();
|
||||||
if (StringUtils.isNotEmpty(namespace)) {
|
if (StringUtils.isNotEmpty(namespace)) {
|
||||||
xml.attribute("xmlns", namespace);
|
xml.attribute("xmlns", namespace);
|
||||||
|
|
|
@ -260,4 +260,18 @@ public class StringUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean nullSafeCharSequenceEquals(CharSequence csOne, CharSequence csTwo) {
|
||||||
|
return nullSafeCharSequenceComperator(csOne, csTwo) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int nullSafeCharSequenceComperator(CharSequence csOne, CharSequence csTwo) {
|
||||||
|
if (csOne == null ^ csTwo == null) {
|
||||||
|
return (csOne == null) ? -1 : 1;
|
||||||
|
}
|
||||||
|
if (csOne == null && csTwo == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return csOne.toString().compareTo(csTwo.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ParsingExceptionTest {
|
||||||
try {
|
try {
|
||||||
PacketParserUtils.parseMessage(parser);
|
PacketParserUtils.parseMessage(parser);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
content = PacketParserUtils.parseContentDepth(parser, parserDepth);
|
content = PacketParserUtils.parseContentDepth(parser, parserDepth, false);
|
||||||
}
|
}
|
||||||
assertThat(MESSAGE_EXCEPTION_ELEMENT + EXTENSION2 + "</message>", equalsCharSequence(content));
|
assertThat(MESSAGE_EXCEPTION_ELEMENT + EXTENSION2 + "</message>", equalsCharSequence(content));
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,14 @@ import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.xml.parsers.FactoryConfigurationError;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
|
||||||
import org.custommonkey.xmlunit.Diff;
|
import org.custommonkey.xmlunit.Diff;
|
||||||
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
|
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
|
||||||
import org.jivesoftware.smack.packet.Message;
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
@ -34,6 +39,7 @@ import org.jivesoftware.smack.packet.Packet;
|
||||||
import org.jivesoftware.smack.packet.Presence;
|
import org.jivesoftware.smack.packet.Presence;
|
||||||
import org.jivesoftware.smack.test.util.TestUtils;
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
@ -790,6 +796,23 @@ public class PacketParserUtilsTest {
|
||||||
assertEquals("", content);
|
assertEquals("", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseElementMultipleNamespace()
|
||||||
|
throws ParserConfigurationException,
|
||||||
|
FactoryConfigurationError, XmlPullParserException,
|
||||||
|
IOException, TransformerException, SAXException {
|
||||||
|
// @formatter:off
|
||||||
|
final String stanza = XMLBuilder.create("outer", "outerNamespace").a("outerAttribute", "outerValue")
|
||||||
|
.element("inner", "innerNamespace").a("innverAttribute", "innerValue")
|
||||||
|
.element("innermost")
|
||||||
|
.t("some text")
|
||||||
|
.asString();
|
||||||
|
// @formatter:on
|
||||||
|
XmlPullParser parser = TestUtils.getParser(stanza, "outer");
|
||||||
|
CharSequence result = PacketParserUtils.parseElement(parser, true);
|
||||||
|
assertXMLEqual(stanza, result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
private String determineNonDefaultLanguage() {
|
private String determineNonDefaultLanguage() {
|
||||||
String otherLanguage = "jp";
|
String otherLanguage = "jp";
|
||||||
Locale[] availableLocales = Locale.getAvailableLocales();
|
Locale[] availableLocales = Locale.getAvailableLocales();
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class ItemProvider implements PacketExtensionProvider
|
||||||
|
|
||||||
if (ProviderManager.getExtensionProvider(payloadElemName, payloadNS) == null)
|
if (ProviderManager.getExtensionProvider(payloadElemName, payloadNS) == null)
|
||||||
{
|
{
|
||||||
CharSequence payloadText = PacketParserUtils.parseElement(parser);
|
CharSequence payloadText = PacketParserUtils.parseElement(parser, true);
|
||||||
return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText));
|
return new PayloadItem<SimplePayload>(id, node, new SimplePayload(payloadElemName, payloadNS, payloadText));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in a new issue