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

com.threewks.thundr.http.service.BaseHttpService Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
/*
 * This file is a component of thundr, a software library from 3wks.
 * Read more: http://3wks.github.io/thundr/
 * Copyright (C) 2014 3wks, 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.threewks.thundr.http.service;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;

import com.atomicleopard.expressive.ETransformer;
import com.atomicleopard.expressive.Expressive;
import com.threewks.thundr.http.Authorization;
import com.threewks.thundr.http.ContentType;
import com.threewks.thundr.http.Header;
import com.threewks.thundr.http.URLEncoder;
import com.threewks.thundr.transformer.TransformerManager;

public abstract class BaseHttpService, Request extends BaseHttpRequest, Response extends BaseHttpResponse> implements
		HttpService {
	protected List HttpMethodsWithoutBodies = Expressive.list("GET", "HEAD", "OPTIONS", "DELETE");
	protected List HttpMethodsWithBodies = Expressive.list("POST", "PUT");
	protected String encoding = "UTF-8";
	protected TransformerManager transformerManager;

	protected BaseHttpService(TransformerManager transformerManager) {
		this.transformerManager = transformerManager;
	}

	@Override
	public abstract Request request(String url);

	protected abstract Response head(Request request) throws HttpException;

	protected abstract Response get(Request request) throws HttpException;

	protected abstract Response put(Request request) throws HttpException;

	protected abstract Response post(Request request) throws HttpException;

	protected abstract Response delete(Request request) throws HttpException;

	protected HttpEntity prepareMultipart(Request request) {
		MultipartEntityBuilder builder = MultipartEntityBuilder.create();
		for (Map.Entry parameter : request.getParameters().entrySet()) {
			String value = getValueAs(parameter.getValue(), String.class);
			builder.addTextBody(parameter.getKey(), value, org.apache.http.entity.ContentType.create("text/plain", "UTF-8"));
		}
		for (FileParameter fileParam : request.getFileParameters()) {
			Object body = fileParam.getBody();
			byte[] data = getValueAs(body, byte[].class);
			org.apache.http.entity.ContentType contentType = org.apache.http.entity.ContentType.create(fileParam.getContentType());
			ContentBody contentBody = new ByteArrayBody(data, contentType, fileParam.getFilename());
			builder.addPart(fileParam.getName(), contentBody);
		}

		HttpEntity httpEntity = builder.build();
		return httpEntity;
	}

	@SuppressWarnings("unchecked")
	protected  T getValueAs(Object value, Class desiredType) {
		Class type = (Class) (value == null ? null : value.getClass());
		T data = type == null ? null : transformerManager.transform(type, desiredType, value);
		return data;
	}

	protected String createFormPostBody(Request request) {
		List parameterPairs = new ArrayList<>();
		Map parameters = request.getParameters();
		for (Map.Entry parameter : parameters.entrySet()) {
			String value = getValueAs(parameter.getValue(), String.class);
			String pair = String.format("%s=%s", encodeParameter(parameter.getKey(), encoding), encodeParameter(value, encoding));
			parameterPairs.add(pair);
		}
		return StringUtils.join(parameterPairs, "&");
	}

	protected String createCookieHeaderValue(BaseHttpRequest request) {
		List cookieStrings = new ArrayList<>();
		for (HttpCookie httpCookie : request.getCookies()) {
			cookieStrings.add(httpCookie.toString());
		}
		return cookieStrings.isEmpty() ? null : StringUtils.join(cookieStrings, "; ");
	}

	protected boolean isMultipart(Request request) {
		String contentType = request.getHeader(Header.ContentType);
		boolean multipartContentType = ContentType.matchesAny(contentType, ContentType.MultipartFormData, ContentType.MultipartMixed);
		if (multipartContentType) {
			return true;
		}
		List fileParameters = request.getFileParameters();
		return Expressive.isNotEmpty(fileParameters);
	}

	/**
	 * Converts the given object to an InputStream reqdy to be written as the body of the request.
	 */
	@SuppressWarnings("unchecked")
	protected  InputStream convertOutgoing(T t) {
		try {
			ETransformer transformer = (ETransformer) transformerManager.getTransformerSafe(t.getClass(), InputStream.class);
			return transformer.from(t);
		} catch (Exception e) {
			throw new HttpException("Unable to transform the request object for output, please make sure a transformer from %s to %s is registered: %s", t.getClass().getSimpleName(),
					InputStream.class.getSimpleName(), e.getMessage());
		}
	}

	/**
	 * Converts the given {@link InputStream} into an instance of the specified type using a registered incoming transformer.
	 */
	protected  T convertIncoming(InputStream is, Class type) {
		try {

			ETransformer transformer = transformerManager.getTransformerSafe(InputStream.class, type);
			return transformer.from(is);
		} catch (Exception e) {
			throw new HttpException("Unable to transform the response to the type %s, please make sure a transformer from %s to %s is registered", type.getName(), InputStream.class.getSimpleName(),
					type.getSimpleName());
		}
	}

	/**
	 * Returns the url for the given request. Methods which do not contain bodies
	 * will encode request parameters into the query string, methods that do will retain
	 * the original url. This allows users to post/put with query strings by just passing
	 * them in originally.
	 * 
	 * @param request
	 * @param method
	 * @return
	 */
	protected String buildUrlString(Request request, String method) {
		String url = request.getUrl();
		if (HttpMethodsWithBodies.contains(method.toUpperCase())) {
			return url;
		} else {
			Map parameters = request.getParameters();

			String parameterString = parameters.isEmpty() ? "" : URLEncoder.encodeQueryString(parameters, transformerManager);
			if (url.contains("?")) {
				parameterString = StringUtils.replaceOnce(parameterString, "?", "&");
			}
			return url + parameterString;
		}
	}

	protected String getAuthorization(Request request) {
		String username = request.getUsername();
		String password = request.getPassword();
		String scheme = request.getScheme();
		if (username != null && password != null) {
			if (Authorization.Basic.equalsIgnoreCase(scheme)) {
				return Authorization.createBasicHeader(username, password);
			} else {
				throw new HttpRequestException("%s only currently supports %s authorization", this.getClass().getSimpleName(), Authorization.Basic);
			}
		}
		return null;
	}

	protected String encodeParameter(String value, String encoding) {
		try {
			return java.net.URLEncoder.encode(value, encoding);
		} catch (UnsupportedEncodingException e) {
			throw new HttpRequestException(e, "Unable to format the parameter using %s: %s", encoding, e.getMessage());
		}
	}
}