Clients like REST part 3
October 20th, 2010 § Leave a Comment
This post is the third one of a mini-series:
| Clients Like REST part 1 | Apache HTTP Commons Client |
| Clients Like REST part 2 | Native J2SE API Client |
| Clients Like REST part 3 | JAX-WS client API |
I will now show you how to access REST services using the JAX-WS client API, but first let me explain the motivation behind this selection. After all JAX-WS is typically used with SOAP services and assumes that a WSDL resides on the server side, so why bother at all with JAX-WS when you can use the JAX-RS client API to consume logically enough REST services? I think that there are quite a few situations where JAX-WS makes sense, and besides JAX-RS examples to access a REST service abound, so here is a list of possible reasons for wanting to use JAX-WS to access a REST service:
- You want to use a single API on the client side to handle both SOAP and REST services (The Dispatch API is particularly flexible, allowing you to handle SOAP-style messages with Header + Payload or REST-style messages with just a Payload, you are also free to use a data binding tool other than JAXB if needs be, Castor comes to mind)
- You want to use an API included in the JDK
- You want to support synchronous, asynchronous and one-way calls without resorting to 3rd-party solutions like COMET
- You want to abstract the actual binding of the transport (JAX-WS allows you to use SOAP 1.1 over HTTP, SOAP 1.2 over HTTP or XML over HTTP)
- You want to abstract the class of objects used for messages: The JAX-WS Dispatch API mandates the support of at least three types (
javax.xml.transform.Source,javax.xml.soap.SOAPMessageandjavax.activation.DataSourceuseful for MIME messages)
We will go over the client code to access the same service – defined through the interface IAutoStatService – and I will note along the way where does the API feel awkward to work with and where it does have some very interesting potential. Again I will illustrate how to add/delete/get/get all and update AutoStatistics, but you will notice right away that everything is very much XML-oriented (as opposed to, say, json). The reason is simple: No matter what binding you use for transport (SOAP 1.1 over HTTP, SOAP 1.2 over HTTP or XML over HTTP) it assumes an XML format. This can be limiting, but unless you use a 3rd party client library such as Jettison you are stuck with XML manipulation when using the plain-vanilla JAX-WS API from the JDK. I made a deliberate attempt to avoid using non-JDK API such as CXF on the client side even though classes such as JaxWsProxyFactoryBean can be quite useful. On the other hand if you are perfectly happy working with XML you will see that JAX-WS integrates naturally with the javax.xml.transform.Source and the javax.xml.transform.Transformer classes. From there any high-level XML API (I used XPath for e.g.) can be readily used.
On the awkward side you will note that JAX-WS expects a WSDL-oriented development and forces you to define two qualified names for the service and the port even though the Dispatch class allows you to handle raw XML. This is illustrated in the javax.xml.ws.Service.createDispatch(QName portName, Class<Source> type, Mode mode) method where you will set the Mode to Service.Mode.PAYLOAD as opposed to Service.Mode.MESSAGE to express the need to work with XML contents without a SOAP envelope, as is the case with REST services.
I also noticed a bug in the CXF implementation (2.2.3) I was using; even though my GET operations are invoked without an additional argument I could not simply call javax.xml.ws.Dispatch.invoke(null) as it would throw an exception, I had to pass in a fake request that would get ignored on the server side without any visible side-effect. My understanding is that the latest Glassfish and Axis2 do not suffer from such a bug. This shouldn’t detract you from using CXF on the server-side…
So here is the code:
package com.apptotest.client;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.http.HTTPBinding;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* We'll use the JAX-WS 2.x API (included in the SDK) to connect and test the following
* REST operations:
* - POST
* - DELETE
* - GET
* - PUT
*/
public class AutoStatServiceImplJAXWSClientTest {
private static final String hostname = "http://localhost:7650/autoStats/AutoStatService";
private Transformer transformer;
@Before
public void setUp() throws Exception {
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
}
/**
* corresponding to URL: http://localhost:7650/cxfweb_ajax/cxf/rest/CustomerService/add
* @throws Exception
*/
@Test
public final void testAddAutoStat() throws Exception {
String xmlAutoStatistics = "9000006150.0BMW 335ix13.3119.04.7";
QName serviceName = new QName("http://test", "fakeservicename");
QName portName = new QName("http://test", "fakeportname");
Service service = Service.create(serviceName);
service.addPort(portName, HTTPBinding.HTTP_BINDING, hostname + "/add");
Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
Map requestContext = dispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "POST");
Map> httpRequestHeaders = new HashMap>();
httpRequestHeaders.put("Content-Type", Arrays.asList(new String[] { "application/xml" }));
httpRequestHeaders.put("Accept", Arrays.asList(new String[] { "application/xml" }));
httpRequestHeaders.put("Content-Length", Arrays.asList(new String[] { Integer.toString(xmlAutoStatistics.length()) }));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpRequestHeaders);
Source result = dispatch.invoke(new StreamSource(new ByteArrayInputStream(xmlAutoStatistics.getBytes())));
StringWriter writer = new StringWriter();
transformer.transform(result, new StreamResult(writer));
Map responseContext = dispatch.getResponseContext();
if (!responseContext.get(org.apache.cxf.message.Message.RESPONSE_CODE).equals(new Integer(200))) {
fail("GET method failed: " + responseContext.get("org.apache.cxf.service.model.MessageInfo"));
} else {
String expectedResponse = "9000006150.0BMW 335ix13.3119.04.7";
assertTrue(writer.toString().contains(expectedResponse));
}
}
/**
* corresponding to URL: http://localhost:7650/autoStats/AutoStatService/delete/{id}
* where {id} gets expanded by the REST template
* @throws Exception
*/
@Test
public final void testDeleteAutoStat() throws Exception {
QName serviceName = new QName("http://test", "fakeservicename");
QName portName = new QName("http://test", "fakeportname");
Service service = Service.create(serviceName);
service.addPort(portName, HTTPBinding.HTTP_BINDING, hostname + "/delete/10003");
Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
Map requestContext = dispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "DELETE");
Map> httpRequestHeaders = new HashMap>();
httpRequestHeaders.put("Content-Type", Arrays.asList(new String[] { "application/xml" }));
httpRequestHeaders.put("Accept", Arrays.asList(new String[] { "application/xml" }));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpRequestHeaders);
String sampleBodyContent = ""
+ "HELLO THERE!!!" + "";
DOMSource request = createDOMSourceFromString(sampleBodyContent);
Source result = dispatch.invoke(request);
StringWriter writer = new StringWriter();
transformer.transform(result, new StreamResult(writer));
Map responseContext = dispatch.getResponseContext();
if (!responseContext.get(org.apache.cxf.message.Message.RESPONSE_CODE).equals(new Integer(200))) {
fail("GET method failed: " + responseContext.get("org.apache.cxf.service.model.MessageInfo"));
} else {
String expectedResponse = "";
assertTrue(writer.toString().contains(expectedResponse));
}
}
/**
* corresponding URL: http://localhost:7650/autoStats/AutoStatService/all
* @throws Exception
*/
@Test
public final void testGetAutoStats() throws Exception {
QName serviceName = new QName("http://test", "fakeservicename");
QName portName = new QName("http://test", "fakeportname");
Service service = Service.create(serviceName);
service.addPort(portName, HTTPBinding.HTTP_BINDING, hostname + "/all");
Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
Map requestContext = dispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "GET");
Map> httpRequestHeaders = new HashMap>();
httpRequestHeaders.put("content-type", Arrays.asList(new String[]{ "application/xml;charset=UTF-8" }));
httpRequestHeaders.put("Content-Type", Arrays.asList(new String[]{ "application/xml;charset=UTF-8" }));
httpRequestHeaders.put("Accept", Arrays.asList(new String[]{ "application/xml" }));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpRequestHeaders);
String sampleBodyContent = ""
+ "HELLO THERE!!!" + "";
DOMSource request = createDOMSourceFromString(sampleBodyContent);
Source result = dispatch.invoke(request);
StringWriter writer = new StringWriter();
transformer.transform(result, new StreamResult(writer));
XPath xpath= XPathFactory.newInstance().newXPath();
InputSource xmlSource = new InputSource(new StringReader(writer.toString()));
Map responseContext = dispatch.getResponseContext();
if (!responseContext.get(org.apache.cxf.message.Message.RESPONSE_CODE).equals(new Integer(200))) {
fail("GET method failed: " + responseContext.get("org.apache.cxf.service.model.MessageInfo"));
} else {
XPathExpression allAutoStatisticsExpr = xpath.compile("//AllAutoStatistics");
Element allStatsElement = (Element) allAutoStatisticsExpr.evaluate(xmlSource, XPathConstants.NODE);
assertNotNull(allStatsElement);
NodeList allStatsChildren = allStatsElement.getChildNodes();
assertTrue("AllAutoStatistics num,of children: " + allStatsChildren.getLength(), allStatsChildren.getLength() >= 6);
Node allStatsChild = allStatsChildren.item(0);
assertTrue(allStatsChild.hasChildNodes());
}
}
/**
* corresponding URL: http://localhost:7650/autoStats/AutoStatService/autostats/1000002
* @throws Exception
*/
@Test
public final void testGetAutoStatAsXml() throws Exception {
QName serviceName = new QName("http://test", "fakeservicename");
QName portName = new QName("http://test", "fakeportname");
Service service = Service.create(serviceName);
service.addPort(portName, HTTPBinding.HTTP_BINDING, hostname + "/autostats/1000002");
Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
Map requestContext = dispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "GET");
Map> httpRequestHeaders = new HashMap>();
httpRequestHeaders.put("content-type", Arrays.asList(new String[]{ "application/xml;charset=UTF-8" }));
httpRequestHeaders.put("Content-Type", Arrays.asList(new String[]{ "application/xml;charset=UTF-8" }));
httpRequestHeaders.put("Accept", Arrays.asList(new String[]{ "application/xml" }));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpRequestHeaders);
String sampleBodyContent = ""
+ "HELLO THERE!!!" + "";
DOMSource request = createDOMSourceFromString(sampleBodyContent);
Source result = dispatch.invoke(request);
StringWriter writer = new StringWriter();
transformer.transform(result, new StreamResult(writer));
Map responseContext = dispatch.getResponseContext();
if (!responseContext.get(org.apache.cxf.message.Message.RESPONSE_CODE).equals(new Integer(200))) {
fail("GET method failed: " + responseContext.get("org.apache.cxf.service.model.MessageInfo"));
} else {
String expectedResponse = "1000002181.0Alfa Romeo 8C Competizione12.4105.04.2";
assertTrue(writer.toString().contains(expectedResponse));
}
}
/**
* corresponding URL: http://localhost:7650/cxfweb_ajax/cxf/rest/CustomerService/edit
* @throws Exception
*/
@Test
public final void testUpdateAutoStat() throws Exception {
String xmlAutoStatistics = "1000003130.0Audi A5 2.0T Quattro - Updated JAX-WS14.8130.06.2";
QName serviceName = new QName("http://test", "fakeservicename");
QName portName = new QName("http://test", "fakeportname");
Service service = Service.create(serviceName);
service.addPort(portName, HTTPBinding.HTTP_BINDING, hostname + "/edit");
Dispatch dispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
Map requestContext = dispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "POST");
Map> httpRequestHeaders = new HashMap>();
httpRequestHeaders.put("Content-Type", Arrays.asList(new String[] { "application/xml" }));
httpRequestHeaders.put("Accept", Arrays.asList(new String[] { "application/xml" }));
httpRequestHeaders.put("Content-Length", Arrays.asList(new String[] { Integer.toString(xmlAutoStatistics.length()) }));
requestContext.put(MessageContext.HTTP_REQUEST_HEADERS, httpRequestHeaders);
Source result = dispatch.invoke(new StreamSource(new ByteArrayInputStream(xmlAutoStatistics.getBytes())));
StringWriter writer = new StringWriter();
transformer.transform(result, new StreamResult(writer));
Map responseContext = dispatch.getResponseContext();
if (!responseContext.get(org.apache.cxf.message.Message.RESPONSE_CODE).equals(new Integer(200))) {
fail("GET method failed: " + responseContext.get("org.apache.cxf.service.model.MessageInfo"));
} else {
assertTrue(writer.toString().contains(expectedResponse));
}
}
/**
* @param input
* @return
* @throws Exception
*/
private DOMSource createDOMSourceFromString(String input) throws Exception {
byte[] bytes = input.getBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(false);
domFactory.setFeature("http://xml.org/sax/features/namespaces", false);
domFactory.setFeature("http://xml.org/sax/features/validation", false);
domFactory.setFeature("http://apache.org/xml/features/validation/schema", false);
DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
Document domTree = domBuilder.parse(stream);
Node node = domTree.getDocumentElement();
DOMSource domSource = new DOMSource(node);
return domSource;
}
}
Clients like REST part 2
October 8th, 2010 § Leave a Comment
This post is the second one of a mini-series:
| Clients Like REST part 1 | Apache HTTP Commons Client |
| Clients Like REST part 2 | Native J2SE API Client |
| Clients Like REST part 3 | JAX-WS client API |
This post will show you how to access the same service – defined through the interface IAutoStatService – using the native J2SE API and in particular how to take full advantage of the HttpURLConnection class. I think that this is a pretty powerful concept: You can access a web service from a Java client without a 3rd party web-service library and without the need to write some type of parser.
Here are some notes about this client implementation:
- It relies on the lowest common denominator to all java apps only, the JDK
- To be complete I will mention that I am using the Jackson JSON processor to construct JSON strings from a POJO and vice versa de-serializing a JSON string coming on an input stream into a POJO; it’s just a convenience tool that does not contradict the above point (using just the native J2SE API)
- Again, there is nothing in this API that is REST-specific or even Web Services-specific; this point is worth stressing, by properly setting up the @javax.ws.rs.Path annotation on the server class the client will be able to call the addAutoStatistics() operation, for example, simply by constructing a POST request in the form http://<host>:<port>/autoStats/AutoStatService/add
- Since we are mainly relying on the HttpURLConnection class you will be forced to think in terms of the details of the HTTP protocol: What to set for Content-Type, Accept or Content-Length request properties? How to decode the HTTP response code? etc… But it’s not that bad and as a bonus your code would be easily portable to another language since these constructs are pretty generic
- You are not limited to a particular data format: if the server side produces JSON, you can de-serialize JSON into POJO, if the server side produces XML, you can de-serialize XML into POJO or use XQuery, etc…
- The testHttpURLConnection(HttpURLConnection connection) method is completely optional but helpful when debugging. It’s mainly included to show you how the various parts of the HTTP message (header/body) are constructed in each of the following cases: POST, DELETE and GET
package com.apptotest.client;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.Permission;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* TODO: We'll use a standard J2SE client (based on {@link HttpURLConnection} to connect
* and test the following REST operations:
* - POST
* - DELETE
* - GET
* - PUT
* This type of coding requires (some) help from the Jackson JSON library to interpret the
* {@link InputStream}.
*/
public class AutoStatServiceImplJ2SEClientTest {
private static final String hostname = "http://localhost:7650/autoStats/AutoStatService";
private URL url;
private HttpURLConnection conn;
private InputStream in;
private OutputStream out;
private ObjectMapper mapper;
@Before
public void setUp() throws Exception {
mapper = new ObjectMapper();
}
@After
public void tearDown() throws Exception {
if (in != null) { in.close(); }
if (out != null) { out.close(); }
if (conn != null) { conn.disconnect(); }
}
/**
* corresponding to URL: http://localhost:7650/autoStats/AutoStatService/add
* @throws Exception
*/
@Test
public final void testAddAutoStat() throws Exception {
AutoStatistics stat = new AutoStatistics("BMW 335i", 9000007L, 150F, 4.7F, 13.3F, 119F);
String jsonValue = mapper.writeValueAsString(stat);
url = new URL(hostname + "/add");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Length", Integer.toString(jsonValue.length()));
conn.getOutputStream().write(jsonValue.getBytes());
conn.getOutputStream().flush();
conn.connect();
testHttpURLConnection(conn);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
fail("POST method failed: " + conn.getResponseCode() + "\t" + conn.getResponseMessage());
} else {
InputStream responseContent = (InputStream) conn.getContent();
AutoStatistics respStat1 = mapper.readValue(responseContent, AutoStatistics.class);
assertNotNull(respStat1);
assertEquals(stat, respStat1);
}
}
/**
* corresponding to URL: http://localhost:7650/cxfweb_ajax/cxf/rest/AutoStatService/delete/{id}
* where {id} gets expanded by the REST template
*/
@Test
public final void testDeleteAutoStat() throws Exception {
url = new URL(hostname + "/delete/1000001");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("DELETE");
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.connect();
testHttpURLConnection(conn);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
fail("DELETE method failed: " + conn.getResponseCode() + "\t" + conn.getResponseMessage());
} else {
InputStream responseContent = (InputStream) conn.getContent();
AutoStatistics respStat1 = mapper.readValue(responseContent, AutoStatistics.class);
assertNotNull(respStat1);
assertEquals(new AutoStatistics(), respStat1);
}
}
/**
* corresponding URL: http://localhost:7650/autoStats/AutoStatService/all
* @throws Exception
*/
@Test
public final void testGetAutoStats() throws Exception {
url = new URL(hostname + "/all");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.connect();
in = conn.getInputStream();
testHttpURLConnection(conn);
if (conn.getContentType().equals("application/json")) {
mapper = new ObjectMapper();
AllAutoStatistics stats = mapper.readValue(in, AllAutoStatistics.class);
assertNotNull(stats);
assertNotNull(stats.getAllStats());
Collection<AutoStatistics> allStats = (Collection<AutoStatistics>) stats.getAllStats();
assertTrue(allStats.contains(new AutoStatistics("Alfa Romeo 8C Competizione", 1000002L, 181F, 4.2F, 12.4F, 105F)));
assertTrue(allStats.contains(new AutoStatistics("Cadillac CTS-V", 1000004L, 191F, 4.1F, 12.3F, 114F)));
}
}
/**
* corresponding URL: http://localhost:7650/autoStats/AutoStatService/autostats/1000002
* @throws Exception
*/
@Test
public final void testGetAutoStatAsXml() throws Exception {
url = new URL(hostname + "/autostats/1000002");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-Type", "application/xml;charset=UTF-8");
conn.setRequestProperty("Accept", "application/xml");
conn.connect();
in = conn.getInputStream();
testHttpURLConnection(conn);
if (conn.getContentType().equals("application/xml")) {
char[] buff = new char[128];
InputStreamReader isr = new InputStreamReader(in);
StringBuilder builder = new StringBuilder();
while (isr.read(buff) != -1) {
builder.append(buff);
}
assertTrue(builder.length() > 0);
String expectedResponse = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><AutoStatistics><id>1000002</id><maxSpeed>181.0</maxSpeed><name>Alfa Romeo 8C Competizione</name><quarterMileTimeInSecs>12.4</quarterMileTimeInSecs><sixtyToZeroDistanceInFt>105.0</sixtyToZeroDistanceInFt><zeroToSixtyTimeInSecs>4.2</zeroToSixtyTimeInSecs></AutoStatistics>";
assertTrue(builder.toString().contains(expectedResponse));
}
}
/**
* corresponding URL: http://localhost:7650/autoStats/AutoStatService/autostats/1000002
*
* @throws Exception
*/
@Test
public final void testGetAutoStatAsJson() throws Exception {
url = new URL(hostname + "/autostats/1000002");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.connect();
in = conn.getInputStream();
testHttpURLConnection(conn);
if (conn.getContentType().equals("application/json")) {
mapper = new ObjectMapper();
AutoStatistics stat = mapper.readValue(in, AutoStatistics.class);
assertNotNull(stat);
assertEquals("name", "Alfa Romeo 8C Competizione", stat.getName());
assertEquals("id", 1000002L, stat.getId().longValue());
assertEquals("maxSpeed", 181.0F, stat.getMaxSpeed().floatValue(), 0.0);
assertEquals("zeroToSixtyTimeInSecs", 4.2F, stat.getZeroToSixtyTimeInSecs().floatValue(), 0.0);
assertEquals("quarterMileTimeInSecs", 12.4F, stat.getQuarterMileTimeInSecs().floatValue(), 0.0);
assertEquals("sixtyToZeroDistanceInFt", 105.0F, stat.getSixtyToZeroDistanceInFt().floatValue(), 0.0);
}
}
/**
* corresponding URL: http://localhost:7650/autoStats/AutoStatService/edit
* @throws Exception
*/
@Test
public final void testUpdateAutoStat() throws Exception {
AutoStatistics stat = new AutoStatistics("Audi A5 2.0T Quattro - Updated J2SE", 1000003L, 130F, 6.2F, 14.8F, 130F);
String jsonValue = mapper.writeValueAsString(stat);
url = new URL(hostname + "/edit");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Length", Integer.toString(jsonValue.length()));
conn.getOutputStream().write(jsonValue.getBytes());
conn.getOutputStream().flush();
conn.connect();
testHttpURLConnection(conn);
if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
fail("POST method failed: " + conn.getResponseCode() + "\t" + conn.getResponseMessage());
} else {
InputStream responseContent = (InputStream) conn.getContent();
AutoStatistics respStat1 = mapper.readValue(responseContent, AutoStatistics.class);
assertNotNull(respStat1);
assertEquals(stat, respStat1);
// and test
url = new URL(hostname + "/all");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.connect();
in = conn.getInputStream();
AllAutoStatistics stats = mapper.readValue(in, AllAutoStatistics.class);
assertNotNull(stats);
assertNotNull(stats.getAllStats());
Collection<AutoStatistics> allStats = stats.getAllStats();
assertTrue(allStats.contains(new AutoStatistics("Audi A5 2.0T Quattro - Updated J2SE", 1000003L, 130F, 6.2F, 14.8F, 130F)));
}
}
/**
* @param connection
* @throws Exception
*/
private void testHttpURLConnection(HttpURLConnection connection) throws Exception {
boolean connAllowUserInteraction = connection.getAllowUserInteraction();
String connContentType = connection.getContentType();
String connContentEncoding = connection.getContentEncoding();
String connRequestMethod = connection.getRequestMethod();
boolean connDoInput = connection.getDoInput();
boolean connDoOutput = connection.getDoOutput();
Permission connPermission = connection.getPermission();
URL connURL = connection.getURL();
Map<String, List<String>> connHeaderFields = connection.getHeaderFields();
System.out.println("connAllowUserInteraction: " + connAllowUserInteraction);
System.out.println("connContentType: " + connContentType);
System.out.println("connContentEncoding: " + connContentEncoding);
System.out.println("connRequestMethod: " + connRequestMethod);
System.out.println("connDoInput: " + connDoInput);
System.out.println("connDoOutput: " + connDoOutput);
System.out.println("connPermission: " + connPermission);
System.out.println("connURL: " + connURL);
if (connHeaderFields != null) {
Set<Entry<String, List<String>>> connHeaderFieldsEntries = connHeaderFields.entrySet();
for (Entry<String, List<String>> entry : connHeaderFieldsEntries) {
System.out.println("connHeaderField: " + entry);
}
}
}
}