Add support for SASL failure 'text' elements

- Also move toString() into TopLevelStreamElement.
- Fix SASLFailure toXML xmlnsAttribute(NAMESPACE)
- Improve SASLFailure parsing
- And introduce XmlUnitUtils
This commit is contained in:
Florian Schmaus 2014-11-18 19:48:02 +01:00
parent 59d3f55003
commit 646a4a6f90
9 changed files with 160 additions and 47 deletions

View File

@ -372,11 +372,6 @@ public abstract class Packet extends TopLevelStreamElement {
return DEFAULT_LANGUAGE;
}
@Override
public String toString() {
return toXML().toString();
}
/**
* Add to, from, id and 'xml:lang' attributes
*

View File

@ -230,18 +230,6 @@ public final class Presence extends Packet {
return buf;
}
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(type);
if (mode != null) {
buf.append(": ").append(mode);
}
if (getStatus() != null) {
buf.append(" (").append(getStatus()).append(")");
}
return buf.toString();
}
/**
* An enum to represent the presence type. Note that presence type is often confused
* with presence mode. Generally, if a user is signed in to a server, they have a presence

View File

@ -23,4 +23,9 @@ package org.jivesoftware.smack.packet;
*/
public abstract class TopLevelStreamElement implements Element {
@Override
public final String toString() {
return toXML().toString();
}
}

View File

@ -16,6 +16,10 @@
*/
package org.jivesoftware.smack.sasl.packet;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import org.jivesoftware.smack.packet.PlainStreamElement;
import org.jivesoftware.smack.sasl.SASLError;
import org.jivesoftware.smack.util.StringUtils;
@ -159,8 +163,18 @@ public class SaslStreamElements {
private final SASLError saslError;
private final String saslErrorString;
private final Map<String, String> descriptiveTexts;
public SASLFailure(String saslError) {
this(saslError, null);
}
public SASLFailure(String saslError, Map<String, String> descriptiveTexts) {
if (descriptiveTexts != null) {
this.descriptiveTexts = descriptiveTexts;
} else {
this.descriptiveTexts = Collections.emptyMap();
}
SASLError error = SASLError.fromString(saslError);
if (error == null) {
// RFC6120 6.5 states that unknown condition must be treat as generic authentication
@ -189,11 +203,48 @@ public class SaslStreamElements {
return saslErrorString;
}
/**
* Get the descriptive text of this SASLFailure.
* <p>
* Returns the descriptive text of this SASLFailure in the system default language if possible. May return null.
* </p>
*
* @return the descriptive text or null.
*/
public String getDescriptiveText() {
String defaultLocale = Locale.getDefault().getLanguage();
String descriptiveText = getDescriptiveText(defaultLocale);
if (descriptiveText == null) {
descriptiveText = getDescriptiveText(null);
}
return descriptiveText;
}
/**
* Get the descriptive test of this SASLFailure.
* <p>
* Returns the descriptive text of this SASLFailure in the given language. May return null if not available.
* </p>
*
* @param xmllang the language.
* @return the descriptive text or null.
*/
public String getDescriptiveText(String xmllang) {
return descriptiveTexts.get(xmllang);
}
@Override
public XmlStringBuilder toXML() {
XmlStringBuilder xml = new XmlStringBuilder();
xml.halfOpenElement(ELEMENT).xmlnsAttribute(ELEMENT).rightAngleBracket();
xml.halfOpenElement(ELEMENT).xmlnsAttribute(NAMESPACE).rightAngleBracket();
xml.emptyElement(saslErrorString);
for (Map.Entry<String, String> entry : descriptiveTexts.entrySet()) {
String xmllang = entry.getKey();
String text = entry.getValue();
xml.halfOpenElement("text").xmllangAttribute(xmllang).rightAngleBracket();
xml.escape(text);
xml.closeElement("text");
}
xml.closeElement(ELEMENT);
return xml;
}

View File

@ -22,9 +22,11 @@ import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -765,26 +767,37 @@ public class PacketParserUtils {
*
* @param parser the XML parser.
* @return a SASL Failure packet.
* @throws Exception if an exception occurs while parsing the packet.
* @throws IOException
* @throws XmlPullParserException
*/
public static SASLFailure parseSASLFailure(XmlPullParser parser) throws Exception {
public static SASLFailure parseSASLFailure(XmlPullParser parser) throws XmlPullParserException, IOException {
final int initialDepth = parser.getDepth();
String condition = null;
boolean done = false;
while (!done) {
Map<String, String> descriptiveTexts = new HashMap<String, String>();
outerloop: while (true) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (!parser.getName().equals("failure")) {
switch (eventType) {
case XmlPullParser.START_TAG:
String name = parser.getName();
if (name.equals("text")) {
String xmllang = getLanguageAttribute(parser);
String text = parser.nextText();
String previousValue = descriptiveTexts.put(xmllang, text);
assert(previousValue == null);
}
else {
assert(condition == null);
condition = parser.getName();
}
}
else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals("failure")) {
done = true;
break;
case XmlPullParser.END_TAG:
if (parser.getDepth() == initialDepth) {
break outerloop;
}
break;
}
}
return new SASLFailure(condition);
return new SASLFailure(condition, descriptiveTexts);
}
/**

View File

@ -200,12 +200,6 @@ public class PacketCollectorTest
setPacketID(String.valueOf(i));
}
@Override
public String toString()
{
return toXML();
}
@Override
public String toXML()
{

View File

@ -21,8 +21,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
import org.jivesoftware.smack.test.util.XmlUnitUtils;
import org.junit.Test;
import org.xml.sax.SAXException;
@ -150,9 +149,7 @@ public class MessageTest {
message.addBody(null, messageBody1);
message.addBody(lang2, messageBody2);
message.addBody(lang3, messageBody3);
Diff xmlDiff = new Diff(control, message.toXML().toString());
xmlDiff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
assertTrue(xmlDiff.similar());
XmlUnitUtils.assertSimilar(control, message.toXML());
Collection<String> languages = message.getBodyLanguages();
List<String> controlLanguages = new ArrayList<String>();

View File

@ -0,0 +1,35 @@
/**
*
* Copyright 2014 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.test.util;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import java.io.IOException;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
import org.xml.sax.SAXException;
public class XmlUnitUtils {
public static void assertSimilar(CharSequence expected, CharSequence actual) throws SAXException, IOException {
Diff diff = new Diff(expected.toString(), actual.toString());
diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
assertXMLEqual(diff, true);
}
}

View File

@ -32,12 +32,14 @@ import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.sasl.SASLError;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements;
import org.jivesoftware.smack.sasl.packet.SaslStreamElements.SASLFailure;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.test.util.XmlUnitUtils;
import org.junit.Test;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
@ -745,11 +747,9 @@ public class PacketParserUtilsTest {
.a("xml:lang", "sp")
.t("This is a test of the emergency broadcast system, 3.")
.asString(outputProperties);
Packet message = PacketParserUtils.parseStanza(control);
Diff xmlDiff = new Diff(control, message.toXML().toString());
xmlDiff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
assertTrue(xmlDiff.similar());
XmlUnitUtils.assertSimilar(control, message.toXML());
}
@Test
@ -813,6 +813,41 @@ public class PacketParserUtilsTest {
assertXMLEqual(stanza, result.toString());
}
@Test
public void parseSASLFailureSimple() throws FactoryConfigurationError, SAXException, IOException,
TransformerException, ParserConfigurationException, XmlPullParserException {
// @formatter:off
final String saslFailureString = XMLBuilder.create(SASLFailure.ELEMENT, SaslStreamElements.NAMESPACE)
.e(SASLError.account_disabled.toString())
.asString();
// @formatter:on
XmlPullParser parser = TestUtils.getParser(saslFailureString, SASLFailure.ELEMENT);
SASLFailure saslFailure = PacketParserUtils.parseSASLFailure(parser);
assertXMLEqual(saslFailureString, saslFailure.toString());
}
@Test
public void parseSASLFailureExtended() throws FactoryConfigurationError, TransformerException,
ParserConfigurationException, XmlPullParserException, IOException, SAXException {
// @formatter:off
final String saslFailureString = XMLBuilder.create(SASLFailure.ELEMENT, SaslStreamElements.NAMESPACE)
.e(SASLError.account_disabled.toString())
.up()
.e("text").a("xml:lang", "en")
.t("Call 212-555-1212 for assistance.")
.up()
.e("text").a("xml:lang", "de")
.t("Bitte wenden sie sich an (04321) 123-4444")
.up()
.e("text")
.t("Wusel dusel")
.asString();
// @formatter:on
XmlPullParser parser = TestUtils.getParser(saslFailureString, SASLFailure.ELEMENT);
SASLFailure saslFailure = PacketParserUtils.parseSASLFailure(parser);
XmlUnitUtils.assertSimilar(saslFailureString, saslFailure.toXML());
}
private String determineNonDefaultLanguage() {
String otherLanguage = "jp";
Locale[] availableLocales = Locale.getAvailableLocales();