formatting

This commit is contained in:
Adrian Cole 2011-10-29 00:00:49 +02:00
parent e5478cdd84
commit 71ac2b89e1
8 changed files with 449 additions and 495 deletions

View File

@ -40,74 +40,61 @@ import com.google.common.base.Function;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
/** /**
* This object will parse the body of an HttpResponse and return the result of type <T> back to the * This object will parse the body of an HttpResponse and return the result of
* caller. * type <T> back to the caller.
* <p> * <p>
* {@link JAXBContext} works with {@link Class} objects instead of {@link Type}. This could be a * {@link JAXBContext} works with {@link Class} objects instead of {@link Type}.
* limitation if we are trying to parse typed collections of objects. However, when using JAXB we * This could be a limitation if we are trying to parse typed collections of
* expect to have well formed XML documents with one single root element, so the objects to parse * objects. However, when using JAXB we expect to have well formed XML documents
* should not be collections but objects that wrap collections of elements, and that should work * with one single root element, so the objects to parse should not be
* fine. * collections but objects that wrap collections of elements, and that should
* work fine.
* *
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
@Singleton @Singleton
public class ParseXMLWithJAXB<T> implements Function<HttpResponse, T> public class ParseXMLWithJAXB<T> implements Function<HttpResponse, T> {
{ @Resource
@Resource protected Logger logger = Logger.NULL;
protected Logger logger = Logger.NULL;
protected XMLParser xml; protected XMLParser xml;
protected final TypeLiteral<T> type; protected final TypeLiteral<T> type;
@Inject @Inject
public ParseXMLWithJAXB(final XMLParser xml, final TypeLiteral<T> type) public ParseXMLWithJAXB(final XMLParser xml, final TypeLiteral<T> type) {
{ this.xml = xml;
this.xml = xml; this.type = type;
this.type = type; }
}
@Override @Override
public T apply(final HttpResponse from) public T apply(final HttpResponse from) {
{ InputStream xml = from.getPayload().getInput();
InputStream xml = from.getPayload().getInput(); try {
try return apply(xml);
{ } catch (Exception e) {
return apply(xml); StringBuffer message = new StringBuffer();
} message.append("Error parsing input");
catch (Exception e) logger.error(e, message.toString());
{ throw new HttpResponseException(message.toString() + "\n" + from, null, from, e);
StringBuffer message = new StringBuffer(); } finally {
message.append("Error parsing input"); releasePayload(from);
logger.error(e, message.toString()); }
throw new HttpResponseException(message.toString() + "\n" + from, null, from, e); }
}
finally
{
releasePayload(from);
}
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T apply(final InputStream stream) throws IOException public T apply(final InputStream stream) throws IOException {
{ return (T) apply(stream, type.getRawType());
return (T) apply(stream, type.getRawType()); }
}
public <V> V apply(final InputStream stream, final Class<V> type) throws IOException public <V> V apply(final InputStream stream, final Class<V> type) throws IOException {
{ try {
try return xml.fromXML(Strings2.toStringAndClose(stream), type);
{ } finally {
return xml.fromXML(Strings2.toStringAndClose(stream), type); if (stream != null) {
} stream.close();
finally }
{ }
if (stream != null) }
{
stream.close();
}
}
}
} }

View File

@ -27,14 +27,13 @@ import java.lang.annotation.Target;
import org.jclouds.http.functions.ParseXMLWithJAXB; import org.jclouds.http.functions.ParseXMLWithJAXB;
/** /**
* Shows the transformer type used to parse XML with the {@link ParseXMLWithJAXB} parser in a * Shows the transformer type used to parse XML with the
* HttpResponse. * {@link ParseXMLWithJAXB} parser in a HttpResponse.
* *
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
@Target(METHOD) @Target(METHOD)
@Retention(RUNTIME) @Retention(RUNTIME)
public @interface JAXBResponseParser public @interface JAXBResponseParser {
{
} }

View File

@ -26,46 +26,39 @@ import org.jclouds.http.HttpRequest;
* *
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
public class BindException extends RuntimeException public class BindException extends RuntimeException {
{ private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private HttpRequest request; private HttpRequest request;
public BindException(final HttpRequest request) public BindException(final HttpRequest request) {
{ super();
super(); this.request = request;
this.request = request; }
}
public BindException(final HttpRequest request, final String message) public BindException(final HttpRequest request, final String message) {
{ super(message);
super(message); this.request = request;
this.request = request; }
}
public BindException(final HttpRequest request, final Throwable cause) public BindException(final HttpRequest request, final Throwable cause) {
{ super(cause.getMessage(), cause);
super(cause.getMessage(), cause); this.request = request;
this.request = request; }
}
public BindException(final HttpRequest request, final String message, final Throwable cause) public BindException(final HttpRequest request, final String message, final Throwable cause) {
{ super(message, cause);
super(message, cause); this.request = request;
this.request = request; }
}
@Override @Override
public String getMessage() public String getMessage() {
{ String msg = "Could not bind object to request" + request + ": ";
String msg = "Could not bind object to request" + request + ": "; return msg + super.getMessage();
return msg + super.getMessage(); }
}
public HttpRequest getRequest() public HttpRequest getRequest() {
{ return request;
return request; }
}
} }

View File

@ -40,39 +40,31 @@ import com.google.common.base.Strings;
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
@Singleton @Singleton
public class BindToXMLPayload implements Binder public class BindToXMLPayload implements Binder {
{ protected final XMLParser xmlParser;
protected final XMLParser xmlParser;
@Inject @Inject
public BindToXMLPayload(final XMLParser xmlParser) public BindToXMLPayload(final XMLParser xmlParser) {
{ this.xmlParser = checkNotNull(xmlParser, "xmlParser");
this.xmlParser = checkNotNull(xmlParser, "xmlParser"); }
}
@Override @Override
public <R extends HttpRequest> R bindToRequest(final R request, final Object input) public <R extends HttpRequest> R bindToRequest(final R request, final Object input) {
{ try {
try String xml = xmlParser.toXML(checkNotNull(input, "input"));
{ request.setPayload(xml);
String xml = xmlParser.toXML(checkNotNull(input, "input")); MutableContentMetadata metadata = request.getPayload().getContentMetadata();
request.setPayload(xml); if (contentTypeMustBeAdded(metadata)) {
MutableContentMetadata metadata = request.getPayload().getContentMetadata(); metadata.setContentType(MediaType.APPLICATION_XML);
if (contentTypeMustBeAdded(metadata)) }
{ return request;
metadata.setContentType(MediaType.APPLICATION_XML); } catch (IOException ex) {
} throw new BindException(request, ex);
return request; }
} }
catch (IOException ex)
{
throw new BindException(request, ex);
}
}
private static boolean contentTypeMustBeAdded(final MutableContentMetadata metadata) private static boolean contentTypeMustBeAdded(final MutableContentMetadata metadata) {
{ return Strings.isNullOrEmpty(metadata.getContentType())
return Strings.isNullOrEmpty(metadata.getContentType())
|| metadata.getContentType().equals("application/unknown"); || metadata.getContentType().equals("application/unknown");
} }
} }

View File

@ -31,27 +31,23 @@ import com.google.inject.ImplementedBy;
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
@ImplementedBy(JAXBParser.class) @ImplementedBy(JAXBParser.class)
public interface XMLParser public interface XMLParser {
{ /** The default xml header. */
/** The default xml header. */ public static final String DEFAULT_XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
public static final String DEFAULT_XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
/**
* Serialize the object into xml. If the object is a generic type, use
* {@link #toXML(Object, Type)}
*/
public String toXML(Object src) throws IOException;
/** /**
* Serialize the generic object into xml. If the object is not a generic, use * Serialize the object into xml.
* {@link #toXML(Object, Type)} */
*/ public String toXML(Object src) throws IOException;
public <T> String toXML(Object src, Class<T> type) throws IOException;
/** /**
* Deserialize the generic object from xml. If the object is not a generic type, use * Serialize the object into xml, as the declared type.
* {@link #fromXML(Object, Class)} */
*/ public <T> String toXML(Object src, Class<T> type) throws IOException;
public <T> T fromXML(String xml, Class<T> type) throws IOException;
/**
* Deserialize the object from xml.
*/
public <T> T fromXML(String xml, Class<T> type) throws IOException;
} }

