All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.genability.client.api.service.BaseService Maven / Gradle / Ivy

package com.genability.client.api.service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.genability.client.util.JodaDateJsonSerializer;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.GzipCompressingEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.genability.client.api.request.BulkUploadRequest;
import com.genability.client.types.Response;

public class BaseService {
	
	protected final Logger log = LoggerFactory.getLogger(this.getClass());
	protected String restApiServer = "https://api.genability.com/rest/";

	protected String appId = null;
	protected String appKey = null;
	
	private ObjectMapper mapper;

	private HttpClient httpClient = HttpClientBuilder.create().build();
	private boolean requestCompression = false;
	
	public BaseService() {
	    mapper = new ObjectMapper();
	    mapper.registerModule(new JodaModule());
	    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
	    mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
	    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
	    mapper.setSerializationInclusion(Include.NON_NULL);
		SimpleModule module = new SimpleModule();
		module.addSerializer(DateTime.class, new JodaDateJsonSerializer());
		mapper.registerModule(module);
    }

	/**
	 * Mutator for IoC and configuration. If not called, this property defaults to 
	 * the Genability Production servers URL.
	 * @param restApiServer the restApiServer to set
	 */
	public void setRestApiServer(String restApiServer) {
		this.restApiServer = restApiServer;
	}
	
	public String getRestApiServer() {
		return restApiServer;
	}

	public void setAppId(String appId) {
		this.appId = appId;
	}

	public void setAppKey(String appKey) {
		this.appKey = appKey;
	}

	/**
	 * Mutator for IoC and configuration. Typically you don't need to worry about this
	 * as the default sets up a mapper for you.
	 * 
	 * @param mapper the mapper to set
	 */
	public void setMapper(ObjectMapper mapper) {
		this.mapper = mapper;
	}

	public ObjectMapper getMapper() {
		return mapper;
	}
	
	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public boolean getRequestCompression() {
		return requestCompression;
	}
	
	public void setRequestCompression(boolean requestCompression) {
		this.requestCompression = requestCompression;
	}
	
	/**
	 * Helper method that makes a HTTP GET to the Genability APIs.
	 * @param  The type parameter.
	 * @param  The type parameter.
	 * @param endpointPath The endpointPath.
	 * @param queryParams The queryParams.
	 * @param resultTypeReference The resultTypeReference.
	 * @return The return value.
	 */
	protected , R> T callGet(String endpointPath, List queryParams, TypeReference resultTypeReference) {
		String qs = null;

		String url = restApiServer + endpointPath; // + "?" + this.getQueryStringCredentials();  // if you prefer to pass creds on query string
		if(queryParams != null) qs = URLEncodedUtils.format(queryParams, "UTF-8");
		if(qs != null) url += "?" + qs;

		if(log.isDebugEnabled()) log.debug(qs);

		HttpGet getRequest = new HttpGet(url);
		if(log.isDebugEnabled()) log.debug(url);

		return execute(getRequest, resultTypeReference);
	}
	
	
	/**
	 * Helper method that makes a HTTP POST to the Genability APIs.
	 * @param  The type parameter.
	 * @param  The type parameter.
	 * @param endpointPath The endpointPath.
	 * @param requestPayload The requestPayload.
	 * @param resultTypeReference The resultTypeReference.
	 * @return The return value.
	 */
	protected , R> T callPost(String endpointPath, final Object requestPayload, TypeReference resultTypeReference) {
		String url = restApiServer + endpointPath;  // + "?" + this.getQueryStringCredentials();  // if you prefer to pass creds on query string
		if(log.isDebugEnabled()) log.debug(url);

		HttpPost postRequest = new HttpPost(url);
		postRequest.setEntity(getEntity(requestPayload));

		return execute(postRequest, resultTypeReference);
	}

	/**
	 * Helper method that makes a HTTP POST to the Genability APIs.
	 * @param  The type parameter.
	 * @param  The type parameter.
	 * @param endpointPath The endpointPath.
	 * @param requestPayload The requestPayload.
	 * @param resultTypeReference The resultTypeReference.
	 * @return The return value.
	 */
	protected , R> T callPut(String endpointPath, final Object requestPayload, TypeReference resultTypeReference) {
		String url = restApiServer + endpointPath; // + "?" +
														// this.getQueryStringCredentials();
														// // if you prefer to
														// pass creds on query
														// string
		if (log.isDebugEnabled())
			log.debug(url);

		HttpPut putRequest = new HttpPut(url);
		putRequest.setEntity(getEntity(requestPayload));

		return execute(putRequest, resultTypeReference);
	}
	
