/* * RpcRequest.java * * Copyright (C) 2009-12 by RStudio, Inc. * * Unless you have received this program directly from RStudio pursuant * to the terms of a commercial license agreement with RStudio, then * this program is licensed to you under the terms of version 3 of the * GNU Affero General Public License. This program is distributed WITHOUT * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details. * */ package org.rstudio.core.client.jsonrpc; import com.google.gwt.http.client.*; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; import com.google.gwt.user.client.Random; import org.rstudio.core.client.Debug; import org.rstudio.core.client.jsonrpc.RequestLogEntry.ResponseType; // NOTE: RpcRequest is an immutable object (all fields are marked final). // this means that it is safe to re-submit an RpcRequest since the // re-submission will always be identical to the initial submission (useful // for retries after network or authentication errors) public class RpcRequest { public static final boolean TRACE = false ; public RpcRequest(String url, String method, JSONArray params, JSONObject kwparams, boolean redactLog, String sourceWindow, String clientId, String clientVersion) { url_ = url; method_ = method; params_ = params ; kwparams_ = kwparams; redactLog_ = redactLog; if (sourceWindow != null) sourceWindow_ = new JSONString(sourceWindow); else sourceWindow_ = null; if (clientId != null) clientId_ = new JSONString(clientId); else clientId_ = null; clientVersion_ = new JSONString(clientVersion); } public void send(RpcRequestCallback callback) { // final references for access from anonymous class final RpcRequest enclosingRequest = this ; final RpcRequestCallback requestCallback = callback ; // build json request object JSONObject request = new JSONObject() ; request.put("method", new JSONString(method_)) ; if ( params_ != null ) request.put("params", params_); if ( kwparams_ != null) request.put("kwparams", kwparams_); // add src window if we have it if (sourceWindow_ != null) request.put("sourceWnd", sourceWindow_); // add client id if we have it if (clientId_ != null) request.put("clientId", clientId_); // add client version request.put("clientVersion", clientVersion_); // configure request builder RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, url_); builder.setHeader("Content-Type", "application/json") ; builder.setHeader("Accept", "application/json"); String requestId = Integer.toString(Random.nextInt()); builder.setHeader("X-RS-RID", requestId); // send request try { String requestString = request.toString(); if (TRACE) Debug.log("Request: " + requestString) ; requestLogEntry_ = RequestLog.log(requestId, redactLog_ ? "[REDACTED]" : requestString); request_ = builder.sendRequest(requestString, new RequestCallback() { public void onError(Request request, Throwable exception) { requestLogEntry_.logResponse(ResponseType.Error, exception.getLocalizedMessage()); // ERROR: Request failed RpcError error = RpcError.create( RpcError.TRANSMISSION_ERROR, exception.getLocalizedMessage()); requestCallback.onError(enclosingRequest, error) ; } public void onResponseReceived(Request request, Response response) { // only accept 200 responses int status = response.getStatusCode(); if ( status == 200 ) { // attempt to parse the response RpcResponse rpcResponse = null ; try { String responseText = response.getText(); if (TRACE) Debug.log("Response: " + responseText) ; requestLogEntry_.logResponse(ResponseType.Normal, responseText); rpcResponse = RpcResponse.parse(responseText); // response received and validated, process it! requestCallback.onResponseReceived(enclosingRequest, rpcResponse) ; } catch(Exception e) { // ERROR: Unable to parse JSON RpcError error = RpcError.create( RpcError.TRANSMISSION_ERROR, e.getLocalizedMessage()); requestCallback.onError(enclosingRequest, error) ; } } else { // ERROR: Non-200 response from server // default error message String message = "Status code " + Integer.toString(status) + " returned"; // override error message for status code 0 if (status == 0) { message = "Unable to establish connection with R session"; } requestLogEntry_.logResponse(ResponseType.Unknown, message); RpcError error = RpcError.create( RpcError.TRANSMISSION_ERROR, message) ; requestCallback.onError(enclosingRequest, error); } }; }); } catch(RequestException e) { // ERROR: general request failure String message = e.getLocalizedMessage(); if (requestLogEntry_ != null) requestLogEntry_.logResponse(ResponseType.Unknown, message); RpcError error = RpcError.create(RpcError.TRANSMISSION_ERROR, message); requestCallback.onError(enclosingRequest, error); } } public void cancel() { if (request_ != null) { request_.cancel(); request_ = null; } if (requestLogEntry_ != null) { requestLogEntry_.logResponse(ResponseType.Cancelled, "Cancelled"); requestLogEntry_ = null; } } final private String url_ ; final private String method_ ; final private JSONArray params_ ; final private JSONObject kwparams_; private final boolean redactLog_; final private JSONString sourceWindow_; final private JSONString clientId_; final private JSONString clientVersion_; private Request request_ = null; private RequestLogEntry requestLogEntry_ = null; }