/** * 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.client.http; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.impl.client.AbstractHttpClient; import com.fujitsu.dc.client.Accessor; import com.fujitsu.dc.client.DaoConfig; import com.fujitsu.dc.client.DaoException; import com.fujitsu.dc.client.DcContext; ///** // * RESTアクセスのためのクラス. // */ /** * It creates a new object of RestAdapter. This class is used for REST access. */ public class RestAdapter implements IRestAdapter { // /** ログオブジェクト. */ // private static Log log = LogFactory.getLog(RestAdapter.class); /** HTTPClient. */ private HttpClient httpClient; // /** アクセス主体. */ /** Reference to Accessor. */ private Accessor accessor; // /** // * コンストラクタ. // * @param as アクセス主体 // */ /** * This is the parameterized constructor to initialize various fields. * @param as Accessor */ public RestAdapter(Accessor as) { this.accessor = as; DaoConfig config = accessor.getDaoConfig(); httpClient = config.getHttpClient(); if (httpClient == null) { httpClient = HttpClientFactory.create(DcContext.getPlatform(), config.getConnectionTimeout()); } String proxyHost = config.getProxyHostname(); int proxyPort = config.getProxyPort(); if (proxyHost != null) { HttpHost proxy = new HttpHost(proxyHost, proxyPort); httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); // ID/Passが共にnullでなければ認証Proxyをセット String proxyUsername = config.getProxyUsername(); String proxyPassword = config.getProxyPassword(); if (httpClient instanceof AbstractHttpClient && proxyUsername != null && proxyPassword != null) { ((AbstractHttpClient) httpClient).getCredentialsProvider().setCredentials( new AuthScope(proxyHost, proxyPort), new UsernamePasswordCredentials(proxyUsername, proxyPassword)); } } } // /** // * HttpClientを置き換える(ユニットテスト用). // * @param value HttpClientオブジェクト // */ /** * This method is used to set the HttpClient value. * @param value HttpClient object */ public void setHttpClient(HttpClient value) { this.httpClient = value; } // /** // * HttpClientを取得する. // * @return HttpClientオブジェクト // */ /** * This method is used to get the HttpClient value. * @return HttpClient object */ public HttpClient getHttpClient() { return this.httpClient; } // /** // * レスポンスボディを受け取るGETメソッド. // * @param url リクエスト対象URL // * @param accept Acceptヘッダ値 // * @return DcResponse型 // * @throws DaoException DAO例外 // */ /** * This is the GET method to receive the response body. * @param url Target Request URL * @param accept Accept Header Value * @return DcResponse value * @throws DaoException Exception thrown */ public DcResponse get(String url, String accept) throws DaoException { return get(url, accept, null); } // /** // * レスポンスボディを受け取るGETメソッド(If-None-Macth指定). // * @param url リクエスト対象URL // * @param accept Acceptヘッダ値 // * @param etag 取得するEtag // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the GET method to receive the response body (If-None-Match specified). * @param url Target Request URL * @param accept Accept Header Value * @param etag Etag value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse get(String url, String accept, String etag) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.GET).acceptEncoding("gzip") .accept(accept).token(getToken()).ifNoneMatch(etag).defaultHeaders(this.accessor.getDefaultHeaders()) .build(); return this.request(req); } // /** // * レスポンスボディを受け取るGETメソッド(If-None-Macth指定). // * @param url リクエスト対象URL // * @param headers リクエストヘッダ // * @param etag 取得するEtag // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the GET method to receive the response body using headers (If-None-Match specified). * @param url Target Request URL * @param headers Request header * @param etag Etag value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse get(String url, Map<String, String> headers, String etag) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.GET).acceptEncoding("gzip") .token(getToken()).ifNoneMatch(etag).defaultHeaders(this.accessor.getDefaultHeaders()).build(); for (Map.Entry<String, String> entry : headers.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } return this.request(req); } // /** // * HEADメソッド. // * @param url リクエスト対象URL // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the HEAD method. * @param url Target Request URL * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse head(String url) throws DaoException { return get(url, CONTENT_TYPE_JSON, null); } // /** // * レスポンスボディを受ける PUTメソッド. // * @param url リクエスト対象URL // * @param map リクエストヘッダーのハッシュマップ // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PUT method that receives the response body. * @param url Target Request URL * @param map Hash map of Request Header * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse put(String url, HashMap<String, String> map) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.PUT).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); for (Map.Entry<String, String> entry : map.entrySet()) { req.setHeader((String) entry.getKey(), (String) entry.getValue()); } return this.request(req); } // /** // * レスポンスボディを受ける PUTメソッド. // * @param url リクエスト対象URL // * @param data 書き込むデータ // * @param etag ETag // * @param contentType CONTENT-TYPE値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PUT method that receives the response body and uses Etag value. * @param url Target Request URL * @param data Data to be sent * @param etag ETag value * @param contentType CONTENT-TYPE value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse put(String url, String data, String etag, String contentType) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.PUT).contentType(contentType) .ifMatch(etag).body(data).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * レスポンスボディを受ける PUTメソッド. // * @param url リクエスト対象URL // * @param data 書き込むデータ // * @param etag ETag // * @param map リクエストヘッダーのハッシュマップ // * @param contentType CONTENT-TYPE値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PUT method that receives the response body and uses Etag value and header map. * @param url Target Request URL * @param data Data to be sent * @param etag ETag value * @param map HashMap of Request Header * @param contentType CONTENT-TYPE value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse put(String url, String data, String etag, HashMap<String, String> map, String contentType) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.PUT).contentType(contentType) .ifMatch(etag).body(data).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()).build(); for (Map.Entry<String, String> entry : map.entrySet()) { req.setHeader((String) entry.getKey(), (String) entry.getValue()); } return this.request(req); } // /** // * Stream登録を行うPUTメソッド. // * @param url PUT対象のURL // * @param contentType メディアタイプ // * @param is PUTするデータストリーム // * @param etag PUT対象のETag // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PUT methods for Stream registration. * @param url PUT Target URL * @param contentType Media Type * @param is Data Stream to be PUT * @param etag Etag value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse putStream(String url, String contentType, InputStream is, String etag) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.PUT).contentType(contentType) .ifMatch(etag).body(is).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * リクエストボディを受け取る POSTメソッド. // * @param url リクエスト対象URL // * @param data 書き込むデータ // * @param contentType CONTENT-TYPE値 // * @param needAuthorization 認証が必要かどうか // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the POST method that receives the request body and need authorization. * @param url PUT Target URL * @param data Data to be written * @param contentType CONTENT-TYPE value * @param needAuthorization For authentication * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse post(String url, String data, String contentType, Boolean needAuthorization) throws DaoException { String token = null; if (needAuthorization) { token = getToken(); } HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.POST).contentType(contentType) .body(data).token(token).defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * リクエストボディを受け取る POSTメソッド. // * @param url リクエスト対象URL // * @param data 書き込むデータ // * @param contentType CONTENT-TYPE値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the POST method that receives the request body and does not need authorization. * @param url PUT Target URL * @param data Data to be written * @param contentType CONTENT-TYPE value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse post(String url, String data, String contentType) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.POST).contentType(contentType) .body(data).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * リクエストヘッダを指定するPOSTメソッド. // * @param url リクエスト対象URL // * @param map リクエストヘッダーのハッシュマップ // * @param data 書き込むデータ // * @param contentType CONTENT-TYPE値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the POST method that receives the request body that does not need authorization and uses header map. * @param url Target URL * @param map HashMap of Request Header * @param data Data to be written * @param contentType CONTENT-TYPE value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse post(String url, HashMap<String, String> map, String data, String contentType) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method(HttpMethods.POST).contentType(contentType) .body(data).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()).build(); for (Map.Entry<String, String> entry : map.entrySet()) { req.setHeader(entry.getKey(), entry.getValue()); } return this.request(req); } // /** // * レスポンスボディを受けるMERGEメソッド. // * @param url リクエスト対象URL // * @param data 書き込むデータ // * @param etag ETag // * @param contentType CONTENT-TYPE値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the MERGE method that receives the response body. * @param url Target URL * @param data Data to be written * @param etag ETag value * @param contentType CONTENT-TYPE value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse merge(String url, String data, String etag, String contentType) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method("MERGE").contentType(contentType).ifMatch(etag) .body(data).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * DELETEメソッド. // * @param url リクエスト対象URL // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the DELETE method that internally calls its overloaded version. * @param url Target URL * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse del(String url) throws DaoException { Map<String, String> headers = null; return this.del(url, headers); } // /** // * DELETEメソッド. // * @param url リクエスト対象URL // * @param etag DELETE対象のETag // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the DELETE method that uses Etag value. * @param url Target URL * @param etag ETag value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse del(String url, String etag) throws DaoException { Map<String, String> headers = new HashMap<String, String>(); headers.put("If-Match", etag); return this.del(url, headers); } /** * This is the overloaded version of delete method with provision for arbitrary header. * @param url to be deleted * @param headers request headers * @return DcResponse response * @throws DaoException Library Exception */ public DcResponse del(String url, Map<String, String> headers) throws DaoException { DcRequestBuilder requestBuilder = new DcRequestBuilder().url(url).method(HttpMethods.DELETE).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()); /** add the headers to request builder. */ if (headers != null && headers.size() > 0) { Set<Entry<String, String>> entrySet = headers.entrySet(); for (Entry<String, String> entry : entrySet) { if (entry.getValue() != null) { requestBuilder.header(entry.getKey(), entry.getValue()); } } } HttpUriRequest req = requestBuilder.build(); return this.request(req); } // /** // * ACLメソッド. // * @param url リクエスト対象URL // * @param body リクエストボディ // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the ACL method for setting the ACL. * @param url Target URL * @param body Request Body * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse acl(String url, String body) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method("ACL").contentType(CONTENT_TYPE_XML) .accept(CONTENT_TYPE_XML).body(body).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * MKCOLメソッド. // * @param url リクエスト対象URL // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the MKCOL method to create a collection. * @param url Target URL * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse mkcol(String url) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method("MKCOL").contentType(CONTENT_TYPE_XML) .accept(CONTENT_TYPE_XML).body(REQUEST_BODY_MKCOL_XML).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * MKCOL拡張メソッド(ODataコレクション作成). // * @param url リクエスト対象URL // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the MKODATA method to create a OData collection. * @param url Target URL * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse mkOData(String url) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method("MKCOL").contentType(CONTENT_TYPE_XML) .accept(CONTENT_TYPE_XML).body(REQUEST_BODYMKODATA_XML).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * MKCOL拡張メソッド(Serviceコレクション作成). // * @param url リクエスト対象URL // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the MKSERVICE method to create a service. * @param url Target URL * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse mkService(String url) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method("MKCOL").contentType(CONTENT_TYPE_XML) .accept(CONTENT_TYPE_XML).body(REQUEST_BODY_SERVICE_XML).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * MKCOL拡張メソッド(Calendarコレクション作成). // * @param url リクエスト対象URL // * @throws DaoException DAO例外 // */ /** * This is the MKCALENDAR method to create a calendar. * @param url Target URL * @throws DaoException Exception thrown */ public void mkCalendar(String url) throws DaoException { this.mkcol(url); } // /** // * サービス登録専用PROPPATCHメソッド. // * @param url リクエスト対象URL // * @param key プロパティ名 // * @param value プロパティの値 // * @param subject サービスサブジェクトの値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PROPPATCH method for service registration with subject. * @param url Target URL * @param key Property Name * @param value Property Value * @param subject Subject service * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse setService(String url, String key, String value, String subject) throws DaoException { String body = REQUEST_BODY_PROPPATCH_XML.replace("SERVICE_KEY", key).replace("SERVICE_VALUE", value) .replace("SERVICE_SUBJECT", subject); HttpUriRequest req = new DcRequestBuilder().url(url).method("PROPPATCH").contentType(CONTENT_TYPE_XML) .accept(CONTENT_TYPE_XML).body(body).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * PROPPATCHメソッド. // * @param url リクエスト対象URL // * @param key プロパティ名 // * @param value プロパティの値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PROPPATCH method for service registration without subject. * @param url Target URL * @param key Property Name * @param value Property Value * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse proppatch(String url, String key, String value) throws DaoException { StringBuilder sb = new StringBuilder(); sb.append("<D:propertyupdate xmlns:D=\"DAV:\" xmlns:dc=\"urn:x-dc1:xmlns\"><D:set><D:prop>"); sb.append("<"); sb.append(key); sb.append(">"); sb.append(value); sb.append("</"); sb.append(key); sb.append(">"); sb.append("</D:prop></D:set></D:propertyupdate>"); HttpUriRequest req = new DcRequestBuilder().url(url).method("PROPPATCH").contentType(CONTENT_TYPE_XML) .accept(CONTENT_TYPE_XML).body(sb.toString()).token(getToken()) .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * PROPFINDメソッド. // * @param url リクエスト対象URL // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This is the PROPFIND method. * @param url Target URL * @return DcResponse object * @throws DaoException Exception thrown */ public DcResponse propfind(String url) throws DaoException { HttpUriRequest req = new DcRequestBuilder().url(url).method("PROPFIND").contentType(CONTENT_TYPE_XML) .token(getToken()).accept(CONTENT_TYPE_XML).depth("1") .defaultHeaders(this.accessor.getDefaultHeaders()).build(); return this.request(req); } // /** // * Reponseボディを受ける場合のHTTPリクエストを行う. // * @param httpReq HTTPリクエスト // * @return DCレスポンスオブジェクト // * @throws DaoException DAO例外 // */ /** * This method is used to make HTTP requests may be subject to response body. * @param httpReq HTTPRequest * @return DCReaponse object * @throws DaoException Exception thrown */ private DcResponse request(HttpUriRequest httpReq) throws DaoException { try { HttpResponse objResponse = httpClient.execute(httpReq); DcResponse dcRes = new DcResponse(objResponse); this.accessor.setResHeaders(objResponse.getAllHeaders()); int statusCode = objResponse.getStatusLine().getStatusCode(); if (statusCode >= STATUS300 && statusCode != HttpStatus.SC_MOVED_TEMPORARILY) { throw DaoException.create(dcRes.bodyAsString(), statusCode); } return dcRes; } catch (IOException ioe) { throw DaoException.create("io exception : " + ioe.getMessage(), 0); } } // /** // * Accessorからトークンを取得する. // * @return トークン // */ /** * This method gets the token from Accessor. * @return Token value */ private String getToken() { String token = this.accessor.getAccessToken(); return token; } /** * This method is used to make a MKCOL request through actual bar file. * @param url box path * @param requestBody HTTP Request Body to be sent in the form of InputStream. * @param contentType ContentType Header Value * @return DcResponse response * @throws DaoException Library Exception */ public DcResponse mkcol(String url, InputStream requestBody, String contentType) throws DaoException { DcRequestBuilder requestBuilder = new DcRequestBuilder().url(url).method("MKCOL").contentType(contentType) .body(requestBody).token(getToken()).defaultHeaders(this.accessor.getDefaultHeaders()); HttpUriRequest req = requestBuilder.build(); return this.request(req); } }