javarpc.lzx
<library>
<include href="rpc/rpc.lzx"/>
<include href="rpc/library/javarpc.js"/>
<class name="javarpc" extends="rpc">
<attribute name="scope" type="string"/>
<attribute name="attributename" value="$once{this.name}" type="string"/>
<attribute name="remoteclassname" type="string"/>
<attribute name="loadoption" value="loadcreate
" type="string"/>
<attribute name="createargs" value="null
" type="expression"/>
<attribute name="objectreturntype" value="pojo
" type="string"/>
<method name="load">
if (! _isScopeOk(this.scope)) {
var errmsg = this.scope + ": bad scope";
if (this.onerror) {
this.onerror.sendEvent(errmsg);
}
Debug.write("javarpc ERROR:" + errmsg);
return;
}
if (! _isLoadOptionOk(this.loadoption)) {
if (this.onerror) {
this.onerror.sendEvent("bad loadoption (" + this.loadoption + ")");
}
Debug.write("javarpc: bad loadoption (" + this.loadoption + ")");
return;
}
if (null == this.name && null == this.attributename &&
('session' == this.scope || 'webapp' == this.scope)) {
if (this.onerror) {
this.onerror.sendEvent("name or attributename have not been set");
}
Debug.write("javarpc: name or attributename have not been set");
return;
}
if (arguments.length == 0) {
arguments = this.createargs;
}
var opts = {
loadoption: this.loadoption,
params: arguments,
classname: this.remoteclassname,
oname: this.attributename,
scope: this.scope
}
LzJavaRPCService.loadObject(this._loadDel, opts, this.secure, this.secureport);
</method>
<method name="unload">
if (! _isScopeOk(this.scope)) {
var errmsg = this.scope + ": bad scope";
if (this.onerror) {
this.onerror.sendEvent(errmsg);
}
Debug.write("javarpc ERROR:" + errmsg);
return;
}
if (this.scope == 'none') {
var errmsg = "cannot remove object with scope " + this.scope;
if (this.onerror) {
this.oneprror.sendEvent(errmsg);
}
Debug.write("javarpc:" + errmsg);
return;
}
LzJavaRPCService.unloadObject(this._unloadDel,
{
classname: this.remoteclassname,
oname: this.attributename,
scope: this.scope
},
this.secure, this.secureport);
</method>
<method name="_isScopeOk" args="scope">
return (scope == 'session' || scope == 'webapp' || scope == 'none');
</method>
<method name="_isLoadOptionOk" args="lo">
return (lo == 'loadcreate' || lo == 'loadonly' || lo == 'create');
</method>
<method name="init">
if (null == this.name && null == this.attributename &&
('session' == this.scope || 'webapp' == this.scope)) {
Debug.write("ERROR: name or attributename not set for " +
this.scope + " scoped javarpc.")
return;
}
this._removeDel = new LzDelegate(this , "_remove");
super.init();
</method>
<method name="makeProxyStubFunction" args="fn">
var stubinfo = this.proxyinfo[fn];
//classname: 'org.openlaszlo.test.xmlrpc.SystemProp'
//methodname: 'org.openlaszlo.test.xmlrpc.SystemProp.getProperties'
//op: 'invoke'
var CLASSNAME = stubinfo['classname'];
var METHODNAME = stubinfo['methodname'];
var DOREQ = stubinfo['doreq'] ? stubinfo['doreq'] : false;
var DORES = stubinfo['dores'] ? stubinfo['dores'] : false;
var stubfunc = function (){
var args = arguments.callee.args;
return LzJavaRPCService.invoke(
arguments[1],
arguments[0],
{op: 'invoke',
objectreturntype: args.objectreturntype,
oname: args.attributename,
scope: args.scope ,
classname: CLASSNAME,
methodname: METHODNAME,
doreq: DOREQ,
dores: DORES}, args.secure, args.secureport);
}
return stubfunc;
</method>
<method name="_setup" args="o">
var ok = super._setup(o);
for (var k in this.proxy) {
var tpka = this.proxy[k]['args'];
if (tpka == null) {
tpka = this.proxy[k].args = {};
}
tpka.secure = this.secure;
tpka.secureport = this.secureport;
tpka.scope = this.scope;
tpka.attributename = this.attributename;
tpka.objectreturntype = this.objectreturntype;
}
return ok;
</method>
<method name="_remove" args="o">
if (o.status == "error" && this['onerror']) {
this.onerror.sendEvent(o.message);
return;
}
this.setAttribute("proxy", null);
if (this.onremove) this.onremove.sendEvent();
</method>
<doc>
<tag name="shortdesc"><text>java remote procedure call</text></tag>
<text>
<p>JavaRPC is a feature that allows server-side Java objects and methods
to be accessed from a client application. JavaRPC is part of the Laszlo
RPC family and shares similar APIs with SOAP and XML-RPC. See the
<a href="../developers/rpc.html">RPC</a> and <a href="../developers/rpc-xmlrpc.html">
XML RPC</a> chapters of the Developer's Guide
for more information.</p>
<p>This tag causes the creation of a JavaRPC object. The <literal>remoteclassname</literal> attribute
specifies what class javarpc represents. To use a class, place it in
<literal>WEB-INF/classes</literal> or, if it exists in a jar, in <literal>WEB-INF lib</literal>. This will ensure
that the class is accessible to the OpenLaszlo Server.</p>
<p>Java classes used in an application must be declared in a security element.
Classes not defined in a security element are not allowed to be accessed or
instantiated. The format of the security element looks like this:</p>
<programlisting>
<security>
<allow>
<pattern>CLASS1</pattern>
<pattern>CLASS2</pattern>
...
<pattern>CLASSN</pattern>
</allow>
</security>
</programlisting>
<p>Each <pattern> is a regular expression.</p>
<programlisting>
<security>
<allow>
<pattern>^org\.openlaszlo</pattern>
</allow>
</security>
</programlisting>
<p>This example demonstrates how to call methods in a java object that exists remotely in the server:</p>
<example>
<canvas debug="true" height="300" width="800">
<debug x="250" y="10" width="500" height="275" />
<security>
<allow>
<pattern>^examples\.TypesExample</pattern>
</allow>
</security>
<!-- See WEB-INF/classes/TypesExample.java for java source. -->
<javarpc name="types_example_rpc" scope="none"
remoteclassname="examples.TypesExample">
<handler name="onload">
// Set buttons visible only after JavaRPC object loads
canvas.buttons.setAttribute('visible', true);
</handler>
<handler name="ondata" args="res">
Debug.debug('(types ondata) response is: %w', res);
</handler>
<handler name="onerror" args="errmsg">
Debug.debug('(types onerror) error: %w', errmsg);
</handler>
<!-- Declaratively pass an integer. -->
<remotecall funcname="passInteger">
<param value="42" />
</remotecall>
<!-- Declaratively pass a double. Note that we name this function pd1
because we have multiple remotecall declarations that call
passDouble but with different parameters. -->
<remotecall name="pd1" funcname="passDouble">
<param value="42.1" />
</remotecall>
<!-- Declaratively pass a double with 0 decimal. The 0 decimal will
truncate and the number will become an integer type when it reaches
the server. This call will fail. -->
<remotecall name="pd2" funcname="passDouble">
<param value="42.0" />
</remotecall>
<!-- Declaratively pass a double with 0 decimal. Wrapping the double in
DoubleWrapper will ensure the value will remain a double when
reaching the server. -->
<remotecall name="pd3" funcname="passDouble">
<param>
<method name="getValue">
return new LzRPCDoubleWrapper(42.0);
</method>
</param>
</remotecall>
</javarpc>
<view name="buttons" visible="false" layout="spacing: 10" >
<button text="pass integer"
onclick="types_example_rpc.passInteger.invoke()" />
<button text="pass double"
onclick="types_example_rpc.pd1.invoke()" />
<button text="pass double (will fail)"
onclick="types_example_rpc.pd2.invoke()" />
<button text="pass double w/LzRPCDoubleWrapper"
onclick="types_example_rpc.pd3.invoke()" />
<button text="pass boolean" onclick="this.passBoolean.invoke()">
<!-- This is a way to declare a remotecall closer to where it's being
used. The remotecontext must be set. -->
<remotecall funcname="passBoolean"
remotecontext="$once{ types_example_rpc }">
<param value="true" />
</remotecall>
</button>
<button text="pass array" onclick="this.passArray.invoke()">
<remotecall name="passArray" funcname="passClientArray"
remotecontext="$once{ types_example_rpc }">
<param value="[1, 'a string', 4.5, false]" />
</remotecall>
</button>
<button text="pass hash" onclick="this.passObject.invoke()">
<remotecall name="passObject" funcname="passClientObject"
remotecontext="$once{ types_example_rpc }">
<param value="{ a: 1, b: 3.14159, c: 'a string value', d: true}">
</param>
</remotecall>
</button>
</view>
</canvas>
</example>
<p>The java source code, which can be found in $LPS_HOME/WEB-INF/classes/examples, looks like:</p>
<programlisting>
package examples;
import java.util.Vector;
import java.util.Hashtable;
public class TypesExample {
public static String passInteger(int i) {
return "got integer parameter: " + i;
}
public static String passDouble(double d) {
return "got double parameter: " + d;
}
public static String passBoolean(boolean b) {
return "got boolean parameter: " + b;
}
public static String passClientArray(Vector v) {
return "got vector parameter: " + v;
}
public static String passClientObject(Hashtable t) {
return "got hashtable parameter: " + t;
}
}
</programlisting>
<table border="1">
<tr>
<th rowspan="1" colspan="1">JavaScript data type</th><th rowspan="1" colspan="1">Parameter types expected by java method</th>
</tr>
<tr>
<td rowspan="1" colspan="1">Number (int)</td><td rowspan="1" colspan="1">int</td>
</tr>
<tr>
<td rowspan="1" colspan="1">Number (double)*</td><td rowspan="1" colspan="1">double</td>
</tr>
<tr>
<td rowspan="1" colspan="1">LzRPCDoubleWrapper</td><td rowspan="1" colspan="1">double</td>
</tr>
<tr>
<td rowspan="1" colspan="1">Boolean</td><td rowspan="1" colspan="1">boolean</td>
</tr>
<tr>
<td rowspan="1" colspan="1">Array</td><td rowspan="1" colspan="1">Vector</td>
</tr>
<tr>
<td rowspan="1" colspan="1">Object</td><td rowspan="1" colspan="1">Hashtable</td>
</tr>
</table>
<p>* Any floating point number with a zero decimal value is considered to be an
integer, i.e., 1.0 is really 1. Use LzRPCDoubleWrapper to ensure a number is
considered a double. For example:</p>
<programlisting>
// assume myrpc is a javarpc object and myrpc.proxy.myMethod is a function
// that expects a single double as a parameter
var mydouble = new LzRPCDoubleWrapper(1.0);
myrpc.proxy.myMethod([ mydouble ], new LzDelegate(...));
</programlisting>
<para>
See Also:
<itemizedlist>
<listitem><sgmltag class="element" role="lz.rpc"><rpc></sgmltag></listitem>
<listitem><sgmltag class="element" role="lz.sessionrpc"><sessionrpc></sgmltag></listitem>
<listitem><sgmltag class="element" role="lz.webapprpc"><webapprpc></sgmltag></listitem>
<listitem><sgmltag class="element" role="lz.soap"><soap></sgmltag></listitem>
<listitem><sgmltag class="element" role="lz.xmlrpc"><xmlrpc></sgmltag></listitem>
<listitem><sgmltag class="element" role="lz.remotecall"><remotecall></sgmltag></listitem>
<listitem><sgmltag class="element" role="tag.security"><security></sgmltag></listitem>
<listitem><link linkend="rpc">Developer's Guide: RPC chapter</link></listitem>
<listitem><link linkend="rpc-javarpc">Developer's Guide: JavaRPC chapter</link></listitem>
</itemizedlist>
</para>
</text>
</doc>
</class>
</library>
Cross References
Includes
Classes
- <class name="javarpc" extends="rpc">