	/**
	 * This method is used to upload large datasets, typically CSV or XML files.
	 * The request object passed in contains the File to upload.
	 * @param  The type parameter.
	 * @param  The type parameter.
	 * @param endpointPath The endpointPath.
	 * @param request The request.
	 * @param resultTypeReference The resultTypeReference.
	 * @return The return value.
	 */
	public , R> T callFileUpload(String endpointPath, BulkUploadRequest request, TypeReference resultTypeReference) {
		String url = restApiServer + endpointPath;  // + "?" + this.getQueryStringCredentials();  // if you prefer to pass creds on query string

		if(log.isDebugEnabled()) log.debug(url);

		// Set up post request and set header auth
		HttpPost postRequest = new HttpPost(url);
		
		// Large files may take a while, so we are setting this to a 5 minute
		// timeout
		Builder requestConfigBuilder = RequestConfig.custom();
		requestConfigBuilder.setSocketTimeout(300000);
		postRequest.setConfig(requestConfigBuilder.build());

		MultipartEntityBuilder builder = MultipartEntityBuilder.create();
		builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

		// Set file data
		FileBody fileBody = new FileBody(request.getFileData());
		builder.addPart("fileData", fileBody);
		builder.addTextBody("fileFormat", request.getFileFormat(),
				ContentType.TEXT_XML);
		postRequest.setEntity(getEntity(builder.build()));

		return execute(postRequest, resultTypeReference);
	}
	
	/**
	 * Helper method that makes a HTTP DELETE to the Genability APIs.
	 * @param  The type parameter.
	 * @param  The type parameter.
	 * @param endpointPath The endpointPath.
	 * @param queryParams The queryParams.
	 * @param resultTypeReference The resultTypeReference.
	 * @return The return value.
	 */
	protected , R> T callDelete(String endpointPath, List queryParams, TypeReference resultTypeReference) {
		String qs = null;

		String url = restApiServer + endpointPath; // + "?" + this.getQueryStringCredentials();  // if you prefer to pass creds on query string
		if(queryParams != null) qs = URLEncodedUtils.format(queryParams, "UTF-8");
		if(qs != null) url += "?" + qs;

		if(log.isDebugEnabled()) log.debug(qs);

		HttpDelete deleteRequest = new HttpDelete(url);

		return execute(deleteRequest, resultTypeReference);
	} // end of callGet

	protected , R> T execute(final HttpRequestBase request, final TypeReference resultTypeReference) {
		try {
			request.addHeader("accept", "application/json");

			String basic_auth = new String(Base64.encodeBase64((appId + ":" + appKey).getBytes()));
			request.addHeader("Authorization", "Basic " + basic_auth);
			request.addHeader("Accept-Encoding", "gzip");
			request.addHeader("Connection", "close"); //close connections after we receive a response

			return httpClient.execute(request, new ResponseHandler() {
				@Override
				public T handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException {
					if (httpResponse.getStatusLine().getStatusCode() != 200) {
						String responseBody = null;
						try {
							responseBody = EntityUtils.toString(httpResponse.getEntity());
						}
						catch (IOException ex) {}

						throw new GenabilityException("Failed " + request.getMethod() + " " + request.getURI() +
								": HTTP error code : " + httpResponse.getStatusLine().getStatusCode(), responseBody);
					}

					//
					// Convert the JSON pay-load to the standard Response object.
					//
					return mapper.readValue(httpResponse.getEntity().getContent(), resultTypeReference);
				}
			});

		}
		catch (ClientProtocolException e) {
			log.error("ClientProtocolException", e);
			throw new GenabilityException(e);
		}
		catch (IOException e) {
			log.error("IOException", e);
			throw new GenabilityException(e);
		}
	}

	private HttpEntity getEntity(Object obj) {
		return getEntity(new JacksonHttpEntity(obj));
	}
	
	private HttpEntity getEntity(HttpEntity ent) {
		if (requestCompression) {
			return new GzipCompressingEntity(ent);
		} else {
			return ent;
		}
	}
	
	private class JacksonHttpEntity extends AbstractHttpEntity {

		private final Object object;

		public JacksonHttpEntity(final Object object) {
			this.object = object;

			setContentType(ContentType.APPLICATION_JSON.getMimeType());
		}

		@Override
		public long getContentLength() {
			return -1;
		}

		@Override
		public boolean isRepeatable() {
			return true;
		}

		@Override
		public boolean isStreaming() {
			return false;
		}

		@Override
		public InputStream getContent() throws IOException {
			return new ByteArrayInputStream(mapper.writeValueAsBytes(object));
		}

		@Override
		public void writeTo(final OutputStream outstream) throws IOException {
			if (outstream == null) {
				throw new IllegalArgumentException("Output stream may not be null");
			}
			mapper.writeValue(outstream, object);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy