Improve SHIM API

- HeadersExtension.getHeaders() now returns a List instead of a
  Collection
- Use XmlStringBuilder in Header and HeadersExtension toXML()
- Add HeadersProviderTest
- Use Smack formatting

Also remove duplicate parsing code regarding SHIM from HOXT
implementation.
This commit is contained in:
Florian Schmaus 2015-01-01 23:57:44 +01:00
parent 06add179ec
commit f2703bc195
7 changed files with 164 additions and 123 deletions

View File

@ -16,6 +16,8 @@
*/ */
package org.jivesoftware.smack.util; package org.jivesoftware.smack.util;
import java.util.Collection;
import org.jivesoftware.smack.packet.Element; import org.jivesoftware.smack.packet.Element;
import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
@ -272,6 +274,13 @@ public class XmlStringBuilder implements Appendable, CharSequence {
return this; return this;
} }
public XmlStringBuilder append(Collection<? extends Element> elements) {
for (Element element : elements) {
append(element.toXML());
}
return this;
}
public XmlStringBuilder emptyElement(Enum<?> element) { public XmlStringBuilder emptyElement(Enum<?> element) {
return emptyElement(element.name()); return emptyElement(element.name());
} }

View File

@ -21,15 +21,12 @@ import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.provider.IQProvider;
import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.hoxt.packet.AbstractHttpOverXmpp; import org.jivesoftware.smackx.hoxt.packet.AbstractHttpOverXmpp;
import org.jivesoftware.smackx.shim.packet.Header;
import org.jivesoftware.smackx.shim.packet.HeadersExtension; import org.jivesoftware.smackx.shim.packet.HeadersExtension;
import org.jivesoftware.smackx.shim.provider.HeaderProvider; import org.jivesoftware.smackx.shim.provider.HeadersProvider;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
/** /**
* Abstract parent for Req and Resp packet providers. * Abstract parent for Req and Resp packet providers.
@ -39,8 +36,6 @@ import java.util.Set;
*/ */
public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmpp> extends IQProvider<H> { public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmpp> extends IQProvider<H> {
private static final String ELEMENT_HEADERS = "headers";
private static final String ELEMENT_HEADER = "header";
private static final String ELEMENT_DATA = "data"; private static final String ELEMENT_DATA = "data";
private static final String ELEMENT_TEXT = "text"; private static final String ELEMENT_TEXT = "text";
private static final String ELEMENT_BASE_64 = "base64"; private static final String ELEMENT_BASE_64 = "base64";
@ -71,8 +66,8 @@ public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmp
int eventType = parser.next(); int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals(ELEMENT_HEADERS)) { if (parser.getName().equals(HeadersExtension.ELEMENT)) {
HeadersExtension headersExtension = parseHeaders(parser); HeadersExtension headersExtension = HeadersProvider.INSTANCE.parse(parser);
body.setHeaders(headersExtension); body.setHeaders(headersExtension);
} else if (parser.getName().endsWith(ELEMENT_DATA)) { } else if (parser.getName().endsWith(ELEMENT_DATA)) {
AbstractHttpOverXmpp.Data data = parseData(parser); AbstractHttpOverXmpp.Data data = parseData(parser);
@ -88,28 +83,6 @@ public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmp
} }
} }
private HeadersExtension parseHeaders(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException {
HeaderProvider provider = new HeaderProvider();
Set<Header> set = new HashSet<Header>();
boolean done = false;
while (!done) {
int eventType = parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals(ELEMENT_HEADER)) {
Header header = provider.parse(parser);
set.add(header);
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals(ELEMENT_HEADERS)) {
done = true;
}
}
}
return new HeadersExtension(set);
}
private AbstractHttpOverXmpp.Data parseData(XmlPullParser parser) throws XmlPullParserException, IOException { private AbstractHttpOverXmpp.Data parseData(XmlPullParser parser) throws XmlPullParserException, IOException {
NamedElement child = null; NamedElement child = null;
boolean done = false; boolean done = false;

View File

@ -16,47 +16,50 @@
*/ */
package org.jivesoftware.smackx.shim.packet; package org.jivesoftware.smackx.shim.packet;
import org.jivesoftware.smack.packet.NamedElement;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.XmlStringBuilder;
/** /**
* Represents a <b>Header</b> entry as specified by the <a href="http://xmpp.org/extensions/xep-031.html">Stanza Headers and Internet Metadata (SHIM)</a> * Represents a <b>Header</b> entry as specified by the <a href="http://xmpp.org/extensions/xep-031.html">Stanza Headers and Internet Metadata (SHIM)</a>
* @author Robin Collier * @author Robin Collier
*/ */
public class Header implements PacketExtension public class Header implements PacketExtension {
{ public static final String ELEMENT = "header";
private String name;
private String value;
public Header(String name, String value)
{
this.name = name;
this.value = value;
}
public String getName()
{
return name;
}
public String getValue() private final String name;
{ private final String value;
return value;
}
public String getElementName() public Header(String name, String value) {
{ this.name = name;
return "header"; this.value = value;
} }
public String getNamespace() public String getName() {
{ return name;
return HeadersExtension.NAMESPACE; }
}
public String toXML() public String getValue() {
{ return value;
return "<header name='" + name + "'>" + value + "</header>"; }
}
public String getElementName() {
return ELEMENT;
}
public String getNamespace() {
return HeadersExtension.NAMESPACE;
}
@Override
public XmlStringBuilder toXML() {
// Upcast to NamedElement since we don't want a xmlns attribute
XmlStringBuilder xml = new XmlStringBuilder((NamedElement) this);
xml.attribute("name", name);
xml.rightAngleBracket();
xml.escape(value);
xml.closeElement(this);
return xml;
}
} }

View File

@ -16,10 +16,12 @@
*/ */
package org.jivesoftware.smackx.shim.packet; package org.jivesoftware.smackx.shim.packet;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension; import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.util.XmlStringBuilder;
/** /**
* Extension representing a list of headers as specified in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a> * Extension representing a list of headers as specified in <a href="http://xmpp.org/extensions/xep-0131">Stanza Headers and Internet Metadata (SHIM)</a>
@ -28,44 +30,48 @@ import org.jivesoftware.smack.packet.PacketExtension;
* *
* @author Robin Collier * @author Robin Collier
*/ */
public class HeadersExtension implements PacketExtension public class HeadersExtension implements PacketExtension {
{ public static final String ELEMENT = "headers";
public static final String NAMESPACE = "http://jabber.org/protocol/shim"; public static final String NAMESPACE = "http://jabber.org/protocol/shim";
private Collection<Header> headers = Collections.emptyList();
public HeadersExtension(Collection<Header> headerList)
{
if (headerList != null)
headers = headerList;
}
public Collection<Header> getHeaders()
{
return headers;
}
public String getElementName() private final List<Header> headers;
{
return "headers";
}
public String getNamespace() public HeadersExtension(List<Header> headerList) {
{ if (headerList != null) {
return NAMESPACE; headers = Collections.unmodifiableList(headerList);
} } else {
headers = Collections.emptyList();
}
}
public String toXML() public List<Header> getHeaders() {
{ return headers;
StringBuilder builder = new StringBuilder("<" + getElementName() + " xmlns='" + getNamespace() + "'>"); }
for (Header header : headers)
{
builder.append(header.toXML());
}
builder.append("</" + getElementName() + '>');
return builder.toString(); public String getElementName() {
} return ELEMENT;
}
public String getNamespace() {
return NAMESPACE;
}
@Override
public XmlStringBuilder toXML() {
XmlStringBuilder xml = new XmlStringBuilder(this);
xml.rightAngleBracket();
xml.append(headers);
xml.closeElement(this);
return xml;
}
/**
* Return the SHIM headers extension of this stanza or null if there is none.
*
* @param packet
* @return the headers extension or null.
*/
public static HeadersExtension from(Packet packet) {
return packet.getExtension(ELEMENT, NAMESPACE);
}
} }

View File

@ -28,23 +28,23 @@ import org.xmlpull.v1.XmlPullParserException;
* *
* @author Robin Collier * @author Robin Collier
*/ */
public class HeaderProvider extends PacketExtensionProvider<Header> public class HeaderProvider extends PacketExtensionProvider<Header> {
{
@Override @Override
public Header parse(XmlPullParser parser, int initialDepth) public Header parse(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException {
throws XmlPullParserException, IOException { String name = parser.getAttributeValue(null, "name");
String name = parser.getAttributeValue(null, "name"); String value = null;
String value = null;
parser.next();
parser.next();
if (parser.getEventType() == XmlPullParser.TEXT) {
if (parser.getEventType() == XmlPullParser.TEXT) value = parser.getText();
value = parser.getText(); }
while(parser.getEventType() != XmlPullParser.END_TAG) while (parser.getEventType() != XmlPullParser.END_TAG) {
parser.next(); parser.next();
}
return new Header(name, value);
} return new Header(name, value);
}
} }

View File

@ -16,7 +16,6 @@
*/ */
package org.jivesoftware.smackx.shim.provider; package org.jivesoftware.smackx.shim.provider;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -30,13 +29,14 @@ import org.jivesoftware.smackx.shim.packet.HeadersExtension;
* *
* @author Robin Collier * @author Robin Collier
*/ */
public class HeadersProvider extends EmbeddedExtensionProvider<HeadersExtension> public class HeadersProvider extends EmbeddedExtensionProvider<HeadersExtension> {
{ public static final HeadersProvider INSTANCE = new HeadersProvider();
@SuppressWarnings("unchecked")
@Override @SuppressWarnings("unchecked")
protected HeadersExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends PacketExtension> content) @Override
{ protected HeadersExtension createReturnExtension(String currentElement, String currentNamespace,
return new HeadersExtension((Collection<Header>)content); Map<String, String> attributeMap, List<? extends PacketExtension> content) {
} return new HeadersExtension((List<Header>) content);
}
} }

View File

@ -0,0 +1,50 @@
/**
*
* 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.smackx.shim.provider;
import static org.junit.Assert.assertEquals;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.test.util.TestUtils;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smackx.shim.packet.Header;
import org.jivesoftware.smackx.shim.packet.HeadersExtension;
import org.junit.Test;
import org.xmlpull.v1.XmlPullParser;
public class HeadersProviderTest {
@Test
public void headersInMessageTest() throws Exception {
// @formatter:off
final String messageStanza =
"<message from='romeo@shakespeare.lit/orchard' to='juliet@capulet.com' type='chat'>" +
"<body>Wherefore are thou?!?</body>" +
"<headers xmlns='http://jabber.org/protocol/shim'>" +
"<header name='Urgency'>high</header>" +
"</headers>" +
"</message>";
// @formatter:on
XmlPullParser parser = TestUtils.getMessageParser(messageStanza);
Message message = PacketParserUtils.parseMessage(parser);
HeadersExtension headers = HeadersExtension.from(message);
Header header = headers.getHeaders().get(0);
assertEquals("Urgency", header.getName());
assertEquals("high", header.getValue());
}
}