001package com.box.sdk; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.Iterator; 006import java.util.List; 007import java.util.Map; 008 009import com.box.sdk.http.HttpHeaders; 010import com.box.sdk.http.HttpMethod; 011import com.eclipsesource.json.JsonArray; 012import com.eclipsesource.json.JsonObject; 013import com.eclipsesource.json.JsonValue; 014 015/** 016 * Used to make a bunch of HTTP Requests as a batch. Currently the number of requests that can be batched at once 017 * is capped at <b>20</b> by the API layer. Also there are certain requests which <b>cannot</b> be performed 018 * by Batch API. Check API documentation for more information. 019 * 020 * <p>The request itself is a BoxJSONRequest but extends it to provide additional functionality for aggregating 021 * a bunch of requests and responding with multiple responses as if the requests were called individually</p> 022 */ 023public class BatchAPIRequest extends BoxJSONRequest { 024 /** 025 * Batch URL Template. 026 */ 027 public static final URLTemplate BATCH_URL_TEMPLATE = new URLTemplate("batch"); 028 private final BoxAPIConnection api; 029 030 /** 031 * Constructs an authenticated BatchRequest using a provided BoxAPIConnection. 032 * @param api an API connection for authenticating the request. 033 */ 034 public BatchAPIRequest(BoxAPIConnection api) { 035 super(api, BATCH_URL_TEMPLATE.build(api.getBaseURL()), HttpMethod.GET); 036 this.api = api; 037 } 038 039 /** 040 * Execute a set of API calls as batch request. 041 * @param requests list of api requests that has to be executed in batch. 042 * @return list of BoxAPIResponses 043 */ 044 public List<BoxAPIResponse> execute(List<BoxAPIRequest> requests) { 045 this.prepareRequest(requests); 046 BoxJSONResponse batchResponse = (BoxJSONResponse) send(); 047 return this.parseResponse(batchResponse); 048 } 049 050 /** 051 * Prepare a batch api request using list of individual reuests. 052 * @param requests list of api requests that has to be executed in batch. 053 */ 054 protected void prepareRequest(List<BoxAPIRequest> requests) { 055 JsonObject body = new JsonObject(); 056 JsonArray requestsJSONArray = new JsonArray(); 057 for (BoxAPIRequest request: requests) { 058 JsonObject batchRequest = new JsonObject(); 059 batchRequest.add("method", request.getMethod()); 060 batchRequest.add("relative_url", request.getUrl().toString().substring(this.api.getBaseURL().length() - 1)); 061 //If the actual request has a JSON body then add it to vatch request 062 if (request instanceof BoxJSONRequest) { 063 BoxJSONRequest jsonRequest = (BoxJSONRequest) request; 064 batchRequest.add("body", jsonRequest.getBodyAsJsonValue()); 065 } 066 //Add any headers that are in the request, except Authorization 067 if (request.getHeaders() != null) { 068 JsonObject batchRequestHeaders = new JsonObject(); 069 for (RequestHeader header: request.getHeaders()) { 070 if (header.getKey() != null && !header.getKey().isEmpty() 071 && HttpHeaders.AUTHORIZATION.equals(header.getKey())) { 072 batchRequestHeaders.add(header.getKey(), header.getValue()); 073 } 074 } 075 batchRequest.add("headers", batchRequestHeaders); 076 } 077 078 //Add the request to array 079 requestsJSONArray.add(batchRequest); 080 } 081 //Add the requests array to body 082 body.add("requests", requestsJSONArray); 083 super.setBody(body); 084 } 085 086 /** 087 * Parses btch api response to create a list of BoxAPIResponse objects. 088 * @param batchResponse response of a batch api request 089 * @return list of BoxAPIResponses 090 */ 091 protected List<BoxAPIResponse> parseResponse(BoxJSONResponse batchResponse) { 092 JsonObject responseJSON = JsonObject.readFrom(batchResponse.getJSON()); 093 List<BoxAPIResponse> responses = new ArrayList<BoxAPIResponse>(); 094 Iterator<JsonValue> responseIterator = responseJSON.get("responses").asArray().iterator(); 095 while (responseIterator.hasNext()) { 096 JsonObject jsonResponse = responseIterator.next().asObject(); 097 BoxAPIResponse response = null; 098 099 //Gather headers 100 Map<String, String> responseHeaders = new HashMap<String, String>(); 101 102 if (jsonResponse.get("headers") != null) { 103 JsonObject batchResponseHeadersObject = jsonResponse.get("headers").asObject(); 104 for (JsonObject.Member member : batchResponseHeadersObject) { 105 String headerName = member.getName(); 106 String headerValue = member.getValue().asString(); 107 responseHeaders.put(headerName, headerValue); 108 } 109 } 110 111 // Construct a BoxAPIResponse when response is null, or a BoxJSONResponse when there's a response 112 // (not anticipating any other response as per current APIs. 113 // Ideally we should do it based on response header) 114 if (jsonResponse.get("response") == null || jsonResponse.get("response").isNull()) { 115 response = 116 new BoxAPIResponse(jsonResponse.get("status").asInt(), responseHeaders); 117 } else { 118 response = 119 new BoxJSONResponse(jsonResponse.get("status").asInt(), responseHeaders, 120 jsonResponse.get("response").asObject()); 121 } 122 responses.add(response); 123 } 124 return responses; 125 } 126}