/framework/src/play/src/main/java/play/libs/WS.java

https://github.com/julienrf/playframework · Java · 355 lines · 209 code · 49 blank · 97 comment · 28 complexity · bcfe9559374e07e9675d19a07cfc57fc MD5 · raw file

  1. package play.libs;
  2. import com.ning.http.client.AsyncHttpClient;
  3. import com.ning.http.client.AsyncCompletionHandler;
  4. import com.ning.http.client.Request;
  5. import com.ning.http.client.RequestBuilderBase;
  6. import com.ning.http.client.Realm.AuthScheme;
  7. import com.ning.http.client.Realm.RealmBuilder;
  8. import com.ning.http.client.FluentStringsMap;
  9. import java.lang.reflect.Method;
  10. import java.lang.reflect.Type;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.File;
  14. import java.util.Collection;
  15. import java.util.Map;
  16. import java.util.HashMap;
  17. import java.util.List;
  18. import java.util.ArrayList;
  19. import javax.xml.parsers.DocumentBuilder;
  20. import javax.xml.parsers.DocumentBuilderFactory;
  21. import org.w3c.dom.Document;
  22. import org.xml.sax.InputSource;
  23. import play.libs.Scala;
  24. import play.libs.F.Promise;
  25. import org.codehaus.jackson.JsonNode;
  26. import org.codehaus.jackson.map.ObjectMapper;
  27. /**
  28. * Asynchronous API to to query web services, as an http client.
  29. *
  30. * The value returned is a Promise<Response>, and you should use Play's asynchronous mechanisms to use this response.
  31. */
  32. public class WS {
  33. private static AsyncHttpClient client = play.api.libs.ws.WS.client();
  34. /**
  35. * Prepare a new request. You can then construct it by chaining calls.
  36. *
  37. * @param url the URL to request
  38. */
  39. public static WSRequestHolder url(String url) {
  40. return new WSRequestHolder(url);
  41. }
  42. /**
  43. * Provides the bridge between Play and the underlying ning request
  44. */
  45. public static class WSRequest extends RequestBuilderBase<WSRequest> {
  46. public WSRequest(String method) {
  47. super(WSRequest.class, method, false);
  48. }
  49. private WSRequest auth(String username, String password, AuthScheme scheme) {
  50. this.setRealm((new RealmBuilder())
  51. .setScheme(scheme)
  52. .setPrincipal(username)
  53. .setPassword(password)
  54. .setUsePreemptiveAuth(true)
  55. .build());
  56. return this;
  57. }
  58. private Promise<Response> execute() {
  59. final play.api.libs.concurrent.STMPromise<Response> scalaPromise = new play.api.libs.concurrent.STMPromise<Response>();
  60. try {
  61. WS.client.executeRequest(request, new AsyncCompletionHandler<com.ning.http.client.Response>() {
  62. @Override
  63. public com.ning.http.client.Response onCompleted(com.ning.http.client.Response response) {
  64. final com.ning.http.client.Response ahcResponse = response;
  65. scalaPromise.redeem(new scala.runtime.AbstractFunction0<Response>() {
  66. public Response apply() {
  67. return new Response(ahcResponse);
  68. }
  69. });
  70. return response;
  71. }
  72. @Override
  73. public void onThrowable(Throwable t) {
  74. scalaPromise.throwing(t);
  75. }
  76. });
  77. } catch (IOException exception) {
  78. scalaPromise.throwing(exception);
  79. }
  80. return new Promise(scalaPromise);
  81. }
  82. }
  83. /**
  84. * provides the User facing API for building WS request.
  85. */
  86. public static class WSRequestHolder {
  87. private final String url;
  88. private Map<String, Collection<String>> headers = new HashMap<String, Collection<String>>();
  89. private Map<String, Collection<String>> queryParameters = new HashMap<String, Collection<String>>();
  90. private String username = null;
  91. private String password = null;
  92. private AuthScheme scheme = null;
  93. public WSRequestHolder(String url) {
  94. this.url = url;
  95. }
  96. /**
  97. * Sets a header with the given name, this can be called repeatedly
  98. *
  99. * @param name
  100. * @param value
  101. */
  102. public WSRequestHolder setHeader(String name, String value) {
  103. if (headers.containsKey(name)) {
  104. Collection<String> values = headers.get(name);
  105. values.add(value);
  106. } else {
  107. List<String> values = new ArrayList<String>();
  108. values.add(value);
  109. headers.put(name, values);
  110. }
  111. return this;
  112. }
  113. /**
  114. * Sets a query parameter with the given name,this can be called repeatedly
  115. *
  116. * @param name
  117. * @param value
  118. */
  119. public WSRequestHolder setQueryParameter(String name, String value) {
  120. if (queryParameters.containsKey(name)) {
  121. Collection<String> values = headers.get(name);
  122. values.add(value);
  123. } else {
  124. List<String> values = new ArrayList<String>();
  125. values.add(value);
  126. queryParameters.put(name, values);
  127. }
  128. return this;
  129. }
  130. /**
  131. * Sets the authentication header for the current request.
  132. *
  133. * @param username
  134. * @param password
  135. * @param scheme authentication scheme
  136. */
  137. public WSRequestHolder setAuth(String username, String password, AuthScheme scheme) {
  138. this.username = username;
  139. this.password = password;
  140. this.scheme = scheme;
  141. return this;
  142. }
  143. /**
  144. * Perform a GET on the request asynchronously.
  145. */
  146. public Promise<Response> get() {
  147. return execute("GET");
  148. }
  149. /**
  150. * Perform a POST on the request asynchronously.
  151. *
  152. * @param body represented as String
  153. */
  154. public Promise<Response> post(String body) {
  155. return executeString("POST", body);
  156. }
  157. /**
  158. * Perform a PUT on the request asynchronously.
  159. *
  160. * @param body represented as String
  161. */
  162. public Promise<Response> put(String body) {
  163. return executeString("PUT", body);
  164. }
  165. /**
  166. * Perform a POST on the request asynchronously.
  167. *
  168. * @param body represented as an InputStream
  169. */
  170. public Promise<Response> post(InputStream body) {
  171. return executeIS("POST", body);
  172. }
  173. /**
  174. * Perform a PUT on the request asynchronously.
  175. *
  176. * @param body represented as an InputStream
  177. */
  178. public Promise<Response> put(InputStream body) {
  179. return executeIS("PUT", body);
  180. }
  181. /**
  182. * Perform a POST on the request asynchronously.
  183. *
  184. * @param body represented as a File
  185. */
  186. public Promise<Response> post(File body) {
  187. return executeFile("POST", body);
  188. }
  189. /**
  190. * Perform a PUT on the request asynchronously.
  191. *
  192. * @param body represented as a File
  193. */
  194. public Promise<Response> put(File body) {
  195. return executeFile("PUT", body);
  196. }
  197. /**
  198. * Perform a DELETE on the request asynchronously.
  199. */
  200. public Promise<Response> delete() {
  201. return execute("DELETE");
  202. }
  203. /**
  204. * Perform a HEAD on the request asynchronously.
  205. */
  206. public Promise<Response> head() {
  207. return execute("HEAD");
  208. }
  209. /**
  210. * Perform a OPTION on the request asynchronously.
  211. */
  212. public Promise<Response> option() {
  213. return execute("OPTION");
  214. }
  215. private Promise<Response> execute(String method) {
  216. WSRequest req = new WSRequest(method).setUrl(url)
  217. .setHeaders(headers)
  218. .setQueryParameters(new FluentStringsMap(queryParameters));
  219. if (this.username != null && this.password != null && this.scheme != null)
  220. req.auth(this.username, this.password, this.scheme);
  221. return req.execute();
  222. }
  223. private Promise<Response> executeString(String method, String body) {
  224. WSRequest req = new WSRequest(method).setBody(body)
  225. .setUrl(url)
  226. .setHeaders(headers)
  227. .setQueryParameters(new FluentStringsMap(queryParameters));
  228. if (this.username != null && this.password != null && this.scheme != null)
  229. req.auth(this.username, this.password, this.scheme);
  230. return req.execute();
  231. }
  232. private Promise<Response> executeIS(String method, InputStream body) {
  233. WSRequest req = new WSRequest(method).setBody(body)
  234. .setUrl(url)
  235. .setHeaders(headers)
  236. .setQueryParameters(new FluentStringsMap(queryParameters));
  237. if (this.username != null && this.password != null && this.scheme != null)
  238. req.auth(this.username, this.password, this.scheme);
  239. return req.execute();
  240. }
  241. private Promise<Response> executeFile(String method, File body) {
  242. WSRequest req = new WSRequest(method).setBody(body)
  243. .setUrl(url)
  244. .setHeaders(headers)
  245. .setQueryParameters(new FluentStringsMap(queryParameters));
  246. if (this.username != null && this.password != null && this.scheme != null)
  247. req.auth(this.username, this.password, this.scheme);
  248. return req.execute();
  249. }
  250. }
  251. /**
  252. * A WS response.
  253. */
  254. public static class Response {
  255. private com.ning.http.client.Response ahcResponse;
  256. public Response(com.ning.http.client.Response ahcResponse) {
  257. this.ahcResponse = ahcResponse;
  258. }
  259. /**
  260. * Get the HTTP status code of the response
  261. */
  262. public int getStatus() {
  263. return ahcResponse.getStatusCode();
  264. }
  265. /**
  266. * Get the given HTTP header of the response
  267. */
  268. public String getHeader(String key) {
  269. return ahcResponse.getHeader(key);
  270. }
  271. /**
  272. * Get the response body as a string
  273. */
  274. public String getBody() {
  275. try {
  276. return ahcResponse.getResponseBody();
  277. } catch (Exception e) {
  278. throw new RuntimeException(e);
  279. }
  280. }
  281. /**
  282. * Get the response body as a {@link Document DOM document}
  283. * @return a DOM document
  284. */
  285. public Document asXml() {
  286. try {
  287. return play.libs.XML.fromInputStream(ahcResponse.getResponseBodyAsStream(), "utf-8");
  288. } catch (Exception e) {
  289. throw new RuntimeException(e);
  290. }
  291. }
  292. /**
  293. * Get the response body as a {@link org.codehaus.jackson.JsonNode}
  294. * @return the json response
  295. */
  296. public JsonNode asJson() {
  297. String json = getBody();
  298. ObjectMapper mapper = new ObjectMapper();
  299. try {
  300. return mapper.readValue(json, JsonNode.class);
  301. } catch (Exception e) {
  302. throw new RuntimeException(e);
  303. }
  304. }
  305. }
  306. }