package com.nvarghese.beowulf.common.http.txn;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang.NotImplementedException;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.client.protocol.RequestAcceptEncoding;
import org.apache.http.client.protocol.RequestAddCookies;
import org.apache.http.client.protocol.ResponseContentEncoding;
import org.apache.http.cookie.CookieOrigin;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nvarghese.beowulf.common.http.client.HttpClientFactory;
import com.nvarghese.beowulf.common.http.client.HttpClientUtil;
import com.nvarghese.beowulf.common.http.payload.MultipartEncodedRequestPayload;
import com.nvarghese.beowulf.common.http.payload.RequestPayload;
import com.nvarghese.beowulf.common.http.payload.RequestPayloadUtils;
import com.nvarghese.beowulf.common.http.payload.UrlEncodedRequestPayload;
import com.nvarghese.beowulf.common.http.wrapper.HttpRequestWrapper;
import com.nvarghese.beowulf.common.http.wrapper.HttpResponseWrapper;
public abstract class AbstractHttpTransaction {
private ObjectId objId;
private ObjectId refererTxnObjId;
private TransactionSource transactionSource;
private HttpRequestWrapper httpRequestWrapper;
private HttpResponseWrapper httpResponseWrapper;
private BasicCookieStore cookieStore;
private AtomicBoolean responseReady;
private AtomicBoolean uncompressed;
private String referer;
protected AtomicBoolean payloadChanged;
protected AtomicBoolean saved;
/* logger */
static Logger logger = LoggerFactory.getLogger(AbstractHttpTransaction.class);
public AbstractHttpTransaction() {
super();
payloadChanged = new AtomicBoolean(false);
responseReady = new AtomicBoolean(false);
uncompressed = new AtomicBoolean(true);
saved = new AtomicBoolean(false);
transactionSource = TransactionSource.NONE;
}
public AbstractHttpTransaction(HttpRequestWrapper requestWrapper, String referer, TransactionSource transactionSource) {
this();
this.cookieStore = new BasicCookieStore();
this.httpRequestWrapper = requestWrapper;
this.referer = referer;
this.transactionSource = transactionSource;
}
@SuppressWarnings("unchecked")
public HttpTxnDocument toHttpTxnDocument() {
updateRequestPayload();
HttpTxnDocument txnDocument = new HttpTxnDocument();
txnDocument.setTransactionSource(transactionSource);
txnDocument.setRequestMethod(httpRequestWrapper.getMethod());
txnDocument.setRequestURI(getURI().toString());
txnDocument.setRequestHeaders((List<BasicHeader>) httpRequestWrapper.getHeaders());
txnDocument.setRequestPayload(RequestPayloadUtils.serialize(httpRequestWrapper.getRequestPayload()));
txnDocument.setPayloadChanged(payloadChanged.get());
txnDocument.setCookieStore(cookieStore);
txnDocument.setRefererTxnObjId(refererTxnObjId);
txnDocument.setReferer(referer);
txnDocument.setResponseReady(responseReady.get());
txnDocument.setUncompressed(uncompressed.get());
if (responseReady.get()) {
txnDocument.setResponseStatusLine((BasicStatusLine) httpResponseWrapper.getStatusLine());
txnDocument.setResponseHeaders((List<BasicHeader>) httpResponseWrapper.getHeaders());
txnDocument.setResponseBody(httpResponseWrapper.getResponseBody());
}
if (saved.get()) {
txnDocument.setId(getObjId());
}
return txnDocument;
}
public static AbstractHttpTransaction getObject(HttpTxnDocument httpTxnDocument) {
AbstractHttpTransaction httpTxn = null;
try {
RequestPayload requestPayload = RequestPayloadUtils.deserialize(httpTxnDocument.getRequestPayload());
HttpRequest httpRequest = HttpTransactionFactory.createHttpRequest(httpTxnDocument.getRequestMethod(),
new URI(httpTxnDocument.getRequestURI()), httpTxnDocument.getRequestHeaders().toArray(new BasicHeader[0]),
requestPayload.toHttpEntity());
httpTxn = HttpTransactionFactory.createTransaction(httpRequest, httpTxnDocument.getReferer(), httpTxnDocument.getTransactionSource());
httpTxn.setCookieStore(httpTxnDocument.getCookieStore());
httpTxn.setObjId(httpTxnDocument.getId());
httpTxn.setRefererTxnObjId(httpTxnDocument.getRefererTxnObjId());
httpTxn.payloadChanged.set(httpTxnDocument.isPayloadChanged());
if (httpTxnDocument.isResponseReady()) {
httpTxn.httpResponseWrapper = new HttpResponseWrapper(httpTxnDocument.getResponseStatusLine(), httpTxnDocument.getResponseHeaders(),
httpTxnDocument.getResponseBody());
httpTxn.responseReady.set(true);
} else {
httpTxn.responseReady.set(false);
}
httpTxn.uncompressed.set(httpTxnDocument.isUncompressed());
httpTxn.setSaved(true);
} catch (URISyntaxException e) {
logger.error("Failed to retrieve the object. Reason: {}", e.getMessage(), e);
} catch (NotImplementedException e) {
logger.error("Failed to retrieve the object. Reason: {}", e.getMessage(), e);
} catch (Exception e) {
logger.error("Failed to retrieve the object. Reason: {}", e.getMessage(), e);
}
return httpTxn;
}
public static AbstractHttpTransaction clone(HttpTxnDocument httpTxnDocument) {
AbstractHttpTransaction httpTxn = null;
try {
RequestPayload requestPayload = RequestPayloadUtils.deserialize(httpTxnDocument.getRequestPayload());
HttpRequest httpRequest = HttpTransactionFactory.createHttpRequest(httpTxnDocument.getRequestMethod(),
new URI(httpTxnDocument.getRequestURI()), httpTxnDocument.getRequestHeaders().toArray(new BasicHeader[0]),
requestPayload.toHttpEntity());
httpTxn = HttpTransactionFactory.createTransaction(httpRequest, httpTxnDocument.getReferer(), httpTxnDocument.getTransactionSource());
httpTxn.setCookieStore(httpTxnDocument.getCookieStore());
httpTxn.setRefererTxnObjId(httpTxnDocument.getRefererTxnObjId());
httpTxn.payloadChanged.set(httpTxnDocument.isPayloadChanged());
httpTxn.responseReady.set(false);
httpTxn.uncompressed.set(false);
httpTxn.setSaved(false);
} catch (URISyntaxException e) {
logger.error("Failed to retrieve the object. Reason: {}", e.getMessage(), e);
} catch (NotImplementedException e) {
logger.error("Failed to retrieve the object. Reason: {}", e.getMessage(), e);
} catch (Exception e) {
logger.error("Failed to retrieve the object. Reason: {}", e.getMessage(), e);
}
return httpTxn;
}
/**
*
* @return
*/
public ObjectId getObjId() {
return objId;
}
/**
*
* @param objId
*/
public void setObjId(ObjectId objId) {
this.objId = objId;
}
/**
*
* @param name
* @param value
*/
public void addRequestHeader(String name, String value) {
httpRequestWrapper.getHttpRequest().addHeader(name, value);
}
/**
*
* @param name
*/
public void removeRequestHeaders(String name) {
httpRequestWrapper.getHttpRequest().removeHeaders(name);
}
/**
*
* @param name
* @return
*/
public Header getFirstRequestHeader(String name) {
return httpRequestWrapper.getHttpRequest().getFirstHeader(name);
}
/**
*
* @param name
* @return
*/
public Header[] getRequestHeaders(String name) {
return httpRequestWrapper.getHttpRequest().getHeaders(name);
}
/**
* Adds query parameter if encoding is of type x-www-urlencoded
*
*
*/
public void addQueryParameter(String name, String value) {
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof UrlEncodedRequestPayload) {
((UrlEncodedRequestPayload) requestPayload).addParameter(name, value);
payloadChanged.set(true);
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.APPLICATION_FORM_URLENCODED);
}
}
/**
* Removes the query parameter
*
*/
public void removeQueryParameter(String name) {
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof UrlEncodedRequestPayload) {
((UrlEncodedRequestPayload) requestPayload).removeParameter(name);
payloadChanged.set(true);
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.APPLICATION_FORM_URLENCODED);
}
}
/**
* Returns the list of all query parameters
*
* @return
*/
public List<NameValuePair> getQueryParameters() {
List<NameValuePair> nps = new ArrayList<NameValuePair>();
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof UrlEncodedRequestPayload) {
nps = ((UrlEncodedRequestPayload) requestPayload).getParameters();
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.APPLICATION_FORM_URLENCODED);
}
return nps;
}
public String getQueryParamater(String name) {
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof UrlEncodedRequestPayload) {
String value = ((UrlEncodedRequestPayload) requestPayload).getParameterValue(name);
return value;
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.APPLICATION_FORM_URLENCODED);
return null;
}
}
/**
* Adds a contentBody as a part data
*
* @param name
* @param contentBody
*/
public void addPart(String name, ContentBody contentBody) {
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof MultipartEncodedRequestPayload) {
((MultipartEncodedRequestPayload) requestPayload).addPart(name, contentBody);
payloadChanged.set(true);
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.MULTIPART_FORM_DATA);
}
}
/**
*
*
*/
public void removePart(String name) {
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof MultipartEncodedRequestPayload) {
((MultipartEncodedRequestPayload) requestPayload).removePart(name);
payloadChanged.set(true);
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.MULTIPART_FORM_DATA);
}
}
/**
* Get all multi-part data
*
*/
public Map<String, ContentBody> getAllParts() {
Map<String, ContentBody> parts = new HashMap<String, ContentBody>();
RequestPayload requestPayload = httpRequestWrapper.getRequestPayload();
if (requestPayload instanceof MultipartEncodedRequestPayload) {
parts = ((MultipartEncodedRequestPayload) requestPayload).getParts();
payloadChanged.set(true);
} else {
logger.warn("Request payload is not of content-type: {}", ContentType.MULTIPART_FORM_DATA);
}
return parts;
}
public void execute() {
try {
responseReady.set(false);
updateRequestPayload();
HttpParams params = HttpClientUtil.createHttpParams(60 * 1000);
DefaultHttpClient httpClient = (DefaultHttpClient) HttpClientFactory.createHttpClient(params);
httpClient.addRequestInterceptor(new RequestAcceptEncoding());
httpClient.addRequestInterceptor(new RequestAddCookies());
httpClient.addResponseInterceptor(new ResponseContentEncoding());
URI uri = getURI();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpHost target = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
// execute request
HttpResponse httpResponse = httpClient.execute(target, httpRequestWrapper.getHttpRequest(), localContext);
responseReady.set(true);
updateResponse(httpResponse, localContext);
} catch (ClientProtocolException e) {
logger.error("Problem in client protocol. Reason: {}", e.getMessage(), e);
} catch (IOException e) {
logger.error("Problem in client protocol. Reason: {}", e.getMessage(), e);
}
}
public void clearResponse() {
httpResponseWrapper = null;
responseReady.set(false);
payloadChanged.set(false);
}
private void updateResponse(HttpResponse httpResponse, HttpContext localContext) {
if (!isResponseReady()) {
logger.warn("Response is not ready to update.");
return;
}
httpResponseWrapper = new HttpResponseWrapper(httpResponse);
Object uncompressedAttribute = localContext.getAttribute(ResponseContentEncoding.UNCOMPRESSED);
if (uncompressedAttribute != null && uncompressedAttribute instanceof Boolean) {
uncompressed.set(Boolean.getBoolean(uncompressedAttribute.toString()));
}
}
protected void updateRequestPayload() {
if (payloadChanged.get()) {
httpRequestWrapper.processUpdates();
payloadChanged.set(false);
}
}
public URI getURI() {
return httpRequestWrapper.getURI();
}
public String getReferer() {
return referer;
}
public BasicCookieStore getCookieStore() {
return cookieStore;
}
public void setCookieStore(BasicCookieStore cookieStore) {
this.cookieStore = cookieStore;
}
public ObjectId getRefererTxnObjId() {
return refererTxnObjId;
}
public void setRefererTxnObjId(ObjectId refererTxnObjId) {
this.refererTxnObjId = refererTxnObjId;
}
public CookieOrigin getCookieOrigin(boolean secure) {
return new CookieOrigin(getHost(), getPort(), getPath(), secure);
}
public String getResourceName() {
return getURI().getPath().replaceFirst(".*/([^/]*)$", "$1");
}
public String getResourcePath() {
String resourcePath = "";
String path = getPath();
if (path != null) {
int lastSlash = path.lastIndexOf("/");
if (lastSlash >= 0) {
resourcePath = path.substring(0, lastSlash + 1);
}
} else {
logger.warn("Null path for URI: {}", getURI());
}
return resourcePath;
}
public String getPath() {
return getURI().getPath();
}
public int getPort() {
return getURI().getPort();
}
public String getHost() {
return getURI().getHost();
}
public String getScheme() {
return getURI().getScheme();
}
public String getHostUriWithoutTrailingSlash() {
String base = getScheme() + "://" + getHost();
int port = getPort();
if (port > 0) {
base += ":" + port;
}
return base;
}
public HttpResponse getResponse() {
HttpResponse response = null;
if (httpResponseWrapper != null) {
response = httpResponseWrapper.getHttpResponse();
}
return response;
}
public byte[] getResponseBody() {
byte[] responseBody = null;
if (httpResponseWrapper != null) {
responseBody = httpResponseWrapper.getResponseBody();
}
return responseBody;
}
public String getResponseBodyAsString() {
String responseString = new String(getResponseBody());
return responseString;
}
public ContentType getContentType() {
ContentType contentType = ContentType.DEFAULT_TEXT;
if (httpResponseWrapper != null) {
contentType = httpResponseWrapper.getContentType();
}
return contentType;
}
public int getResponseStatusCode() {
int statusCode = 0;
if (httpResponseWrapper != null)
statusCode = httpResponseWrapper.getStatusLine().getStatusCode();
return statusCode;
}
public long getResponseContentLength() {
long length = -1;
if (getResponseBody() != null) {
length = getResponseBody().length;
}
return length;
}
public Header[] getResponseHeaders(final String headerName) {
Header[] headers = new Header[0];
if (httpResponseWrapper != null) {
headers = httpResponseWrapper.getHttpResponse().getHeaders(headerName);
}
return headers;
}
public Header[] getAllResponseHeaders() {
Header[] headers = new Header[0];
if (httpResponseWrapper != null) {
headers = httpResponseWrapper.getHttpResponse().getAllHeaders();
}
return headers;
}
/**
*
* @return All response headers formated as they would be found in the raw
* HTTP response.
*/
public String getAllResponseHeadersAsString() {
String headers = "";
if (httpResponseWrapper != null) {
for (Header header : getAllResponseHeaders()) {
headers = headers.concat(header.toString()).concat("\r\n");
}
return headers;
}
return null;
}
public HttpResponseWrapper getResponseWrapper() {
return httpResponseWrapper;
}
public void setReferer(String referer) {
this.referer = referer;
}
public boolean isResponseReady() {
return responseReady.get();
}
public boolean isUncompressed() {
return uncompressed.get();
}
public boolean isSaved() {
return saved.get();
}
public void setSaved(boolean value) {
saved.set(value);
}
public TransactionSource getTransactionSource() {
return transactionSource;
}
public void setTransactionSource(TransactionSource transactionSource) {
this.transactionSource = transactionSource;
}
/**
*
* @return
*/
public String requestToString() {
StringBuilder requestString = new StringBuilder();
requestString.append(httpRequestWrapper.getHttpRequest().getRequestLine().toString()).append("\n");
for (Header header : httpRequestWrapper.getHttpRequest().getAllHeaders()) {
requestString.append(header.toString()).append("\n");
}
requestString.append("\n");
return requestString.toString();
}
/**
*
* @return
*/
public String responseToString() {
StringBuilder responseString = new StringBuilder();
if (httpResponseWrapper != null) {
responseString.append(httpResponseWrapper.getStatusLine().toString() + "\r\n");
for (Header header : httpResponseWrapper.getHeaders()) {
responseString.append(header.toString()).append("\n");
}
responseString.append("\r\n");
responseString.append(new String(httpResponseWrapper.getResponseBody()));
}
return responseString.toString();
}
}