/** * 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; import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.http.HttpHeaders; ///** // * $Batchのレスポンスを解析するクラス. // */ /** * This class is used to analyze the response of $ Batch. */ public class ODataBatchResponseParser { /** Variable BOUNDARY_KEY. */ static final String BOUNDARY_KEY = "--batch_"; /** Variable CHARSET_KEY. */ static final String CHARSET_KEY = "--changeset_"; /** Variable HTTP. */ static final String HTTP = "HTTP/1.1"; /** Variable CRLF. */ static final String CRLF = System.getProperty("line.separator"); /** Variable BLANK_LINE. */ static final String BLANK_LINE = CRLF + CRLF; /** Variable CONTENTTYPE_HTTP. */ static final String CONTENTTYPE_HTTP = "application/http"; /** Variable CONTENTTYPE_MULTIPART. */ static final String CONTENTTYPE_MULTIPART = "application/http"; // /** レスポンス情報の一覧. */ /** List of response information. */ ArrayList<ODataResponse> resList = new ArrayList<ODataResponse>(); // /** // * レスポンス解析. // * @param reader レスポンスボディReader // * @param boudaryKey Boundaryキー // * @return ODataResponseの配列 // */ /** * This method performs analysis on response using Reader. * @param reader Reader object * @param boudaryKey BoundaryKey * @return ODataResponse Array */ public List<ODataResponse> parse(Reader reader, String boudaryKey) { parseBoundary(reader, BOUNDARY_KEY); return resList; } // /** // * レスポンス解析. // * @param in レスポンスボディ文字列 // * @param boudaryKey Boundaryキー // * @return ODataResponseの配列 // */ /** * This method performs analysis on response using StringReader. * @param in Response Body String * @param boudaryKey BoundaryKey * @return ODataResponse Array */ public List<ODataResponse> parse(String in, String boudaryKey) { parseBoundary(new StringReader(in), BOUNDARY_KEY); return resList; } /** * This method parses the boundary. * @param reader Reader object * @param boudaryKey BoundaryKey */ void parseBoundary(Reader reader, String boudaryKey) { BufferedReader br = new BufferedReader(reader); StringBuilder sb = new StringBuilder(); try { String str = br.readLine(); while (str != null) { if (str.startsWith(boudaryKey)) { if (sb.length() > 0) { parseBodyBlock(sb.toString()); sb = new StringBuilder(); } str = br.readLine(); continue; } sb.append(str); sb.append(CRLF); str = br.readLine(); } br.close(); } catch (IOException e) { throw new RuntimeException(e); } } /** * This method parses the body. * @param body Response Body String */ void parseBodyBlock(String body) { // 空行で分割する /** To separate by a blank line. */ String[] blocks = body.split(BLANK_LINE); // ブロックが2個以上存在しなければHttpレスポンス型ではない /** It is not a Http response type block unless there are two or more. */ if (blocks.length < 2) { return; } // ブロックのヘッダ部を取得 /** Get the header portion of the block. */ HashMap<String, String> boundaryHeaders = parseHeaders(blocks[0]); // ブロックヘッダのContent-Typeを取得 /** Get the Content-Type header of the block. */ String contentType = boundaryHeaders.get(HttpHeaders.CONTENT_TYPE); if (contentType != null) { if (contentType.startsWith(CONTENTTYPE_HTTP)) { // application/http ならば 1つのリクエスト /** one request if application / http. */ StringBuilder responseBody = new StringBuilder(); // ボディ内に空行がふくまれている場合、2個目以降を連結する /** If a blank line is included in the body, connect the second and subsequent lines. */ for (int i = 2; i < blocks.length; i++) { responseBody.append(blocks[i]); } resList.add(new ODataResponse(blocks[1], responseBody.toString())); } else { // multipart/mixed ばらばマルチパート(複数のブロックで構成) /** (consist of blocks) multipart / mixed multipart Barabbas. */ parseBoundary(new StringReader(body), CHARSET_KEY); } } } // /** // * 複数行の塊となっているレスポンスヘッダーを分解してハッシュマップにセットする. // * @param value レスポンスヘッダ文字列 // * @return 1つ1つに分解されたハッシュマップ // */ /** * This method parses the headers by setting the hash map by decomposing the response header if it is of more than * one line. * @param value Response Header String * @return Hash map that has been broken down into one single value */ HashMap<String, String> parseHeaders(String value) { // 改行コードで分解する /** Decompose with a new line code. */ String[] lines = value.split(CRLF); HashMap<String, String> map = new HashMap<String, String>(); for (String line : lines) { String[] key = line.split(":"); if (key.length > 1) { // 前後に空白が含まれている可能性があるため、トリムしてからセットする /** Because there is a possibility of spaces in front and rear, so sets it after trim. */ map.put(key[0].trim(), key[1].trim()); } } return map; } }