com.threewks.thundr.http.service.ning.HttpRequestNing Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of thundr-http-ning Show documentation
Show all versions of thundr-http-ning Show documentation
An implementation of thundr-http using the ning asynchronous library
/*
* This file is a component of thundr, a software library from 3wks.
* Read more: http://www.3wks.com.au/thundr
* Copyright (C) 2013 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.ning;
import static com.threewks.thundr.http.HttpSupport.convertToValidUrl;
import java.io.InputStream;
import java.net.HttpCookie;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import jodd.util.Base64;
import jodd.util.StringUtil;
import com.atomicleopard.expressive.Expressive;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
import com.threewks.thundr.http.ContentType;
import com.threewks.thundr.http.FileParameter;
import com.threewks.thundr.http.HttpSupport;
import com.threewks.thundr.http.HttpSupport.Header;
import com.threewks.thundr.http.service.HttpRequest;
import com.threewks.thundr.http.service.HttpRequestException;
import com.threewks.thundr.http.service.HttpResponse;
import com.threewks.thundr.util.Encoder;
public class HttpRequestNing implements HttpRequest {
private String encoding = "UTF-8";
private String url;
private Object body;
private Map headers = new HashMap();
private Map parameters = new LinkedHashMap();
private List cookies = new ArrayList();
private boolean followRedirects = true;
private long timeout = 60000;
private String username;
private String password;
private String scheme;
@SuppressWarnings("unused")
private List fileParameters = Collections.emptyList();
private HttpServiceNing httpService;
private AsyncHttpClient client;
public HttpRequestNing(HttpServiceNing httpService, AsyncHttpClient client, String url) {
this.httpService = httpService;
this.url = convertToValidUrl(url);
this.client = client;
}
/**
* Indicate if the WS should continue when hitting a 301 or 302
*
* @return the WebRequest for chaining.
*/
@Override
public HttpRequest followRedirects(boolean value) {
this.followRedirects = value;
return this;
}
@Override
public HttpRequest timeout(long millis) {
this.timeout = millis;
return this;
}
@Override
public HttpRequest body(Object body) {
this.body = body;
return this;
}
/**
* Sets the content type of the request. For content types not supported in the {@link ContentType} enum,
* you can set the content type header directly.
*
* request.header({@link HttpSupport#HttpHeaderContentType}, "content/type");
*
*
*/
@Override
public HttpRequest contentType(ContentType contentType) {
return contentType(contentType.value());
}
@Override
public HttpRequest contentType(String contentType) {
header(Header.ContentType, contentType);
return this;
}
@Override
public HttpRequest headers(Map headers) {
this.headers = headers;
return this;
}
@Override
public HttpRequest header(String name, String value) {
this.headers.put(name, value);
return this;
}
@Override
public HttpRequest cookie(HttpCookie cookie) {
this.cookies.add(cookie);
return this;
}
@Override
public HttpRequest cookies(Collection cookie) {
this.cookies.addAll(cookie);
return this;
}
@Override
public HttpRequest parameter(String name, String value) {
this.parameters.put(name, value);
return this;
}
@Override
public HttpRequest parameter(String name, Object value) {
this.parameters.put(name, value);
return this;
}
/**
* Adds the given parameters to request.
* GET: parameters are passed as a query string
* POST: parameters are passed in the body
* PUT: parameters are passed in the body
* DELETE: parameters are passed as a query string
*/
@Override
public HttpRequest parameters(Map parameters) {
this.parameters.putAll(parameters);
return this;
}
@Override
public HttpResponse get() {
BoundRequestBuilder builder = client.prepareGet(getBaseUrl());
setCommonProperties(builder);
setContentTypeIfNotPresent(ContentType.TextPlain);
addAuthorization(builder);
addHeaders(builder);
addCookies(builder);
addQueryParameters(builder);
addBody(builder);
try {
return new HttpResponseNing(builder.execute(), httpService);
} catch (Exception e) {
throw new HttpRequestException(e, "Failed to create a GET request: %s", e.getMessage());
}
}
@Override
public HttpResponse post() {
BoundRequestBuilder builder = client.preparePost(getBaseUrl());
setCommonProperties(builder);
setContentTypeIfNotPresent(ContentType.ApplicationFormUrlEncoded);
addAuthorization(builder);
addHeaders(builder);
addCookies(builder);
addParameters(builder);
addBody(builder);
try {
return new HttpResponseNing(builder.execute(), httpService);
} catch (Exception e) {
throw new HttpRequestException(e, "Failed to create a POST request: %s", e.getMessage());
}
}
@Override
public HttpResponse put() {
BoundRequestBuilder builder = client.preparePut(getBaseUrl());
setCommonProperties(builder);
setContentTypeIfNotPresent(ContentType.ApplicationFormUrlEncoded);
addAuthorization(builder);
addHeaders(builder);
addCookies(builder);
addParameters(builder);
addBody(builder);
try {
return new HttpResponseNing(builder.execute(), httpService);
} catch (Exception e) {
throw new HttpRequestException(e, "Failed to create a PUT request: %s", e.getMessage());
}
}
@Override
public HttpResponse delete() {
BoundRequestBuilder builder = client.prepareDelete(getBaseUrl());
setCommonProperties(builder);
setContentTypeIfNotPresent(ContentType.TextPlain);
addAuthorization(builder);
addHeaders(builder);
addCookies(builder);
addQueryParameters(builder);
addBody(builder);
try {
return new HttpResponseNing(builder.execute(), httpService);
} catch (Exception e) {
throw new HttpRequestException(e, "Failed to create a DELETE request: %s", e.getMessage());
}
}
@Override
public HttpResponse head() {
BoundRequestBuilder builder = client.prepareHead(getBaseUrl());
setCommonProperties(builder);
setContentTypeIfNotPresent(ContentType.TextPlain);
addAuthorization(builder);
addHeaders(builder);
addCookies(builder);
addQueryParameters(builder);
try {
return new HttpResponseNing(builder.execute(), httpService);
} catch (Exception e) {
throw new HttpRequestException(e, "Failed to create a HEAD request: %s", e.getMessage());
}
}
@Override
public HttpRequest authorize(String username, String password, String scheme) {
this.username = username;
this.password = password;
this.scheme = scheme;
return this;
}
public HttpRequest authorize(String username, String password) {
return authorize(username, password, HttpSupport.Authorizations.Basic);
}
public HttpRequest files(FileParameter... fileParameters) {
this.fileParameters = Arrays.asList(fileParameters);
return this;
}
public HttpRequest files(List fileParameters) {
this.fileParameters = fileParameters;
return this;
}
protected String basicAuthHeader() {
return "Basic " + Base64.encodeToString(this.username + ":" + this.password);
}
protected String encode(String part) {
try {
return URLEncoder.encode(part, encoding);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
protected String createQueryString() {
StringBuilder sb = new StringBuilder();
for (String key : this.parameters.keySet()) {
if (sb.length() > 0) {
sb.append("&");
}
Object value = this.parameters.get(key);
if (value != null) {
if (value instanceof Collection> || value.getClass().isArray()) {
Collection> values = value.getClass().isArray() ? Arrays.asList((Object[]) value) : (Collection>) value;
boolean first = true;
for (Object v : values) {
if (!first) {
sb.append("&");
}
first = false;
sb.append(encode(key)).append("=").append(encode(v.toString()));
}
} else {
sb.append(encode(key)).append("=").append(encode(this.parameters.get(key).toString()));
}
}
}
return sb.toString();
}
private void setCommonProperties(BoundRequestBuilder builder) {
builder.setFollowRedirects(followRedirects);
builder.setBodyEncoding(encoding);
}
private void addCookies(BoundRequestBuilder builder) {
List cookies = Expressive.Transformers.transformAllUsing(NingTransformers.toNingCookie).from(this.cookies);
for (com.ning.http.client.Cookie cookie : cookies) {
builder.addCookie(cookie);
}
}
private void addHeaders(BoundRequestBuilder builder) {
for (Map.Entry header : headers.entrySet()) {
builder.addHeader(header.getKey(), StringUtil.toString(header.getValue()));
}
}
private void addQueryParameters(BoundRequestBuilder builder) {
for (Map.Entry parameter : parameters.entrySet()) {
builder.addQueryParameter(parameter.getKey(), StringUtil.toString(parameter.getValue()));
}
}
private void addParameters(BoundRequestBuilder builder) {
for (Map.Entry parameter : parameters.entrySet()) {
builder.addParameter(parameter.getKey(), StringUtil.toString(parameter.getValue()));
}
}
private void addAuthorization(BoundRequestBuilder builder) {
if (username != null && password != null) {
if (HttpSupport.Authorizations.Basic.equalsIgnoreCase(scheme)) {
String authorisation = HttpSupport.Authorizations.Basic + " " + new Encoder(this.username + ":" + this.password).base64().string();
builder.addHeader(HttpSupport.Header.Authorization, authorisation);
} else {
throw new HttpRequestException("%s only currently supports %s authorization", HttpServiceNing.class.getSimpleName(), HttpSupport.Authorizations.Basic);
}
}
}
private void addBody(BoundRequestBuilder builder) {
if (body != null) {
InputStream is = httpService.convertOutgoing(body);
builder.setBody(is);
}
}
/**
* Return the request url without any request parameters
*
* @return
*/
private String getBaseUrl() {
return StringUtil.cutToIndexOf(url, '?');
}
private void setContentTypeIfNotPresent(ContentType contentType) {
if (!headers.containsKey(Header.ContentType)) {
header(Header.ContentType, contentType.value());
}
}
}