/** * personium.io * Copyright 2014 FUJITSU LIMITED * * 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.fujitsu.dc.test.jersey; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 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.HttpUriRequest; import org.apache.http.client.params.HttpClientParams; import org.apache.http.cookie.Cookie; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import com.fujitsu.dc.test.DcCoreTestConfig; /** * RESTアクセスのためのクラス. */ public class DcRestAdapter { /** ログオブジェクト. */ private Log log; /** Content-Type に指定する文字列定義. */ public static final String CONTENT_TYPE_JSON = "application/json"; /** Content-Type に指定する文字列定義. */ public static final String CONTENT_TYPE_XML = "application/xml"; /** Content-Type に指定する文字列定義. */ public static final String CONTENT_FORMURLENCODE = "application/x-www-form-urlencoded"; /** ポストデータのエンコード種別. */ private static final String ENCODE = "UTF-8"; /** デフォルトタイムアウト値. */ private static final int TIMEOUT = 85000; /** HTTPClient. */ private HttpClient httpClient; /** * コンストラクタ. */ public DcRestAdapter() { httpClient = HttpClientFactory.create("insecure", TIMEOUT); HttpClientParams.setRedirecting(httpClient.getParams(), false); log = LogFactory.getLog(DcRestAdapter.class); } /** * HttpClientを置き換える(ユニットテスト用). * @param value HttpClientオブジェクト */ public final void setHttpClient(final HttpClient value) { this.httpClient = value; } /** * レスポンスボディを受け取るGETメソッド. * @param url リクエスト対象URL * @param headers リクエストヘッダのハッシュマップ * @return DcResponse型 * @throws DcException DAO例外 */ public final DcResponse get(final String url, final HashMap<String, String> headers) throws DcException { HttpUriRequest req = new HttpGet(url); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); debugHttpRequest(req, ""); DcResponse res = this.request(req); return res; } /** * レスポンスボディを受け取るGETメソッド. * @param url リクエスト対象URL * @param headers リクエストヘッダのハッシュマップ * @return DcResponse型 * @throws DcException DAO例外 */ public final DcResponse getAcceptEncodingGzip(final String url, final HashMap<String, String> headers) throws DcException { HttpUriRequest req = new HttpGet(url); req.addHeader("Accept-Encoding", "gzip"); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); debugHttpRequest(req, ""); DcResponse res = this.request(req); return res; } /** * レスポンスボディを受ける PUTメソッド. * @param url リクエスト対象URL * @param data 書き込むデータ * @param headers リクエストヘッダのハッシュマップ * @return DcResponse型 * @throws DcException DAO例外 */ public final DcResponse put(final String url, final String data, final HashMap<String, String> headers) throws DcException { String contentType = headers.get(HttpHeaders.CONTENT_TYPE); HttpUriRequest req = makePutRequest(url, data, contentType); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); debugHttpRequest(req, data); DcResponse res = request(req); return res; } /** * Stream登録を行うPUTメソッド. * @param url PUT対象のURL * @param headers リクエストヘッダのハッシュマップ * @param is PUTするデータストリーム * @return DcResponse型 * @throws DcException DAO例外 */ public final DcResponse put(final String url, final HashMap<String, String> headers, final InputStream is) throws DcException { String contentType = headers.get(HttpHeaders.CONTENT_TYPE); HttpUriRequest req = makePutRequestByStream(url, contentType, is); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); debugHttpRequest(req, "body is InputStream..."); DcResponse res = request(req); return res; } /** * リクエストボディを受け取る POSTメソッド. * @param url リクエスト対象URL * @param data 書き込むデータ * @param headers リクエストヘッダのハッシュマップ * @return DcResponse型 * @throws DcException DAO例外 */ public final DcResponse post(final String url, final String data, final HashMap<String, String> headers) throws DcException { String contentType = headers.get(HttpHeaders.CONTENT_TYPE); HttpUriRequest req = makePostRequest(url, data, contentType); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); debugHttpRequest(req, data); DcResponse res = request(req); return res; } /** * DELETEメソッド. * @param url リクエスト対象URL * @param headers リクエストヘッダのハッシュマップ * @return DcResponse型 * @throws DcException DAO例外 */ public final DcResponse del(final String url, final HashMap<String, String> headers) throws DcException { HttpDelete req = new HttpDelete(url); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); debugHttpRequest(req, ""); return this.request(req); } /** * GET/POST/PUT/DELETE 以外のメソッド. * @param method Httpメソッド * @param url リクエスト対象URL * @param body リクエストボディ * @param headers リクエストヘッダのハッシュマップ * @return DcResponse型 * @throws DcException DAO例外 */ public DcResponse request(final String method, String url, String body, HashMap<String, String> headers) throws DcException { HttpEntityEnclosingRequestBase req = new HttpEntityEnclosingRequestBase() { @Override public String getMethod() { return method; } }; req.setURI(URI.create(url)); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } req.addHeader("X-Dc-Version", DcCoreTestConfig.getCoreVersion()); if (body != null) { HttpEntity httpEntity = null; try { String bodyStr = toUniversalCharacterNames(body); httpEntity = new StringEntity(bodyStr); } catch (UnsupportedEncodingException e) { throw DcException.create("error while request body encoding : " + e.getMessage(), 0); } req.setEntity(httpEntity); } debugHttpRequest(req, body); return this.request(req); } /** * GETメソッドのためのリクエストオブジェクト生成. * @param url リクエスト対象のURL * @param accept メディアタイプ * @return リクエストオブジェクト */ protected final HttpUriRequest makeGetRequest(final String url, final String accept) { HttpUriRequest request = new HttpGet(url); makeCommonHeaders(request, null, accept, null); request.addHeader("Accept-Encoding", "gzip"); return request; } /** * PUTメソッドのためのリクエストオブジェクトを生成. * @param url リクエスト対象のURL * @param data PUTするデータ * @param contentType メディアタイプ * @return HttpPutインスタンス * @throws DcException DAO例外 */ protected final HttpPut makePutRequest(final String url, final String data, final String contentType) throws DcException { HttpPut request = new HttpPut(url); HttpEntity body = null; try { if (DcRestAdapter.CONTENT_TYPE_JSON.equals(contentType)) { String bodyStr = toUniversalCharacterNames(data); body = new StringEntity(bodyStr); } else { body = new StringEntity(data, DcRestAdapter.ENCODE); } } catch (UnsupportedEncodingException e) { throw DcException.create("error while request body encoding : " + e.getMessage(), 0); } request.setEntity(body); return request; } /** * PUTするリクエストオブジェクトを生成. * @param url リクエスト対象のURL * @param contentType メディアタイプ * @param is PUTするデータストリーム * @return HttpPutクラスインスタンス * @throws DcException DAO例外 */ protected final HttpPut makePutRequestByStream(final String url, final String contentType, final InputStream is) throws DcException { HttpPut request = new HttpPut(url); InputStreamEntity body; body = new InputStreamEntity(is, -1); Boolean chunked = true; if (chunked != null) { body.setChunked(chunked); } request.setEntity(body); return request; } /** * POSTメソッドのためのリクエストオブジェクトを生成. * @param url POST対象のURL * @param data POSTするデータ * @param contentType メディアタイプ * @return POSTされたデータ * @throws DcException DAO例外 */ protected final HttpPost makePostRequest(final String url, final String data, final String contentType) throws DcException { HttpPost request = new HttpPost(url); HttpEntity body = null; try { String bodyStr = toUniversalCharacterNames(data); body = new StringEntity(bodyStr); } catch (UnsupportedEncodingException e) { throw DcException.create("error while request body encoding : " + e.getMessage(), 0); } request.setEntity(body); makeCommonHeaders(request, contentType, contentType, null); return request; } /** * 共通のヘッダをセット. * @param req リクエストオブジェクト * @param contentType メディア種別 * @param accept Acceptヘッダ * @param etag Etag値 */ protected final void makeCommonHeaders(final HttpUriRequest req, final String contentType, final String accept, final String etag) { /* * String token = accessor.getAccessToken(); if (!token.isEmpty()) { req.setHeader("Authorization", * "Token token=\"" + token + "\""); } DaoConfig config = accessor.getDaoConfig(); String version = * config.getDcVersion(); if (!"".equals(version)) { req.setHeader("X-Tritium-Version", version); } */ if (contentType != null) { req.addHeader("Content-Type", contentType); } if (accept != null) { req.addHeader("Accept", accept); } if (etag != null) { req.addHeader("If-Match", etag); } } /** ステータスコード 300. */ // private static final int STATUS300 = 300; /** ステータスコード 499. */ // private static final int STATUS499 = 499; /** * Reponseボディを受ける場合のHTTPリクエストを行う. * @param httpReq HTTPリクエスト * @return DCレスポンスオブジェクト * @throws DcException DAO例外 */ private DcResponse request(final HttpUriRequest httpReq) throws DcException { try { HttpResponse objResponse = httpClient.execute(httpReq); DcResponse dcRes = new DcResponse(objResponse); /* * int statusCode = objResponse.getStatusLine().getStatusCode(); if (statusCode >= STATUS300) { * debugHttpResponse(objResponse); throw DcException.create(dcRes.bodyAsString(), statusCode); } if * (statusCode > STATUS499) { debugHttpResponse(objResponse); throw DcException.create(dcRes.bodyAsString(), * statusCode); } */ debugHttpResponse(objResponse); return dcRes; } catch (Exception ioe) { throw DcException.create("io exception : " + ioe.getMessage(), 0); } } /** * Cookieを取得する. * @return cookieリスト */ public List<Cookie> getCookies() { return ((DefaultHttpClient) httpClient).getCookieStore().getCookies(); } /** 日本語UTFのためのマスク値. */ private static final int CHAR_MASK = 0x7f; /** 日本語UTFのためのマスク値. */ private static final int CHAR_JPUTF_MASK = 0x10000; /** * 日本語文字列エンコード. * @param inStr エンコード対象の文字列 * @return エンコード後の文字列 */ private String toUniversalCharacterNames(final String inStr) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < inStr.length(); i++) { int c = inStr.charAt(i); if (c > CHAR_MASK) { sb.append("\\u"); sb.append(Integer.toHexString((CHAR_JPUTF_MASK + c)).substring(1)); } else { sb.append((char) c); } } return sb.substring(0, sb.length()); } /** * デバッグ用. * @param res デバッグ出力するResponseオブジェクト */ private void debugHttpResponse(final HttpResponse res) { if (log.isDebugEnabled()) { log.debug("【Response】 ResponseCode: " + res.getStatusLine().getStatusCode()); Header[] headers = res.getAllHeaders(); for (int i = 0; i < headers.length; i++) { log.debug("ResponseHeader[" + headers[i].getName() + "] : " + headers[i].getValue()); } } } /** * デバッグ用. * @param req デバッグ出力するRequestオブジェクト * @param body デバッグ出力するリクエストボディ */ private void debugHttpRequest(final HttpUriRequest req, final String body) { log.debug(req.getURI()); if (log.isDebugEnabled()) { log.debug("【Request】 " + req.getMethod() + " " + req.getURI()); Header[] headers = req.getAllHeaders(); for (int i = 0; i < headers.length; i++) { log.debug("RequestHeader[" + headers[i].getName() + "] : " + headers[i].getValue()); } log.debug("RequestBody: " + body); } } }