View File

@ -39,45 +39,35 @@ import org.jclouds.xml.XMLParser;
* @see ParseXMLWithJAXB * @see ParseXMLWithJAXB
*/ */
@Singleton @Singleton
public class JAXBParser implements XMLParser public class JAXBParser implements XMLParser {
{ @Override
@Override public String toXML(final Object src) throws IOException {
public String toXML(final Object src) throws IOException return toXML(src, src.getClass());
{ }
return toXML(src, src.getClass());
}
@Override @Override
public <T> String toXML(final Object src, final Class<T> type) throws IOException public <T> String toXML(final Object src, final Class<T> type) throws IOException {
{ try {
try JAXBContext context = JAXBContext.newInstance(type);
{ Marshaller marshaller = context.createMarshaller();
JAXBContext context = JAXBContext.newInstance(type); StringWriter writer = new StringWriter();
Marshaller marshaller = context.createMarshaller(); marshaller.marshal(src, writer);
StringWriter writer = new StringWriter(); return writer.toString();
marshaller.marshal(src, writer); } catch (JAXBException ex) {
return writer.toString(); throw new IOException("Could not marshall object", ex);
} }
catch (JAXBException ex) }
{
throw new IOException("Could not marshall object", ex);
}
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T> T fromXML(final String xml, final Class<T> type) throws IOException public <T> T fromXML(final String xml, final Class<T> type) throws IOException {
{ try {
try StringReader reader = new StringReader(xml);
{ JAXBContext context = JAXBContext.newInstance(type);
StringReader reader = new StringReader(xml); Unmarshaller unmarshaller = context.createUnmarshaller();
JAXBContext context = JAXBContext.newInstance(type); return (T) unmarshaller.unmarshal(reader);
Unmarshaller unmarshaller = context.createUnmarshaller(); } catch (Exception ex) {
return (T) unmarshaller.unmarshal(reader); throw new IOException("Could not unmarshall document", ex);
} }
catch (Exception ex) }
{
throw new IOException("Could not unmarshall document", ex);
}
}
} }

View File

@ -39,55 +39,54 @@ import com.google.common.collect.Multimap;
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
@Test(groups = "unit", testName = "BindToXMLPayloadTest") @Test(groups = "unit", testName = "BindToXMLPayloadTest")
public class BindToXMLPayloadTest public class BindToXMLPayloadTest {
{ XMLParser xml = new JAXBParser();
XMLParser xml = new JAXBParser();
@Test @Test
public void testBindJAXBObject() throws SecurityException, NoSuchMethodException public void testBindJAXBObject() throws SecurityException, NoSuchMethodException {
{ BindToXMLPayload binder = new BindToXMLPayload(xml);
BindToXMLPayload binder = new BindToXMLPayload(xml);
// Build the object to bind
TestJAXBDomain obj = new TestJAXBDomain();
obj.setElem("Hello World");
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build(); // Build the object to bind
request = binder.bindToRequest(request, obj); TestJAXBDomain obj = new TestJAXBDomain();
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER + "<test><elem>Hello World</elem></test>"); obj.setElem("Hello World");
assertEquals(request.getPayload().getContentMetadata().getContentType(), MediaType.APPLICATION_XML);
}
@Test
public void testHeaderIsChangedIfNeeded() throws SecurityException, NoSuchMethodException
{
BindToXMLPayload binder = new BindToXMLPayload(xml);
// Build the object to bind
TestJAXBDomain obj = new TestJAXBDomain();
obj.setElem("Hello World");
// Add teh unknown content-type header to verify it is changed by the binder HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build();
Multimap<String, String> headers = ImmutableMultimap.<String, String> of("Content-type", "application/unknown"); request = binder.bindToRequest(request, obj);
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).headers(headers).build(); assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER
+ "<test><elem>Hello World</elem></test>");
request = binder.bindToRequest(request, obj); assertEquals(request.getPayload().getContentMetadata().getContentType(), MediaType.APPLICATION_XML);
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER + "<test><elem>Hello World</elem></test>"); }
assertEquals(request.getPayload().getContentMetadata().getContentType(), MediaType.APPLICATION_XML);
}
@Test(expectedExceptions = NullPointerException.class) @Test
public void testNullIsBad() public void testHeaderIsChangedIfNeeded() throws SecurityException, NoSuchMethodException {
{ BindToXMLPayload binder = new BindToXMLPayload(xml);
BindToXMLPayload binder = new BindToXMLPayload(xml);
binder.bindToRequest(HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build(), null); // Build the object to bind
} TestJAXBDomain obj = new TestJAXBDomain();
obj.setElem("Hello World");
@Test(expectedExceptions = BindException.class)
public void testInvalidObjectBinding() // Add teh unknown content-type header to verify it is changed by the
{ // binder
BindToXMLPayload binder = new BindToXMLPayload(xml); Multimap<String, String> headers = ImmutableMultimap.<String, String> of("Content-type", "application/unknown");
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build(); HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).headers(headers)
request = binder.bindToRequest(request, new Object()); .build();
}
request = binder.bindToRequest(request, obj);
assertEquals(request.getPayload().getRawContent(), XMLParser.DEFAULT_XML_HEADER
+ "<test><elem>Hello World</elem></test>");
assertEquals(request.getPayload().getContentMetadata().getContentType(), MediaType.APPLICATION_XML);
}
@Test(expectedExceptions = NullPointerException.class)
public void testNullIsBad() {
BindToXMLPayload binder = new BindToXMLPayload(xml);
binder.bindToRequest(HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build(), null);
}
@Test(expectedExceptions = BindException.class)
public void testInvalidObjectBinding() {
BindToXMLPayload binder = new BindToXMLPayload(xml);
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://momma")).build();
request = binder.bindToRequest(request, new Object());
}
} }