Coverage Report - org.apache.shindig.social.opensocial.service.JsonRpcServlet
 
Classes in this File Line Coverage Branch Coverage Complexity
JsonRpcServlet
74%
61/82
61%
17/28
0
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements. See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership. The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License. You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied. See the License for the
 16  
  * specific language governing permissions and limitations under the License.
 17  
  */
 18  
 package org.apache.shindig.social.opensocial.service;
 19  
 
 20  
 import org.apache.shindig.auth.SecurityToken;
 21  
 import org.apache.shindig.common.util.JsonConversionUtil;
 22  
 import org.apache.shindig.social.ResponseError;
 23  
 import org.apache.shindig.social.opensocial.spi.DataCollection;
 24  
 import org.apache.shindig.social.opensocial.spi.RestfulCollection;
 25  
 
 26  
 import com.google.common.collect.Lists;
 27  
 import org.apache.commons.io.IOUtils;
 28  
 import org.apache.commons.lang.StringUtils;
 29  
 import org.json.JSONArray;
 30  
 import org.json.JSONException;
 31  
 import org.json.JSONObject;
 32  
 
 33  
 import java.io.IOException;
 34  
 import java.util.List;
 35  
 import java.util.concurrent.Future;
 36  
 import javax.servlet.ServletException;
 37  
 import javax.servlet.http.HttpServletRequest;
 38  
 import javax.servlet.http.HttpServletResponse;
 39  
 
 40  
 /**
 41  
  * JSON-RPC handler servlet.
 42  
  */
 43  7
 public class JsonRpcServlet extends ApiServlet {
 44  
 
 45  
   @Override
 46  
   protected void doGet(HttpServletRequest servletRequest,
 47  
       HttpServletResponse servletResponse)
 48  
       throws ServletException, IOException {
 49  1
     SecurityToken token = getSecurityToken(servletRequest);
 50  1
     if (token == null) {
 51  0
       sendSecurityError(servletResponse);
 52  0
       return;
 53  
     }
 54  
 
 55  
     try {
 56  1
       setCharacterEncodings(servletRequest, servletResponse);
 57  1
       JSONObject request = JsonConversionUtil.fromRequest(servletRequest);
 58  1
       dispatch(request, servletRequest, servletResponse, token);
 59  0
     } catch (JSONException je) {
 60  
       // FIXME
 61  1
     }
 62  1
   }
 63  
 
 64  
   @Override
 65  
   protected void doPost(HttpServletRequest servletRequest,
 66  
       HttpServletResponse servletResponse)
 67  
       throws ServletException, IOException {
 68  6
     SecurityToken token = getSecurityToken(servletRequest);
 69  6
     if (token == null) {
 70  0
       sendSecurityError(servletResponse);
 71  0
       return;
 72  
     }
 73  
 
 74  6
     setCharacterEncodings(servletRequest, servletResponse);
 75  6
     servletResponse.setContentType("application/json");
 76  
 
 77  
     try {
 78  6
       String content = IOUtils.toString(servletRequest.getInputStream(),
 79  
           servletRequest.getCharacterEncoding());
 80  6
       if ((content.indexOf('[') != -1) && content.indexOf('[') < content.indexOf('{')) {
 81  
         // Is a batch
 82  1
         JSONArray batch = new JSONArray(content);
 83  1
         dispatchBatch(batch, servletRequest, servletResponse, token);
 84  1
       } else {
 85  5
         JSONObject request = new JSONObject(content);
 86  5
         dispatch(request, servletRequest, servletResponse, token);
 87  
       }
 88  0
     } catch (JSONException je) {
 89  0
       sendBadRequest(je, servletResponse);
 90  6
     }
 91  6
   }
 92  
 
 93  
   protected void dispatchBatch(JSONArray batch, HttpServletRequest servletRequest,
 94  
       HttpServletResponse servletResponse, SecurityToken token) throws JSONException, IOException {
 95  
     // Use linked hash map to preserve order
 96  1
     List<Future<?>> responses = Lists.newArrayListWithExpectedSize(batch.length());
 97  
 
 98  
     // Gather all Futures.  We do this up front so that
 99  
     // the first call to get() comes after all futures are created,
 100  
     // which allows for implementations that batch multiple Futures
 101  
     // into single requests.
 102  3
     for (int i = 0; i < batch.length(); i++) {
 103  2
       JSONObject batchObj = batch.getJSONObject(i);
 104  2
       RpcRequestItem requestItem = new RpcRequestItem(batchObj, token, jsonConverter);
 105  2
       responses.add(handleRequestItem(requestItem, servletRequest));
 106  
     }
 107  
 
 108  
     // Resolve each Future into a response.
 109  
     // TODO: should use shared deadline across each request
 110  1
     JSONArray result = new JSONArray();
 111  3
     for (int i = 0; i < batch.length(); i++) {
 112  2
       JSONObject batchObj = batch.getJSONObject(i);
 113  2
       String key = null;
 114  2
       if (batchObj.has("id")) {
 115  2
         key = batchObj.getString("id");
 116  
       }
 117  2
       result.put(getJSONResponse(key, getResponseItem(responses.get(i))));
 118  
     }
 119  1
     servletResponse.getWriter().write(result.toString());
 120  1
   }
 121  
 
 122  
   protected void dispatch(JSONObject request, HttpServletRequest servletRequest,
 123  
       HttpServletResponse servletResponse, SecurityToken token) throws JSONException, IOException {
 124  6
     String key = null;
 125  6
     if (request.has("id")) {
 126  6
       key = request.getString("id");
 127  
     }
 128  6
     RpcRequestItem requestItem = new RpcRequestItem(request, token, jsonConverter);
 129  
 
 130  
     // Resolve each Future into a response.
 131  
     // TODO: should use shared deadline across each request
 132  6
     ResponseItem response = getResponseItem(handleRequestItem(requestItem, servletRequest));
 133  6
     JSONObject result = getJSONResponse(key, response);
 134  6
     servletResponse.getWriter().write(result.toString());
 135  6
   }
 136  
 
 137  
   private JSONObject getJSONResponse(String key, ResponseItem responseItem) throws JSONException {
 138  8
     JSONObject result = new JSONObject();
 139  8
     if (key != null) {
 140  8
       result.put("id", key);
 141  
     }
 142  8
     if (responseItem.getError() != null) {
 143  2
       result.put("error", getErrorJson(responseItem));
 144  2
     } else {
 145  6
       Object response = responseItem.getResponse();
 146  6
       JSONObject converted = (JSONObject) jsonConverter.convertToJson(response);
 147  
 
 148  6
       if (response instanceof RestfulCollection) {
 149  
         // FIXME this is a little hacky because of the field names in the RestfulCollection
 150  0
         converted.put("list", converted.remove("entry"));
 151  0
         result.put("data", converted);
 152  0
       } else if (response instanceof DataCollection) {
 153  0
         if (converted.has("entry")) {
 154  0
           result.put("data", converted.get("entry"));
 155  0
         }
 156  
       } else {
 157  6
         result.put("data", converted);
 158  
       }
 159  
     }
 160  8
     return result;
 161  
   }
 162  
 
 163  
   // TODO(doll): Refactor the responseItem so that the fields on it line up with this format.
 164  
   // Then we can use the general converter to output the response to the client and we won't
 165  
   // be harcoded to json.
 166  
   private JSONObject getErrorJson(ResponseItem responseItem) throws JSONException {
 167  2
     JSONObject error = new JSONObject();
 168  2
     error.put("code", responseItem.getError().getHttpErrorCode());
 169  
 
 170  2
     String message = responseItem.getError().toString();
 171  2
     if (StringUtils.isNotBlank(responseItem.getErrorMessage())) {
 172  2
       message += ": " + responseItem.getErrorMessage();
 173  
     }
 174  2
     error.put("message", message);
 175  2
     return error;
 176  
   }
 177  
 
 178  
   @Override
 179  
   protected void sendError(HttpServletResponse servletResponse, ResponseItem responseItem)
 180  
       throws IOException {
 181  
     try {
 182  0
       JSONObject error = getErrorJson(responseItem);
 183  0
       servletResponse.getWriter().write(error.toString());
 184  0
     } catch (JSONException je) {
 185  
       // This really shouldn't ever happen
 186  0
       servletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
 187  
           "Error generating error response " + je.getMessage());
 188  0
     }
 189  0
   }
 190  
 
 191  
   private void sendBadRequest(Throwable t, HttpServletResponse response) throws IOException {
 192  0
     sendError(response, new ResponseItem(ResponseError.BAD_REQUEST,
 193  
         "Invalid batch - " + t.getMessage()));
 194  0
   }
 195  
 }