<?xml version="1.0"?>

<!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
-->

<document>

 <properties>
  <title>Turbine Services - JSON-RPC Service</title>
  <author email="seade@backstagetech.com.au">Scott Eade</author>
 </properties>

<body>

<section name="JSON-RPC Service">

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

</section>

<section name="Configuration">

<source><![CDATA[
# -------------------------------------------------------------------
#
#  S E R V I C E S
#
# -------------------------------------------------------------------
...
services.JsonRpcService.classname=org.apache.turbine.services.jsonrpc.TurbineJsonRpcService
...
]]></source>

</section>

<section name="Usage">

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

<source><![CDATA[
public class MyJsonFunctions
{
    public String getHello(String clientParameter)
    {
        return "Hello " + clientParameter;
    }
    public String getGoodbye(String clientParameter)
    {
        return "Goodbye " + clientParameter;
    }
}
]]></source>

<p>
Next you implement your Screen class to make your functions available:
</p>

<source><![CDATA[
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);
    }
}
]]></source>

<subsection name="Client Side: Synchronous AJAX Calls">
<p>

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:
</p>

<source><![CDATA[
// 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;
}
]]></source>

<p>
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 <code>webapps\jsonrpc</code> directory):
</p>

<source><![CDATA[
$page.addScript($content.getURI('scripts/jsonrpc.js'))
]]></source>

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

<source><![CDATA[
<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>
]]></source>

</subsection>
<subsection name="Client Side: Asynchronous AJAX Call">

<p>
Alternatively, asynchronous calls require handling of the deferred objects, which could be done by using some kind of <a href="https://www.promisejs.org/">Promise</a>) library.
As an example a <a href="http://api.jquery.com/category/deferred-object/">JQuery Promise Object model</a> (supported since version 1.5) is shown.
Usage of asynchronous calls conforms more to <a href="ttps://xhr.spec.whatwg.org/#synchronous-flag">XMLHttpRequest specification</a>.
</p>

<source><![CDATA[

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

]]></source>

<p>
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 <code>webapps\jsonrpc</code> directory):
</p>

<source><![CDATA[
$page.addScript($content.getURI('scripts/jsonrpc.js'))
]]></source>

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

<source><![CDATA[
<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>
]]></source>

</subsection>
<p>
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.
</p>

</section>

</body>
</document>
