Java tutorial
/** * (c) 2003-2014 MuleSoft, Inc. The software in this package is published under * the terms of the CPAL v1.0 license, a copy of which has been included with this * distribution in the LICENSE.md file. */ package org.mule.modules.handshake.client.impl; import java.io.IOException; import java.lang.reflect.Type; import java.math.BigDecimal; import java.security.KeyStore.Builder; import java.util.Map; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.mule.modules.handshake.client.serialization.BigDecimalAsStringSerializer; import org.mule.modules.handshake.client.serialization.HandshakeCustomerSerializer; import org.mule.modules.handshake.client.serialization.HandshakeItemSerializer; import org.mule.modules.handshake.client.serialization.HandshakeOrderSerializer; import org.mule.modules.handshake.core.Customer; import org.mule.modules.handshake.core.HandshakeAPIResponse; import org.mule.modules.handshake.core.Item; import org.mule.modules.handshake.core.Order; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.WebResource; import com.sun.jersey.api.client.config.ClientConfig; import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; import com.sun.jersey.api.client.filter.LoggingFilter; import com.sun.jersey.core.util.MultivaluedMapImpl; /** * Base class for all the service client in this project. The class handles: * * <ul> * <li>base URL creation</li> * <li>creation of the Jersey client</li> * <li>set up of basic authentication headers</li> * <li>read of files from input streams</li> * <li>string serialization of the responses</li> * </ul> */ public abstract class AbstractHandshakeClient { private final String baseUrl; protected final Gson gson; public AbstractHandshakeClient(final String baseUrl) { this.baseUrl = baseUrl; final GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Order.class, new HandshakeOrderSerializer()); builder.registerTypeAdapter(Customer.class, new HandshakeCustomerSerializer()); builder.registerTypeAdapter(Item.class, new HandshakeItemSerializer()); builder.registerTypeAdapter(BigDecimal.class, new BigDecimalAsStringSerializer()); this.gson = builder.create(); } /** * @return the base URL for the service, inclduing what is added by {@link AbstractHandshakeClient#extendGetBaseUrl(StringBuilder)} */ protected String getBaseURL() { return this.extendGetBaseUrl(new StringBuilder(this.baseUrl)).toString(); } /** * This method is called by getBaseURL for the user to extend the base URL * of its ServiceClient implementation. * * @param baseUrl a builder with the Base Url * @return the builder, with the extended content as needed */ protected abstract StringBuilder extendGetBaseUrl(final StringBuilder baseUrl); /** * Creates a {@link Builder} * * @param user for authentication * @param password for authentication * @param url the URL to be hit by the client * @param queryParameters a map containing all the query parameters * @return the builder. */ protected WebResource.Builder getBuilder(final String user, final String password, final String antiThrottleKey, final String url, final Map<String, String> queryParameters) { final ClientConfig clientConfig = getJerseyClientConfiguration(); Client client = null; if (clientConfig == null) { client = Client.create(); } else { client = Client.create(clientConfig); } client.addFilter(new LoggingFilter()); client.addFilter(getBasicAuthenticationFilter(user, password)); if (StringUtils.isNotBlank(antiThrottleKey)) { client.addFilter(new HandshakeAntiThrottleFilter(antiThrottleKey)); } final WebResource wr = client.resource(url); final MultivaluedMap<String, String> actualQueryParameters = mapToMultivaluedMap(queryParameters); // We want all request to return whole objects where possible, instead of just references if (!actualQueryParameters.containsKey("full")) { actualQueryParameters.putSingle("full", "true"); } return wr.queryParams(actualQueryParameters).type(MediaType.APPLICATION_JSON_TYPE); } protected <T> HandshakeAPIResponse<T> get(final WebResource.Builder resourceBuilder, final Type type) { final ClientResponse clientResponse = resourceBuilder.get(ClientResponse.class); return processResponse(clientResponse, type); } protected <T> T singleGet(final WebResource.Builder resourceBuilder, final Type type) { final ClientResponse clientResponse = resourceBuilder.get(ClientResponse.class); return processResponse(clientResponse, type); } protected <T> T post(final WebResource.Builder resourceBuilder, final Type requestType, final Type responseType, final Object params) { final String paramsString = gson.toJson(params, requestType); final ClientResponse clientResponse = resourceBuilder.post(ClientResponse.class, paramsString); return processResponse(clientResponse, responseType); } protected <T> T update(final WebResource.Builder resourceBuilder, final Type objectType, final T edited) { final String paramsString = gson.toJson(edited, objectType); final ClientResponse clientResponse = resourceBuilder.put(ClientResponse.class, paramsString); return processResponse(clientResponse, objectType); } /** * @param clientResponse returned by the invocation * @param responseType of the expected response * @return the response, null if not found, or an Exception if something bad happened */ private <T> T processResponse(final ClientResponse clientResponse, final Type responseType) { final String response = readResponseFromClientResponse(clientResponse); if (clientResponse.getStatus() == 404) { return null; } else if (clientResponse.getStatus() >= 400) { throw new HandshakeAPIException(response); } try { return parseJson(response, responseType); } catch (final IOException e) { throw new RuntimeException(e); } } /** * This method is called by getBuilder before the creation of the * {@link Client}. The {@link ClientConfig} is used to create the * {@link Client}. * * @return */ protected ClientConfig getJerseyClientConfiguration() { return null; } /** * Creates a {@link HTTPBasicAuthFilter} for HTTP basic authentication. * * @param user * @param password * @return a {@link HTTPBasicAuthFilter} to be added to the {@link Client} */ private HTTPBasicAuthFilter getBasicAuthenticationFilter(final String user, final String password) { return new HTTPBasicAuthFilter(user, password); } /** * Transform a map in a {@link MultivaluedMap} which is needed by Jersey to * send query parameters. It also validate that not empty parameters are * being send. * * @param map * the map of query parameters * @return the same map in an {@link MultivaluedMap} object. */ protected MultivaluedMap<String, String> mapToMultivaluedMap(final Map<String, String> map) { final MultivaluedMap<String, String> multivaluedMap = new MultivaluedMapImpl(); if (map != null && !map.isEmpty()) { for (final String key : map.keySet()) { multivaluedMap.add(key, map.get(key)); } } return multivaluedMap; } protected String readResponseFromClientResponse(final ClientResponse clientResponse) { try { return IOUtils.toString(clientResponse.getEntityInputStream()); } catch (final IOException e) { throw new RuntimeException(e); } } /** * Parse JSON to specified type * * @param <V> type of the object to obtain * @param string JSON-formatted string to parse * @param type of the object to obtain * @return parsed object * @throws IOException if the string is not JSON-formatted */ protected <V> V parseJson(final String string, final Type type) throws IOException { try { return gson.fromJson(string, type); } catch (final JsonParseException jpe) { final IOException ioe = new IOException("Parse exception converting JSON to object"); //$NON-NLS-1$ ioe.initCause(jpe); throw ioe; } } }