/*
* 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;
}