javarpc.lzx

<library>
    
    <include href="rpc/rpc.lzx"/>
    <include href="rpc/library/javarpc.js"/>

    <class name="javarpc" extends="rpc">

        <!--- One of 'session', 'webapp', or 'none' to set the scope of the
              remote object. This attribute must be set before creating or
              loading the object. If scope is 'session' or 'webapp', name or
              attributename must be set. -->
        <attribute name="scope" type="string"/>

        <!--- Attribute name of server remote object. Name or attributename must
              be set when scope is 'session' and 'webapp'. Default is the name
              of this object. -->
        <attribute name="attributename" value="$once{this.name}" type="string"/>

        <!--- The remote class name associated with the remote object. This must
              be set if creating the remote object. If loading the object, the
              classname will be set during onload. -->
       <attribute name="remoteclassname" type="string"/>

        <!--- One of 'loadcreate', 'loadonly', or 'create'. 'Loadcreate' tries
              to load javarpc object if it exists in the server, else it creates
              it before loading. 'Loadonly' will only load object if it exists,
              else an error is returned. 'Create' will always create the object
              in the server. Default is 'loadcreate'. -->
        <attribute name="loadoption" value="loadcreate" type="string"/>

        <!--- Used if loadoption='loadcreate' or loadoption='create'. Arguments
              to construct remote object with. The value passed in must be an
              array, e.g., [1, 'mystring', 1.45]. Default is null. -->
        <attribute name="createargs" value="null" type="expression"/>

        <!--- Used to determine what server-side object member values are
              returned to the client. One of 'pojo' (returns public member
              values) or 'javabean' (returns members that have associated
              getters). Default is 'pojo' (plain old java object). -->
        <attribute name="objectreturntype" value="pojo" type="string"/>

        <!--=================================================================-->
        <!-- public methods                                                  -->
        <!--=================================================================-->

        <!--- Load the object. If successful, this.proxy is set to an object
              with remote APIs. -->
        <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>


        <!--- Unload the remote object. On, this.proxy is set to null. -->
        <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>


        <!--=================================================================-->
        <!-- private methods                                                 -->
        <!--=================================================================-->

        <!--- @keywords private -->
        <method name="_isScopeOk" args="scope">
            return (scope == 'session' || scope == 'webapp' || scope == 'none');
        </method>

        <!--- @keywords private -->
        <method name="_isLoadOptionOk" args="lo">
            return (lo == 'loadcreate' || lo == 'loadonly' || lo == 'create');
        </method>

        <!--- @keywords private -->
        <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>

        <!--- @keywords private -->
        <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>

        <!--- @keywords private -->
        <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>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2009 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
<!-- @LZX_VERSION@                                                         -->

Cross References

Includes

Classes