Java tutorial
/* Copyright 2008 Fabrizio Cannizzo * * This file is part of RestFixture. * * RestFixture (http://code.google.com/p/rest-fixture/) is free software: * you can redistribute it and/or modify it under the terms of the * GNU Lesser General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * RestFixture is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with RestFixture. If not, see <http://www.gnu.org/licenses/>. * * If you want to contact the author please leave a comment here * http://smartrics.blogspot.com/2008/08/get-fitnesse-with-some-rest.html */ package smartrics.rest.client; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; import java.util.List; import org.apache.commons.httpclient.*; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.FileRequestEntity; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A generic REST client based on {@code HttpClient}. */ public class RestClientImpl implements RestClient { private static Logger LOG = LoggerFactory.getLogger(RestClientImpl.class); private final HttpClient client; private String baseUrl; /** * Constructor allowing the injection of an {@code * org.apache.commons.httpclient.HttpClient}. * * @param client * the client * See {@link org.apache.commons.httpclient.HttpClient} */ public RestClientImpl(HttpClient client) { if (client == null) throw new IllegalArgumentException("Null HttpClient instance"); this.client = client; } /** * See {@link smartrics.rest.client.RestClient#setBaseUrl(java.lang.String)} */ public void setBaseUrl(String bUrl) { this.baseUrl = bUrl; } /** * See {@link smartrics.rest.client.RestClient#getBaseUrl()} */ public String getBaseUrl() { return baseUrl; } /** * Returns the Http client instance used by this implementation. * * @return the instance of HttpClient * See {@link org.apache.commons.httpclient.HttpClient} * See {@link smartrics.rest.client.RestClientImpl#RestClientImpl(HttpClient)} */ public HttpClient getClient() { return client; } /** * See {@link smartrics.rest.client.RestClient#execute(smartrics.rest.client.RestRequest)} */ public RestResponse execute(RestRequest request) { return execute(getBaseUrl(), request); } /** * See {@link smartrics.rest.client.RestClient#execute(java.lang.String, smartrics.rest.client.RestRequest)} */ public RestResponse execute(String hostAddr, final RestRequest request) { if (request == null || !request.isValid()) throw new IllegalArgumentException("Invalid request " + request); if (request.getTransactionId() == null) request.setTransactionId(Long.valueOf(System.currentTimeMillis())); LOG.debug("request: {}", request); HttpMethod m = createHttpClientMethod(request); configureHttpMethod(m, hostAddr, request); RestResponse resp = new RestResponse(); resp.setTransactionId(request.getTransactionId()); resp.setResource(request.getResource()); try { client.executeMethod(m); for (Header h : m.getResponseHeaders()) { resp.addHeader(h.getName(), h.getValue()); } resp.setStatusCode(m.getStatusCode()); resp.setStatusText(m.getStatusText()); resp.setBody(m.getResponseBodyAsString()); resp.setRawBody(m.getResponseBody()); } catch (HttpException e) { String message = "Http call failed for protocol failure"; throw new IllegalStateException(message, e); } catch (IOException e) { String message = "Http call failed for IO failure"; throw new IllegalStateException(message, e); } finally { m.releaseConnection(); } LOG.debug("response: {}", resp); return resp; } /** * Configures the instance of HttpMethod with the data in the request and * the host address. * * @param m * the method class to configure * @param hostAddr * the host address * @param request * the rest request */ protected void configureHttpMethod(HttpMethod m, String hostAddr, final RestRequest request) { addHeaders(m, request); setUri(m, hostAddr, request); m.setQueryString(request.getQuery()); if (m instanceof EntityEnclosingMethod) { RequestEntity requestEntity = null; String fileName = request.getFileName(); if (fileName != null) { requestEntity = configureFileUpload(fileName); } else { fileName = request.getMultipartFileName(); if (fileName != null) { requestEntity = configureMultipartFileUpload(m, request, requestEntity, fileName); } else { requestEntity = new RequestEntity() { public boolean isRepeatable() { return true; } public void writeRequest(OutputStream out) throws IOException { PrintWriter printer = new PrintWriter(out); printer.print(request.getBody()); printer.flush(); } public long getContentLength() { return request.getBody().getBytes().length; } public String getContentType() { List<smartrics.rest.client.RestData.Header> values = request.getHeader("Content-Type"); String v = "text/xml"; if (values.size() != 0) v = values.get(0).getValue(); return v; } }; } } ((EntityEnclosingMethod) m).setRequestEntity(requestEntity); } } private RequestEntity configureMultipartFileUpload(HttpMethod m, final RestRequest request, RequestEntity requestEntity, String fileName) { File file = new File(fileName); try { requestEntity = new MultipartRequestEntity( new Part[] { new FilePart(request.getMultipartFileParameterName(), file) }, ((EntityEnclosingMethod) m).getParams()); } catch (FileNotFoundException e) { throw new IllegalArgumentException("File not found: " + fileName, e); } return requestEntity; } private RequestEntity configureFileUpload(String fileName) { final File file = new File(fileName); if (!file.exists()) { throw new IllegalArgumentException("File not found: " + fileName); } return new FileRequestEntity(file, "application/octet-stream"); } public String getContentType(RestRequest request) { List<smartrics.rest.client.RestData.Header> values = request.getHeader("Content-Type"); String v = "text/xml"; if (values.size() != 0) v = values.get(0).getValue(); return v; } private void setUri(HttpMethod m, String hostAddr, RestRequest request) { String host = hostAddr == null ? client.getHostConfiguration().getHost() : hostAddr; if (host == null) throw new IllegalStateException("hostAddress is null: please config httpClient host configuration or " + "pass a valid host address or config a baseUrl on this client"); String uriString = host + request.getResource(); try { m.setURI(createUri(uriString, false)); } catch (URIException e) { throw new IllegalStateException("Problem when building URI: " + uriString, e); } catch (NullPointerException e) { throw new IllegalStateException("Building URI with null string", e); } } protected URI createUri(String uriString, boolean escaped) throws URIException { return new URI(uriString, escaped); } /** * factory method that maps a string with a HTTP method name to an * implementation class in Apache HttpClient. Currently the name is mapped * to <code>org.apache.commons.httpclient.methods.%sMethod</code> where * <code>%s</code> is the parameter mName. * * @param mName * the method name * @return the method class */ protected String getMethodClassnameFromMethodName(String mName) { return String.format("org.apache.commons.httpclient.methods.%sMethod", mName); } /** * Utility method that creates an instance of {@code * org.apache.commons.httpclient.HttpMethod}. * * @param request * the rest request * @return the instance of {@code org.apache.commons.httpclient.HttpMethod} * matching the method in RestRequest. */ @SuppressWarnings("unchecked") protected HttpMethod createHttpClientMethod(RestRequest request) { String mName = request.getMethod().toString(); String className = getMethodClassnameFromMethodName(mName); try { Class<HttpMethod> clazz = (Class<HttpMethod>) Class.forName(className); HttpMethod m = clazz.newInstance(); return m; } catch (ClassNotFoundException e) { throw new IllegalStateException( className + " not found: you may be using a too old or " + "too new version of HttpClient", e); } catch (InstantiationException e) { throw new IllegalStateException("An object of type " + className + " cannot be instantiated", e); } catch (IllegalAccessException e) { throw new IllegalStateException("The default ctor for type " + className + " cannot be invoked", e); } catch (RuntimeException e) { throw new IllegalStateException("Exception when instantiating: " + className, e); } } private void addHeaders(HttpMethod m, RestRequest request) { for (RestData.Header h : request.getHeaders()) { m.addRequestHeader(h.getName(), h.getValue()); } } }