1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-22 22:32:06 +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:
Florian Schmaus 2014-09-05 22:06:58 +02:00
commit 34bc13bec7
7 changed files with 110 additions and 21 deletions

View file

@ -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;
} }
/** /**

View file

@ -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);
}
} }

View file

@ -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);

View file

@ -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());
}
} }

View file

@ -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));
} }

View file

@ -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();

View file

@ -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