/** * 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.UnsupportedEncodingException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.UUID; import com.fujitsu.dc.client.Accessor; import com.fujitsu.dc.client.DaoException; ///** // * $Batchアクセスのためのリクエストを作成するクラス. // */ /** * It creates a new object of BatchAdapter. This class is used to create a request for $Batch access . */ public class BatchAdapter implements IRestAdapter { // /** アクセス主体. */ /** Reference to Accessor. */ private Accessor accessor; /** Variable for BatchBoundary. */ private String batchBoundary; // /** $Batchリクエスト. */ // private StringBuilder sbRequest = new StringBuilder(); /** Variable for Batch. */ private Batch batch; /** Variable for ChangeSet. */ private ChangeSet changeSet; // /** 改行コード. */ /** Line feed code. */ private static final String CRLF = "\r\n"; // /** // * コマンドを$Batchフォーマットに生成する. // */ /** * This is the inner class used to generate the $Batch format command. */ private class Command { /** Variable for URL. */ private String url = null; /** Variable for Method. */ private String method = null; /** Variable for Etag. */ private String etag = null; /** Variable for Body. */ private StringBuilder body = null; /** Variable for ContentLength. */ private int contentLength = 0; /** Variable for Headers. */ private ArrayList<String> headers = new ArrayList<String>(); /** * This method is used to set Content Length. * @param value the body to set. */ void setBody(String value) { body = new StringBuilder(value); try { this.contentLength = value.getBytes("UTF-8").length; } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } /** * This method adds key value pair in header array. * @param key Value * @param value Value */ void addHeader(final String key, final String value) { this.headers.add(key + ": " + value); } /** * This method is used to get the $batch format command. * @return $batch format command */ String get() { StringBuilder sb = new StringBuilder(); /** GET. */ if (this.method.equals(HttpMethods.GET)) { sb.append("--" + batchBoundary).append(CRLF); sb.append("Content-Type: application/http").append(CRLF); sb.append("Content-Transfer-Encoding:binary").append(CRLF); sb.append(CRLF); } /** method url http-ver. */ sb.append(this.method).append(" ").append(this.url).append(" HTTP/1.1").append(CRLF); /** host. */ sb.append("Host: ").append(CRLF); /** header. */ for (String header : headers) { sb.append(header).append(CRLF); } /** Content-Length. */ sb.append("Content-Length: " + Integer.toString(this.contentLength)).append(CRLF); /** If-Match. */ if (null != this.etag) { sb.append("If-Match: " + this.etag).append(CRLF); } if (HttpMethods.POST.equals(this.method) || HttpMethods.PUT.equals(this.method)) { sb.append(CRLF); sb.append(this.body.toString()).append(CRLF); } return sb.toString(); } } // /** // * $Batchの複数ChangeSetをまとめる. // */ /** * This is the inner class used to put together a multiple ChangeSet of $Batch. */ private class ChangeSet { /** Variable for Changeset Boundary. */ private String changesetBoundary = null; /** Variable for Body. */ private StringBuilder body = null; // private int contentLength = 0; /** * This is the parameterized constructor to initialize changesetBoundary. * @param value changesetBoundary Value */ ChangeSet(final String value) { this.changesetBoundary = value; } /** * This method is used to create the body for ChangeSet. * @param value Value * @throws DaoException Exception thrown */ void append(final String value) throws DaoException { if (body == null) { body = new StringBuilder(); } else { body.append(CRLF); } /** ChangeSetHeader. */ body.append("--" + this.changesetBoundary).append(CRLF); body.append("Content-Type: application/http").append(CRLF); body.append("Content-Transfer-Encoding: binary").append(CRLF); body.append(CRLF); body.append(value); // try { // this.contentLength += body.toString().getBytes("UTF-8").length; // } catch (UnsupportedEncodingException e) { // throw new DaoException(e.getMessage()); // } } /** * This method is used to get the $Batch ChangeSet command. * @return $Batch ChangeSet command * @throws DaoException Exception thrown */ String get() throws DaoException { this.body.append(CRLF); StringBuilder sb = new StringBuilder(); String changeSetFooter = "--" + this.changesetBoundary + "--"; sb.append("--" + batchBoundary).append(CRLF); sb.append("Content-Type: multipart/mixed; boundary=").append(this.changesetBoundary).append(CRLF); // Content-Length try { sb.append( "Content-Length: " + Integer.toString(this.body.toString().getBytes("UTF-8").length + changeSetFooter.getBytes("UTF-8").length)).append(CRLF); } catch (UnsupportedEncodingException e) { throw new DaoException(e.getMessage()); } sb.append(CRLF); /** ChangeSetBody. */ sb.append(this.body); sb.append(changeSetFooter).append(CRLF); return sb.toString(); } } // /** // * コマンドを$Batchフォーマットに生成する. // */ /** * This is the inner class used to generate the $Batch format command. */ private class Batch { /** Variable for Batch. */ private StringBuilder batch = null; /** * This is the default constructor to initialize Batch. */ Batch() { batch = new StringBuilder(); // batch.append("--" + batchBoundary).append(BR); // batch.append("Content-Type: application/http").append(BR); } /** * This method is used to append value to Batch. * @param value the body to set. */ void append(String value) { if (batch.length() > 0) { batch.append(CRLF); } batch.append(value); } /** * This method is used to get the Batch value. * @return Batch value in String form */ String get() { batch.append(CRLF); batch.append("--" + batchBoundary + "--"); return batch.toString(); } } // /** // * コンストラクタ. // * @param as アクセス主体 // */ /** * This is the parameterized constructor used to initialize various class variables. * @param as Accessor object */ public BatchAdapter(Accessor as) { this.accessor = as; this.batchBoundary = "batch_" + UUID.randomUUID().toString(); this.batch = new Batch(); } /** * This method returns the Accessor. * @return the accessor */ public final Accessor getAccessor() { return accessor; } /** * This method returns the BatchBoundary. * @return the batchBoundary */ public final String getBatchBoundary() { return batchBoundary; } /** * This method is used to append value to the ChangeSet. * @param value ChangeSet value * @throws DaoException Exception thrown */ private void appendChangeSet(String value) throws DaoException { if (null == this.changeSet) { this.changeSet = new ChangeSet("changeset_" + UUID.randomUUID().toString()); } this.changeSet.append(value); } /** * This method appends value of ChangeSet to Batch and overwrites ChangeSet. * @throws DaoException Exception thrown */ private void writeChangeSet() throws DaoException { if (null != this.changeSet) { batch.append(changeSet.get()); this.changeSet = null; } } // /** // * BatchBoundaryを挿入する. // * @throws DaoException Dao例外 // */ /** * This method is used to insert the BatchBoundary. * @throws DaoException Exception thrown */ public void insertBoundary() throws DaoException { writeChangeSet(); } /** * This method is used to fetch the Command. It calls its overloaded version internally. * @param url URL value * @param accept Value * @return DcResponse * @throws DaoException Exception thrown */ @Override public DcResponse get(String url, String accept) throws DaoException { return get(url, accept, null); } /** * This method appends the ChangeSet. It returns a new instance of DcBatchResponse. * @param url Value * @param accept Value * @param etag Value * @return DcResponse * @throws DaoException Exception thrown */ @Override public DcResponse get(String url, String accept, String etag) throws DaoException { // 溜めたChangeSetを吐き出す /** Update ChangeSet. */ this.writeChangeSet(); Command cmd = new Command(); cmd.method = HttpMethods.GET; cmd.url = url; cmd.addHeader("Accept-Encoding", "gzip"); cmd.addHeader("Accept", accept); cmd.etag = etag; batch.append(cmd.get()); return new DcBatchRespose(); } /** * This method will be used to return Command when headers are specified. This has not been implemented yet. * @param url Value * @param headers Map * @param etag Value * @return DcResponse * @throws DaoException Exception thrown */ @Override public DcResponse get(String url, Map<String, String> headers, String etag) throws DaoException { throw new DaoException("Not Implemented"); } /** * This method retrieves the ChangeSet. * @param url Value * @return DcResponse object * @throws DaoException Exception thrown */ @Override public DcResponse head(String url) throws DaoException { // 溜めたChangeSetを吐き出す /** Update ChangeSet. */ this.writeChangeSet(); return get(url, CONTENT_TYPE_JSON, null); } /** * This method updates the ChangeSet. * @param url Value * @param data Value * @param etag Value * @param contentType Value * @return DcBatchRespose object * @throws DaoException Exception thrown */ @Override public DcResponse put(String url, String data, String etag, String contentType) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.PUT; cmd.url = url; cmd.addHeader("Content-Type", contentType); cmd.etag = etag; cmd.setBody(data); appendChangeSet(cmd.get()); return new DcBatchRespose(); } /** * This method updates the ChangeSet and creates header for Command. * @param url Value * @param data Value * @param etag Value * @param map Header Map * @param contentType Value * @return DcBatchRespose object * @throws DaoException Exception thrown */ @Override public DcResponse put(String url, String data, String etag, HashMap<String, String> map, String contentType) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.PUT; cmd.url = url; cmd.addHeader("Content-Type", contentType); cmd.etag = etag; cmd.setBody(data); for (Map.Entry<String, String> entry : map.entrySet()) { cmd.addHeader(entry.getKey(), entry.getValue()); } appendChangeSet(cmd.get()); return new DcBatchRespose(); } /** * This method creates a ChangeSet. * @param url Value * @param data Value * @param contentType Value * @return DcBatchRespose object * @throws DaoException Exception thrown */ @Override public DcResponse post(String url, String data, String contentType) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.POST; cmd.url = url; cmd.addHeader("Content-Type", contentType); cmd.setBody(data); appendChangeSet(cmd.get()); return new DcBatchRespose(); } /** * This method creates a ChangeSet and creates header for Command. * @param url Value * @param map Header Map * @param data Value * @param contentType Value * @return DcBatchRespose object * @throws DaoException Exception thrown */ @Override public DcResponse post(String url, HashMap<String, String> map, String data, String contentType) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.POST; cmd.url = url; cmd.addHeader("Content-Type", contentType); cmd.setBody(data); for (Map.Entry<String, String> entry : map.entrySet()) { cmd.addHeader(entry.getKey(), entry.getValue()); } appendChangeSet(cmd.get()); return new DcBatchRespose(); } /** * This method deletes the ChangeSet. * @param url Value * @return DcBatchResponse object * @throws DaoException Exception thrown */ @Override public DcResponse del(String url) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.DELETE; cmd.url = url; appendChangeSet(cmd.get()); return new DcBatchRespose(); } /** * This method deletes the ChangeSet using Etag value. * @param url Value * @param etag Value * @return DcBatchResponse object * @throws DaoException Exception thrown */ @Override public DcResponse del(String url, String etag) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.DELETE; cmd.url = url; cmd.etag = etag; appendChangeSet(cmd.get()); return new DcBatchRespose(); } // /** // * $Batchのボディ情報を取得する. // * @return Batch登録するボディ. // * @throws DaoException DAO例外 // */ /** * This method is used to get the body of information $ Batch. * @return Batch Registration Body * @throws DaoException Exception thrown */ public String get() throws DaoException { // 溜めたChangeSetを吐き出す /** Update ChangeSet. */ this.writeChangeSet(); return this.batch.get(); } // /** // * レスポンスボディを受けるMERGEメソッド. // * @param url リクエスト対象URL // * @param data 書き込むデータ // * @param etag ETag // * @param contentType CONTENT-TYPE値 // * @return DcResponseオブジェクト // * @throws DaoException DAO例外 // */ /** * This method will receive the response body. It has not been implemented yet. * @param url Target Request URL * @param data Data to be witten * @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 { // TODO バッチ経由のMERGEメソッドの処理を実装する /** TODO Implement the processing of the MERGE method via batch. */ DcResponse res = null; return res; } /** * This method updates the ChangeSet and adds header to Command. * @param url Value * @param map Header Map * @return DcBatchRespose object * @throws DaoException Exception thrown */ @Override public DcResponse put(String url, HashMap<String, String> map) throws DaoException { Command cmd = new Command(); cmd.method = HttpMethods.PUT; cmd.url = url; for (Map.Entry<String, String> entry : map.entrySet()) { cmd.addHeader(entry.getKey(), entry.getValue()); } appendChangeSet(cmd.get()); return new DcBatchRespose(); } }