package org.odata4j.examples.cxf.consumer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.net.URI; import java.util.List; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status.Family; import javax.ws.rs.core.Response.StatusType; import javax.ws.rs.core.UriBuilder; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.core4j.Enumerable; import org.odata4j.consumer.AbstractODataClient; import org.odata4j.consumer.ODataClientBatchResponse; import org.odata4j.consumer.ODataClientRequest; import org.odata4j.consumer.ODataClientResponse; import org.odata4j.consumer.behaviors.OClientBehavior; import org.odata4j.consumer.behaviors.OClientBehaviors; import org.odata4j.core.ODataConstants; import org.odata4j.core.ODataConstants.Charsets; import org.odata4j.core.ODataHttpMethod; import org.odata4j.core.OError; import org.odata4j.core.Throwables; import org.odata4j.exceptions.ODataProducerException; import org.odata4j.exceptions.ODataProducerExceptions; import org.odata4j.format.Entry; import org.odata4j.format.FormatParserFactory; import org.odata4j.format.FormatType; import org.odata4j.format.FormatWriter; import org.odata4j.format.FormatWriterFactory; import org.odata4j.format.SingleLink; import org.odata4j.internal.BOMWorkaroundReader; import org.odata4j.stax2.XMLEventReader2; import org.odata4j.stax2.util.StaxUtil; /** * OData client based on Apache's HTTP client implementation. */ public class ODataCxfClient extends AbstractODataClient { private final OClientBehavior[] requiredBehaviors = new OClientBehavior[] { OClientBehaviors.methodTunneling("MERGE") }; private final OClientBehavior[] behaviors; private final HttpClient httpClient; public ODataCxfClient(FormatType type, OClientBehavior... behaviors) { super(type); this.behaviors = Enumerable.create(requiredBehaviors).concat(Enumerable.create(behaviors)).toArray(OClientBehavior.class); this.httpClient = new DefaultHttpClient(); if (System.getProperties().containsKey("http.proxyHost") && System.getProperties().containsKey("http.proxyPort")) { // support proxy settings String hostName = System.getProperties().getProperty("http.proxyHost"); String hostPort = System.getProperties().getProperty("http.proxyPort"); HttpHost proxy = new HttpHost(hostName, Integer.parseInt(hostPort)); this.httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); } } public Reader getFeedReader(ODataClientResponse response) { HttpResponse httpResponse = ((CxfClientResponse) response).getHttpResponse(); try { InputStream textEntity = httpResponse.getEntity().getContent(); return new BOMWorkaroundReader(new InputStreamReader(textEntity, Charsets.Upper.UTF_8)); } catch (Exception e) { throw Throwables.propagate(e); } } public String requestBody(FormatType formatType, ODataClientRequest request) throws ODataProducerException { ODataClientResponse response = doRequest(formatType, request, Status.OK); String string = entityToString(((CxfClientResponse) response).getHttpResponse().getEntity()); response.close(); return string; } @SuppressWarnings("unchecked") protected ODataClientResponse doRequest(FormatType reqType, ODataClientRequest request, StatusType... expectedResponseStatus) throws ODataProducerException { UriBuilder uriBuilder = UriBuilder.fromPath(request.getUrl()); for (String key : request.getQueryParams().keySet()) uriBuilder = uriBuilder.queryParam(key, request.getQueryParams().get(key)); URI uri = uriBuilder.build(); if (this.behaviors != null) { for (OClientBehavior behavior : behaviors) request = behavior.transform(request); } HttpUriRequest httpRequest = this.getRequestByMethod(request.getMethod(), uri); // maybe something better is needed here String acceptHeader = ""; for (int i = 0; i < reqType.getAcceptableMediaTypes().length; i++) { acceptHeader += reqType.getAcceptableMediaTypes()[i]; if (i < reqType.getAcceptableMediaTypes().length - 1) acceptHeader += ", "; } if (acceptHeader.length() > 0) httpRequest.addHeader(HttpHeaders.ACCEPT, acceptHeader); for (String header : request.getHeaders().keySet()) httpRequest.addHeader(header, request.getHeaders().get(header)); if (!request.getHeaders().containsKey(ODataConstants.Headers.USER_AGENT)) httpRequest.addHeader(ODataConstants.Headers.USER_AGENT, "odata4j.org"); if (request.getPayload() != null && httpRequest instanceof HttpEntityEnclosingRequest) { HttpEntityEnclosingRequest entityRequest = (HttpEntityEnclosingRequest) httpRequest; Class<?> payloadClass; if (request.getPayload() instanceof Entry) payloadClass = Entry.class; else if (request.getPayload() instanceof SingleLink) payloadClass = SingleLink.class; else throw new IllegalArgumentException("Unsupported payload: " + request.getPayload()); StringWriter sw = new StringWriter(); FormatWriter<Object> fw = (FormatWriter<Object>) FormatWriterFactory.getFormatWriter(payloadClass, null, this.getFormatType().toString(), null); fw.write(null, sw, request.getPayload()); String entityString = sw.toString(); // allow the client to override the default format writer content-type String contentType = request.getHeaders().containsKey(ODataConstants.Headers.CONTENT_TYPE) ? request.getHeaders().get(ODataConstants.Headers.CONTENT_TYPE) : fw.getContentType(); try { StringEntity entity = new StringEntity(entityString); entity.setContentType(contentType); entityRequest.setEntity(entity); } catch (UnsupportedEncodingException e) { Throwables.propagate(e); } } // execute request HttpResponse httpResponse = null; try { httpResponse = this.httpClient.execute(httpRequest); } catch (IOException e) { Throwables.propagate(e); } StatusType status = Status.fromStatusCode(httpResponse.getStatusLine().getStatusCode()); if (status == null) { final StatusLine statusLine = httpResponse.getStatusLine(); status = new StatusType() { public int getStatusCode() { return statusLine.getStatusCode(); } public Family getFamily() { return null; } public String getReasonPhrase() { return statusLine.getReasonPhrase(); } }; } for (StatusType expStatus : expectedResponseStatus) if (expStatus.getStatusCode() == status.getStatusCode()) return new CxfClientResponse(httpResponse); // the server responded with an unexpected status RuntimeException exception; String textEntity = entityToString(httpResponse.getEntity()); // input stream can only be consumed once try { // report error as ODataProducerException in case we get a well-formed OData error... MediaType contentType = MediaType.valueOf(httpResponse.getEntity().getContentType().getValue()); OError error = FormatParserFactory.getParser(OError.class, contentType, null).parse(new StringReader(textEntity)); exception = ODataProducerExceptions.create(status, error); } catch (RuntimeException e) { // ... otherwise throw a RuntimeError exception = new RuntimeException(String.format("Expected status %s, found %s. Server response:", Enumerable.create(expectedResponseStatus).join(" or "), status) + "\n" + textEntity, e); } throw exception; } protected XMLEventReader2 toXml(ODataClientResponse response) { HttpResponse httpResponse = ((CxfClientResponse) response).getHttpResponse(); try { InputStream textEntity = httpResponse.getEntity().getContent(); return StaxUtil.newXMLEventReader(new BOMWorkaroundReader(new InputStreamReader(textEntity, Charsets.Upper.UTF_8))); } catch (Exception e) { throw Throwables.propagate(e); } } private HttpUriRequest getRequestByMethod(String method, URI uri) { switch (ODataHttpMethod.fromString(method)) { case GET: return new HttpGet(uri); case PUT: return new HttpPut(uri); case POST: return new HttpPost(uri); case DELETE: return new HttpDelete(uri); case OPTIONS: return new HttpOptions(uri); case HEAD: return new HttpHead(uri); default: throw new RuntimeException("Method unknown: " + method); } } private String entityToString(HttpEntity entity) { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), Charsets.Upper.UTF_8)); StringBuilder stringBuilder = new StringBuilder(); String line = null; while ((line = bufferedReader.readLine()) != null) stringBuilder.append(line); bufferedReader.close(); return stringBuilder.toString(); } catch (IOException e) { Throwables.propagate(e); return null; } } @Override public List<ODataClientBatchResponse> batchRequest(FormatType formatType, ODataClientRequest batchRequest, List<?> childRequests) throws ODataProducerException { // TODO Auto-generated method stub return null; } @Override public Reader getFeedReader(String payload) { // TODO Auto-generated method stub return null; } }