Update HOXT API to use the buidler pattern.

This commit is contained in:
Tibo-lg 2015-06-29 12:10:01 +02:00 committed by Florian Schmaus
parent ebcbdb75cd
commit 4d57848a0f
6 changed files with 331 additions and 174 deletions

View File

@ -31,20 +31,25 @@ public abstract class AbstractHttpOverXmpp extends IQ {
public static final String NAMESPACE = "urn:xmpp:http"; public static final String NAMESPACE = "urn:xmpp:http";
protected AbstractHttpOverXmpp(String element) {
super(element, NAMESPACE);
}
private HeadersExtension headers; private HeadersExtension headers;
private Data data; private Data data;
protected String version; protected String version;
protected AbstractHttpOverXmpp(String element, Builder<?, ?> builder) {
super(element, NAMESPACE);
this.headers = builder.headers;
this.data = builder.data;
this.version = builder.version;
}
protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
IQChildElementXmlStringBuilder builder = getIQHoxtChildElementBuilder(xml); IQChildElementXmlStringBuilder builder = getIQHoxtChildElementBuilder(xml);
builder.optAppend(headers.toXML()); builder.optAppend(headers);
builder.optAppend(data.toXML()); /* data cannot be fed to optAppend */
if (data != null) {
builder.optAppend(data.toXML());
}
return builder; return builder;
} }
@ -64,15 +69,6 @@ public abstract class AbstractHttpOverXmpp extends IQ {
return version; return version;
} }
/**
* Sets version attribute.
*
* @param version version attribute
*/
public void setVersion(String version) {
this.version = version;
}
/** /**
* Returns Headers element. * Returns Headers element.
* *
@ -82,15 +78,6 @@ public abstract class AbstractHttpOverXmpp extends IQ {
return headers; return headers;
} }
/**
* Sets Headers element.
*
* @param headers Headers element
*/
public void setHeaders(HeadersExtension headers) {
this.headers = headers;
}
/** /**
* Returns Data element. * Returns Data element.
* *
@ -101,16 +88,65 @@ public abstract class AbstractHttpOverXmpp extends IQ {
} }
/** /**
* Sets Data element. * A builder for XMPP connection configurations.
* <p>
* See ConnectionConfiguration Buidler for more details.
* </p>
* *
* @param data Headers element * @param <B> the builder type parameter.
* @param <C> the resulting HttpOverXmpp IQ
*/ */
public void setData(Data data) { public static abstract class Builder<B extends Builder<B, C>, C extends AbstractHttpOverXmpp> {
this.data = data;
private HeadersExtension headers;
private Data data;
private String version = "1.1";
/**
* Sets Data element.
*
* @param data Headers element
*
* @return the builder
*/
public B setData(Data data) {
this.data = data;
return getThis();
}
/**
* Sets Headers element.
*
* @param headers Headers element
*
* @return the builder
*/
public B setHeaders(HeadersExtension headers) {
this.headers = headers;
return getThis();
}
/**
* Sets version attribute.
*
* @param version version attribute
*
* @return the builder
*/
public B setVersion(String version) {
this.version = version;
return getThis();
}
public abstract C build();
protected abstract B getThis();
} }
/** /**
* Representation of Data element.<p> * Representation of Data element.
* <p>
* This class is immutable. * This class is immutable.
*/ */
public static class Data { public static class Data {
@ -150,7 +186,8 @@ public abstract class AbstractHttpOverXmpp extends IQ {
} }
/** /**
* Representation of Text element.<p> * Representation of Text element.
* <p>
* This class is immutable. * This class is immutable.
*/ */
public static class Text implements NamedElement { public static class Text implements NamedElement {
@ -193,7 +230,8 @@ public abstract class AbstractHttpOverXmpp extends IQ {
} }
/** /**
* Representation of Base64 element.<p> * Representation of Base64 element.
* <p>
* This class is immutable. * This class is immutable.
*/ */
public static class Base64 implements NamedElement { public static class Base64 implements NamedElement {
@ -236,7 +274,8 @@ public abstract class AbstractHttpOverXmpp extends IQ {
} }
/** /**
* Representation of Xml element.<p> * Representation of Xml element.
* <p>
* This class is immutable. * This class is immutable.
*/ */
public static class Xml implements NamedElement { public static class Xml implements NamedElement {
@ -279,7 +318,8 @@ public abstract class AbstractHttpOverXmpp extends IQ {
} }
/** /**
* Representation of ChunkedBase64 element.<p> * Representation of ChunkedBase64 element.
* <p>
* This class is immutable. * This class is immutable.
*/ */
public static class ChunkedBase64 implements NamedElement { public static class ChunkedBase64 implements NamedElement {
@ -321,7 +361,8 @@ public abstract class AbstractHttpOverXmpp extends IQ {
} }
/** /**
* Representation of Ibb element.<p> * Representation of Ibb element.
* <p>
* This class is immutable. * This class is immutable.
*/ */
public static class Ibb implements NamedElement { public static class Ibb implements NamedElement {

View File

@ -24,15 +24,18 @@ import org.jivesoftware.smack.util.StringUtils;
* @author Andriy Tsykholyas * @author Andriy Tsykholyas
* @see <a href="http://xmpp.org/extensions/xep-0332.html">XEP-0332: HTTP over XMPP transport</a> * @see <a href="http://xmpp.org/extensions/xep-0332.html">XEP-0332: HTTP over XMPP transport</a>
*/ */
public class HttpOverXmppReq extends AbstractHttpOverXmpp { public final class HttpOverXmppReq extends AbstractHttpOverXmpp {
public static final String ELEMENT = "req"; public static final String ELEMENT = "req";
private HttpOverXmppReq(Builder builder) {
public HttpOverXmppReq(HttpMethod method, String resource) { super(ELEMENT, builder);
super(ELEMENT); this.method = builder.method;
this.method = method; this.resource = builder.resource;
this.resource = resource; this.maxChunkSize = builder.maxChunkSize;
this.ibb = builder.ibb;
this.jingle = builder.jingle;
this.sipub = builder.sipub;
setType(Type.set); setType(Type.set);
} }
@ -40,12 +43,12 @@ public class HttpOverXmppReq extends AbstractHttpOverXmpp {
private String resource; private String resource;
// TODO: validate: xs:minInclusive value='256' xs:maxInclusive value='65536' // TODO: validate: xs:minInclusive value='256' xs:maxInclusive value='65536'
private int maxChunkSize = 0; // 0 means not set private int maxChunkSize; // 0 means not set
private boolean sipub = true; private boolean sipub;
private boolean ibb = true; private boolean ibb;
private boolean jingle = true; private boolean jingle;
@Override @Override
protected IQChildElementXmlStringBuilder getIQHoxtChildElementBuilder(IQChildElementXmlStringBuilder builder) { protected IQChildElementXmlStringBuilder getIQHoxtChildElementBuilder(IQChildElementXmlStringBuilder builder) {
@ -96,15 +99,6 @@ public class HttpOverXmppReq extends AbstractHttpOverXmpp {
return maxChunkSize; return maxChunkSize;
} }
/**
* Sets maxChunkSize attribute.
*
* @param maxChunkSize maxChunkSize attribute
*/
public void setMaxChunkSize(int maxChunkSize) {
this.maxChunkSize = maxChunkSize;
}
/** /**
* Returns sipub attribute. * Returns sipub attribute.
* *
@ -114,15 +108,6 @@ public class HttpOverXmppReq extends AbstractHttpOverXmpp {
return sipub; return sipub;
} }
/**
* Sets sipub attribute.
*
* @param sipub sipub attribute
*/
public void setSipub(boolean sipub) {
this.sipub = sipub;
}
/** /**
* Returns ibb attribute. * Returns ibb attribute.
* *
@ -132,15 +117,6 @@ public class HttpOverXmppReq extends AbstractHttpOverXmpp {
return ibb; return ibb;
} }
/**
* Sets ibb attribute.
*
* @param ibb ibb attribute
*/
public void setIbb(boolean ibb) {
this.ibb = ibb;
}
/** /**
* Returns jingle attribute. * Returns jingle attribute.
* *
@ -150,12 +126,119 @@ public class HttpOverXmppReq extends AbstractHttpOverXmpp {
return jingle; return jingle;
} }
public static Builder builder() {
return new Builder();
}
/** /**
* Sets jingle attribute. * A configuration builder for HttpOverXmppReq. Use {@link HttpOverXmppReq#builder()} to obtain a new instance and
* * {@link #build} to build the configuration.
* @param jingle jingle attribute
*/ */
public void setJingle(boolean jingle) { public static final class Builder extends AbstractHttpOverXmpp.Builder<Builder, HttpOverXmppReq> {
this.jingle = jingle;
private HttpMethod method;
private String resource;
// TODO: validate: xs:minInclusive value='256' xs:maxInclusive
// value='65536'
private int maxChunkSize = 0; // 0 means not set
private boolean sipub = true;
private boolean ibb = true;
private boolean jingle = true;
private Builder() {
}
/**
* Sets method attribute.
*
* @param method attribute
*
* @return the builder
*/
public Builder setMethod(HttpMethod method) {
this.method = method;
return this;
}
/**
* Sets resource attribute.
*
* @param resource attribute
*
* @return the builder
*/
public Builder setResource(String resource) {
this.resource = resource;
return this;
}
/**
* Sets jingle attribute.
*
* @param jingle jingle attribute
*
* @return the builder
*/
public Builder setJingle(boolean jingle) {
this.jingle = jingle;
return this;
}
/**
* Sets ibb attribute.
*
* @param ibb ibb attribute
*
* @return the builder
*/
public Builder setIbb(boolean ibb) {
this.ibb = ibb;
return this;
}
/**
* Sets sipub attribute.
*
* @param sipub sipub attribute
*
* @return the builder
*/
public Builder setSipub(boolean sipub) {
this.sipub = sipub;
return this;
}
/**
* Sets maxChunkSize attribute.
*
* @param maxChunkSize maxChunkSize attribute
*
* @return the builder
*/
public Builder setMaxChunkSize(int maxChunkSize) {
this.maxChunkSize = maxChunkSize;
return this;
}
@Override
public HttpOverXmppReq build() {
if (method == null) {
throw new IllegalArgumentException("Method cannot be null");
}
if (resource == null) {
throw new IllegalArgumentException("Resource cannot be null");
}
return new HttpOverXmppReq(this);
}
@Override
protected Builder getThis() {
return this;
}
} }
} }

View File

@ -24,17 +24,18 @@ import org.jivesoftware.smack.util.StringUtils;
* @author Andriy Tsykholyas * @author Andriy Tsykholyas
* @see <a href="http://xmpp.org/extensions/xep-0332.html">XEP-0332: HTTP over XMPP transport</a> * @see <a href="http://xmpp.org/extensions/xep-0332.html">XEP-0332: HTTP over XMPP transport</a>
*/ */
public class HttpOverXmppResp extends AbstractHttpOverXmpp { public final class HttpOverXmppResp extends AbstractHttpOverXmpp {
public static final String ELEMENT = "resp"; public static final String ELEMENT = "resp";
private HttpOverXmppResp(Builder builder) {
public HttpOverXmppResp() { super(ELEMENT, builder);
super(ELEMENT); this.statusCode = builder.statusCode;
this.statusMessage = builder.statusMessage;
} }
private int statusCode; private int statusCode;
private String statusMessage = null; private String statusMessage;
@Override @Override
protected IQChildElementXmlStringBuilder getIQHoxtChildElementBuilder(IQChildElementXmlStringBuilder builder) { protected IQChildElementXmlStringBuilder getIQHoxtChildElementBuilder(IQChildElementXmlStringBuilder builder) {
@ -59,15 +60,6 @@ public class HttpOverXmppResp extends AbstractHttpOverXmpp {
return statusCode; return statusCode;
} }
/**
* Sets statusCode attribute.
*
* @param statusCode statusCode attribute
*/
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
/** /**
* Returns statusMessage attribute. * Returns statusMessage attribute.
* *
@ -77,12 +69,53 @@ public class HttpOverXmppResp extends AbstractHttpOverXmpp {
return statusMessage; return statusMessage;
} }
/** public static Builder builder() {
* Sets statusMessage attribute. return new Builder();
*
* @param statusMessage statusMessage attribute
*/
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
} }
/**
* A configuration builder for HttpOverXmppReq. Use {@link HttpOverXmppResp#builder()} to obtain a new instance and
* {@link #build} to build the configuration.
*/
public static final class Builder extends AbstractHttpOverXmpp.Builder<Builder, HttpOverXmppResp> {
private int statusCode = 200;
private String statusMessage = null;
/**
* Sets statusCode attribute.
*
* @param statusCode statusCode attribute
*
* @return the builder
*/
public Builder setStatusCode(int statusCode) {
this.statusCode = statusCode;
return this;
}
/**
* Sets statusMessage attribute.
*
* @param statusMessage statusMessage attribute
*
* @return the builder
*/
public Builder setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
return this;
}
@Override
public HttpOverXmppResp build() {
return new HttpOverXmppResp(this);
}
@Override
protected Builder getThis() {
return this;
}
}
} }

View File

@ -49,73 +49,78 @@ public abstract class AbstractHttpOverXmppProvider<H extends AbstractHttpOverXmp
static final String ATTRIBUTE_VERSION = "version"; static final String ATTRIBUTE_VERSION = "version";
/** /**
* Parses Headers and Data elements. * Parses HeadersExtension element if any.
* *
* @param parser parser * @param parser parser
* @param elementName name of concrete implementation of this element * @return HeadersExtension or null if no headers
* @param body parent Body element * @throws Exception
* @throws Exception
*/ */
protected void parseHeadersAndData(XmlPullParser parser, String elementName, AbstractHttpOverXmpp body) throws Exception { protected HeadersExtension parseHeaders(XmlPullParser parser) throws Exception {
boolean done = false; HeadersExtension headersExtension = null;
/* We are either at start of headers, start of data or end of req/res */
while (!done) { if (parser.next() == XmlPullParser.START_TAG && parser.getName().equals(HeadersExtension.ELEMENT)) {
int eventType = parser.next(); headersExtension = HeadersProvider.INSTANCE.parse(parser);
parser.next();
if (eventType == XmlPullParser.START_TAG) {
if (parser.getName().equals(HeadersExtension.ELEMENT)) {
HeadersExtension headersExtension = HeadersProvider.INSTANCE.parse(parser);
body.setHeaders(headersExtension);
} else if (parser.getName().endsWith(ELEMENT_DATA)) {
AbstractHttpOverXmpp.Data data = parseData(parser);
body.setData(data);
} else {
throw new IllegalArgumentException("unexpected tag:" + parser.getName() + "'");
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals(elementName)) {
done = true;
}
}
} }
return headersExtension;
} }
private AbstractHttpOverXmpp.Data parseData(XmlPullParser parser) throws XmlPullParserException, IOException { /**
* Parses Data element if any.
*
* @param parser parser
* @return Data or null if no data
*
* @throws XmlPullParserException
* @throws IOException
*/
protected AbstractHttpOverXmpp.Data parseData(XmlPullParser parser) throws XmlPullParserException, IOException {
NamedElement child = null; NamedElement child = null;
boolean done = false; boolean done = false;
AbstractHttpOverXmpp.Data data = null;
/* We are either at start of data or end of req/res */
if (parser.getEventType() == XmlPullParser.START_TAG) {
while (!done) {
int eventType = parser.next();
while (!done) { if (eventType == XmlPullParser.START_TAG) {
int eventType = parser.next(); switch (parser.getName()) {
case ELEMENT_TEXT:
if (eventType == XmlPullParser.START_TAG) { child = parseText(parser);
if (parser.getName().equals(ELEMENT_TEXT)) { break;
child = parseText(parser); case ELEMENT_BASE_64:
} else if (parser.getName().equals(ELEMENT_BASE_64)) { child = parseBase64(parser);
child = parseBase64(parser); break;
} else if (parser.getName().equals(ELEMENT_CHUNKED_BASE_64)) { case ELEMENT_CHUNKED_BASE_64:
child = parseChunkedBase64(parser); child = parseChunkedBase64(parser);
} else if (parser.getName().equals(ELEMENT_XML)) { break;
child = parseXml(parser); case ELEMENT_XML:
} else if (parser.getName().equals(ELEMENT_IBB)) { child = parseXml(parser);
child = parseIbb(parser); break;
} else if (parser.getName().equals(ELEMENT_SIPUB)) { case ELEMENT_IBB:
// TODO: sipub is allowed by xep-0332, but is not implemented yet child = parseIbb(parser);
throw new UnsupportedOperationException("sipub is not supported yet"); break;
} else if (parser.getName().equals(ELEMENT_JINGLE)) { case ELEMENT_SIPUB:
// TODO: jingle is allowed by xep-0332, but is not implemented yet // TODO: sipub is allowed by xep-0332, but is not
throw new UnsupportedOperationException("jingle is not supported yet"); // implemented yet
} else { throw new UnsupportedOperationException("sipub is not supported yet");
// other elements are not allowed case ELEMENT_JINGLE:
throw new IllegalArgumentException("unsupported child tag: " + parser.getName()); // TODO: jingle is allowed by xep-0332, but is not
} // implemented yet
} else if (eventType == XmlPullParser.END_TAG) { throw new UnsupportedOperationException("jingle is not supported yet");
if (parser.getName().equals(ELEMENT_DATA)) { default:
done = true; // other elements are not allowed
throw new IllegalArgumentException("unsupported child tag: " + parser.getName());
}
} else if (eventType == XmlPullParser.END_TAG) {
if (parser.getName().equals(ELEMENT_DATA)) {
done = true;
}
} }
} }
data = new AbstractHttpOverXmpp.Data(child);
} }
AbstractHttpOverXmpp.Data data = new AbstractHttpOverXmpp.Data(child);
return data; return data;
} }

View File

@ -16,8 +16,10 @@
*/ */
package org.jivesoftware.smackx.hoxt.provider; package org.jivesoftware.smackx.hoxt.provider;
import org.jivesoftware.smackx.hoxt.packet.AbstractHttpOverXmpp;
import org.jivesoftware.smackx.hoxt.packet.HttpMethod; import org.jivesoftware.smackx.hoxt.packet.HttpMethod;
import org.jivesoftware.smackx.hoxt.packet.HttpOverXmppReq; import org.jivesoftware.smackx.hoxt.packet.HttpOverXmppReq;
import org.jivesoftware.smackx.shim.packet.HeadersExtension;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
/** /**
@ -33,16 +35,13 @@ public class HttpOverXmppReqProvider extends AbstractHttpOverXmppProvider<HttpOv
private static final String ATTRIBUTE_MAX_CHUNK_SIZE = "maxChunkSize"; private static final String ATTRIBUTE_MAX_CHUNK_SIZE = "maxChunkSize";
@Override @Override
public HttpOverXmppReq parse(XmlPullParser parser, int initialDepth) public HttpOverXmppReq parse(XmlPullParser parser, int initialDepth) throws Exception {
throws Exception {
String method = parser.getAttributeValue("", ATTRIBUTE_METHOD); String method = parser.getAttributeValue("", ATTRIBUTE_METHOD);
String resource = parser.getAttributeValue("", ATTRIBUTE_RESOURCE); String resource = parser.getAttributeValue("", ATTRIBUTE_RESOURCE);
String version = parser.getAttributeValue("", ATTRIBUTE_VERSION); String version = parser.getAttributeValue("", ATTRIBUTE_VERSION);
String maxChunkSize = parser.getAttributeValue("", ATTRIBUTE_MAX_CHUNK_SIZE); String maxChunkSize = parser.getAttributeValue("", ATTRIBUTE_MAX_CHUNK_SIZE);
HttpMethod reqMethod = HttpMethod.valueOf(method); HttpMethod reqMethod = HttpMethod.valueOf(method);
HttpOverXmppReq req = new HttpOverXmppReq(reqMethod, resource);
req.setVersion(version);
Boolean sipub = true; Boolean sipub = true;
Boolean jingle = true; Boolean jingle = true;
@ -62,16 +61,14 @@ public class HttpOverXmppReqProvider extends AbstractHttpOverXmppProvider<HttpOv
jingle = Boolean.valueOf(jingleStr); jingle = Boolean.valueOf(jingleStr);
} }
req.setIbb(ibb); int maxChunkSizeValue = 0;
req.setSipub(sipub);
req.setJingle(jingle);
if (maxChunkSize != null) { if (maxChunkSize != null) {
int maxChunkSizeValue = Integer.parseInt(maxChunkSize); maxChunkSizeValue = Integer.parseInt(maxChunkSize);
req.setMaxChunkSize(maxChunkSizeValue);
} }
parseHeadersAndData(parser, HttpOverXmppReq.ELEMENT, req); HeadersExtension headers = parseHeaders(parser);
return req; AbstractHttpOverXmpp.Data data = parseData(parser);
return HttpOverXmppReq.builder().setMethod(reqMethod).setResource(resource).setIbb(ibb).setSipub(sipub).setJingle(jingle).setMaxChunkSize(maxChunkSizeValue).setData(data).setHeaders(headers).setVersion(version).build();
} }
} }

View File

@ -16,7 +16,9 @@
*/ */
package org.jivesoftware.smackx.hoxt.provider; package org.jivesoftware.smackx.hoxt.provider;
import org.jivesoftware.smackx.hoxt.packet.AbstractHttpOverXmpp;
import org.jivesoftware.smackx.hoxt.packet.HttpOverXmppResp; import org.jivesoftware.smackx.hoxt.packet.HttpOverXmppResp;
import org.jivesoftware.smackx.shim.packet.HeadersExtension;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
/** /**
@ -31,19 +33,15 @@ public class HttpOverXmppRespProvider extends AbstractHttpOverXmppProvider<HttpO
private static final String ATTRIBUTE_STATUS_CODE = "statusCode"; private static final String ATTRIBUTE_STATUS_CODE = "statusCode";
@Override @Override
public HttpOverXmppResp parse(XmlPullParser parser, int initialDepth) public HttpOverXmppResp parse(XmlPullParser parser, int initialDepth) throws Exception {
throws Exception {
String version = parser.getAttributeValue("", ATTRIBUTE_VERSION); String version = parser.getAttributeValue("", ATTRIBUTE_VERSION);
String statusMessage = parser.getAttributeValue("", ATTRIBUTE_STATUS_MESSAGE); String statusMessage = parser.getAttributeValue("", ATTRIBUTE_STATUS_MESSAGE);
String statusCodeString = parser.getAttributeValue("", ATTRIBUTE_STATUS_CODE); String statusCodeString = parser.getAttributeValue("", ATTRIBUTE_STATUS_CODE);
int statusCode = Integer.parseInt(statusCodeString); int statusCode = Integer.parseInt(statusCodeString);
HttpOverXmppResp resp = new HttpOverXmppResp(); HeadersExtension headers = parseHeaders(parser);
AbstractHttpOverXmpp.Data data = parseData(parser);
return HttpOverXmppResp.builder().setHeaders(headers).setData(data).setStatusCode(statusCode).setStatusMessage(statusMessage).setVersion(version).build();
resp.setVersion(version);
resp.setStatusMessage(statusMessage);
resp.setStatusCode(statusCode);
parseHeadersAndData(parser, HttpOverXmppResp.ELEMENT, resp);
return resp;
} }
} }