JSON-RPC Service

The JSON-RPC Service supports JavaScript to Java AJAX communications using JSON-RPC-Java (Jabsorb replaced project oss.metaparadigm.com/jsonrpc/. As of March 2015 Google Code projects are only read-only and this project is archived too, though GIT exports are allowed probably until Jan 2016, e.g. https://github.com/gmkll/jabsorb).

Configuration

# -------------------------------------------------------------------
#
#  S E R V I C E S
#
# -------------------------------------------------------------------
...
services.JsonRpcService.classname=org.apache.turbine.services.jsonrpc.TurbineJsonRpcService
...

Usage

There are a number of things you need to do in order to add AJAX functionality to your webapp. First you implement the functions:

public class MyJsonFunctions
{
    public String getHello(String clientParameter)
    {
        return "Hello " + clientParameter;
    }
    public String getGoodbye(String clientParameter)
    {
        return "Goodbye " + clientParameter;
    }
}

Next you implement your Screen class to make your functions available:

public class MyJsonScreen extends JSONScreen
{
    public void doOutput(RunData data) throws Exception
    {
        MyJsonFunctions myFunctions = new MyJsonFunctions();

        // Session specific
        TurbineJsonRpc.registerObject(data.getSession(), "myFunctions", myFunctions);

        // Global
        //TurbineJsonRpc.registerObjectGlobal("testGlobal", testObject);

        super.doOutput(data);
    }
}

Client Side: Synchronous AJAX Calls

Now we shift focus to your template classes. Firstly, there are a few useful utility functions that you need to make sure are available to the pages that will include AJAX functionality:

// Body onload utility (supports multiple onload functions)
function SafeAddOnload(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload();
      func();
    };
  }
}

// Prepare for possible JSON-RPC requests.
// jsonurl must be set before calling this function.
// First example synchronous call
function jsonOnLoadSync() {
  try {
    jsonrpc = new JSONRpcClient(jsonurl);
  }
  catch(e) {
    if(e.message) {
      alert(e.message);
    }
    else {
      alert(e);
    }
  }
}


// Process a JSON-RPC request.
function jsonEval(evalStr) {
  try	{
    return eval(evalStr);
  }
  catch(e) {
    if(e.javaStack) {
      alert("Exception: \n\n" + e.javaStack);
    }
    else {
      alert("Exception: \n\n" + e);
    }
  }
  return null;
}

In these pages you also need to include the JavaScript necessary to process the JSON calls - this file is available as part of the JSON-RPC Java distribution (it is included in the webapps\jsonrpc directory):

$page.addScript($content.getURI('scripts/jsonrpc.js'))

Then you need to set up the specific handler for the page (synchronous example):

<script type="text/javascript">
<!--
  ## Set up the JSON-RPC handler.
  var jsonurl = '$link.setScreen("MyJsonScreen")';
  SafeAddOnload(jsonOnLoad);
  ## myArg below would be provided when you call this function from your
  ## web page (usually you would retrieve something via the DOM or your
  ## favorite JavaScript DOM wrapper library).
  function retrieveHello(myArg) {
    ## This is a synchronous call.
    var helloResult = jsonEval("jsonrpc.myFunctions.getHello(" + myArg + ")");
    if(null == helloResult) {
      alert('Something went wrong!');
      return;
    }
    ## Here you would again use the DOM to include the result somewhere on your
    ## page.
  }
//-->
</script>

Client Side: Asynchronous AJAX Call

Alternatively, asynchronous calls require handling of the deferred objects, which could be done by using some kind of Promise) library. As an example a JQuery Promise Object model (supported since version 1.5) is shown. Usage of asynchronous calls conforms more to XMLHttpRequest specification.


// Prepare for possible JSON-RPC requests.
// jsonurl must be set before calling this function.
// Second example asynchronous call
var deferred;
function jsonOnLoad() {
  try { 
      // This feature is available since jabsorb 1.1 release, cft. webapps/jaxrpc/CHANGES.txt.
      // JQuery Promises are available since jQuery 1.5/1.8 (with major changes).
      // This is just an example, any other Promise handling will do it.
       if (deferred != undefined) {
            return deferred;
        } else {
            deferred =  jQuery.Deferred(function(defer) {
      // Add a default function as first parameter to enable asynchronous call.
                  jsonrpc = new JSONRpcClient(function(result, e) {
                        defer.resolve(result,e);
                    }, jsonurl);
            }).promise();
            return deferred;
        }
  }
  catch(e) {
    if(e.message) {
      alert(e.message);
    }
    else {
      alert(e);
    }
  }
}

In these pages you also need to include the JavaScript necessary to process the JSON calls - this file is available as part of the JSON-RPC-Java distribution (it is included in the webapps\jsonrpc directory):

$page.addScript($content.getURI('scripts/jsonrpc.js'))

Then you need to set up the specific handler for the page (in this case a asynchronous handler):

<script type="text/javascript">
<!--
  ## Set up the JSON-RPC handler.
  var jsonurl = '$link.setScreen("MyJsonScreen")';

  ## myArg below would be provided when you call this function from your
  ## web page (usually you would retrieve something via the DOM or your
  ## favorite JavaScript DOM wrapper library).
  function retrieveHello(myArg) {
    ## This is a an ansynchronous call as you provide as first parameter a callback function to getHello
    ## (Jabsorb JSON-RPC library expects it this way).
    var promiseA = jsonOnLoad();
    var promiseB = jQuery.Deferred();
    promiseA.done(
       function() {
         jQuery.Deferred(function(deferred) {
           jsonrpc.myFunctions.getHello( function(res,e) {
                    deferred.resolve(); // not used
                    promiseB.resolve(res);
                  }, " + myArg + ")" );
            }).promise();
        }
    );
    return jQuery.when(promiseA, promiseB);
    }
    
  # call function 
  var helloResult;
  var promise = retrieveHello(myArg);
  promise.done( 
      function(resultA,resultB) {
        helloResult = resultB;
        ## Here or in another dependent Promise you would again use the DOM to include the result somewhere on your
        ## page.
    }
  ); 
//-->
</script>

The above code is executable by users that are not logged into your application. Your Screen class can extend JSONSecureScreen to require that users be logged in before allowing execution.