The RemoteObject is a very simple concept - it is
a remote procedure call allows you to invoke methods of java classes saved
on the server. RemoteObject is a 100% java implementation and works on
the top of HTTP, so this package is free from firewall restrictions.
So your classes are locating on the server and methods
will be running also on the server. Your clients part just passes parameters
and obtains result. And all this is implemented on the top of HTTP. It
means for example you can use this from applets. You can use this approach
for example for sending mail (your applet can not open sockets, but server
based class can do that), for JDBC connections etc. The size of clients
stuff is less than 10Kb.
The package itself contains two parts:
java classes for clients interface
servlet (analogue of RMI's registery) for server.
The servlet ROServlet.class can be used with any servletrunner.
Example
Let we see some example:
import java.io.*;
// clients class
import RemoteObject;
class TestRemote
{
public static void main(String argv[])
{
/** create proxy
** the name of the object is A.
** We assume that under this name we have
some object instance for the class located on our server
** the reference for the host is a reference for
our servlet
**/
RemoteObject ro=new RemoteObject("http://your_host_here/servlet/ROServlet/","A")
/* set method
* int myMethod(String title, int num)
*/
ro.setMethod("myMethod");
/*
* set params
*/
ro.addParam("title","java.lang.String","Sum is: ");
ro.addParamAsInt("num",3);
/*
* invoke it
*/
int i=ro.invoke();
/*
* print out result (error) code
*/
System.out.println("result code="+i);
/*
* get result of calculation and print it
*/
Integer res=(Integer)ro.getResult();
System.out.println(res==null?"null":"res="+res.intValue());
/*
* check parameter value
*/
System.out.println("title="+(String)ro.getParam("title"));
}
}
The value returned by the underlying method is automatically wrapped in an object if it has a primitive type. In case your returned values or parameters are Objects, they should be Serializable.
Objects.
Objects can be created during the servlet loading in the servlet's init()
method. You can preload servlet and create all objects (object instances)
before any using or they can be created during the first call to this servlet.
You can also create/delete objects in runtime through Adminstrator's
console
And objects also can be created in runtime through API calls.
For objects preloading your servlet should have intial parameter with the name load. In this parameter you must set text file (e.g. absolute path) contains objects description. It is just a text file, each line describes one element in the form of:
object_name=class_name(list_of_parameters)
Empty lines, lines starts with # or // are ignoring. List_of_parameters
can be empty (constructor without parameters).
E.g. for example above we can have in this file some like that:
# first instance of class A
A=A();
# second instance of class A
B=A(2,"my class on server")
You can save that in any text file and for ROServlet you can set some like that in properties file :
# ROServlet (it is for JSDK, your file is /home/usr/init.txt)
servlet.ROServlet.code=ROServlet
servlet.ROServlet.initArgs=load=/home/user/init.txt
See manual for your servletrunner how to set initial parameters for servlet.
So for the each line in your initial script will be created new object instance. ROServlet will use appropriate class constructor and save this instance under the given name.
There is no special requirements for server object. You do not need extends some Remote Interfaces, making them serializable etc.
This servlet has got own class loader. So you can set the initial directory
for your classes and in that case you will always load the latest version
of your classes (you do not need restart your servlet). The name of this
parameter is classes
E.g.:
# ROServlet (it is for JSDK, your file is /home/usr/init.txt)
servlet.ROServlet.code=ROServlet
servlet.ROServlet.initArgs=load=/home/user/init.txt,classes=/home/your_dir_for_class_files
In case servlet can not find class in this directory class will be loaded through the system classloader (it means looking CLASSPATH).
Parameters parsing for constructors
In all cases when we are looking class constructor or class method we
need to make some conclusion about
parameter types.
If the current parameter represents integer we assume this type is
int
If the current parameter represents float we assume this type is float.
If the current parameter is true or false we assume this
type in boolean
In all another cases we assume this type is String.
For example:
// we assume A(int,float,String,boolean)
A_OBJECT=A(2,5.6,a123,true)
If some string value is enclosed into ", it will be passed to java without
that.
E.g.
# parameter type is a String and value is a 222 , not a "222"
YetAnotherObject=myPackage.myClass("222")
Schema.
The common schema is:
1) create proxy
2) set method
3) set type/value
for parameters (or skip that if your method has no parameters)
4) invoke method
5) check error code
6) get result value (is
null if your method has got type void)
7) read new values for parameters
of non-primitive type (primitive type parameters
are passing by value and
not changed any way).
Client's interface is described below:
At the first hand you can create proxy, set method (function name),use methods like addParameterXXX() where XXX is some type and invoke it.
// create proxy for existing object instance
public RemoteObject(String your_host, String object_name)
host name is URL for ROServlet
// create new object instance and proxy
public RemoteObject(String your_host, String object_name,String
class_name,String parameters_list)
you can pass null or empty string as a parameters_list if you need to call constructor without parameters. Otherwise it is a list of actual parameters values, splited by commas. See description above about parameters parsing.
// set method name
public void setMethod(String method_name)
/*
* add parameters type/value
* splited by parameter types
*/
// common form
public void addParam(String param_name, String type_name, Object
val)
// type is Object
public void addParamAsObject(String param_name, Object val)
// type is byte
public void addParamAsByte(String param_name, byte val)
// type is short
public void addParamAsShort(String param_name, short val)
// type is int
public void addParamAsInt(String param_name, int val)
// type is long
public void addParamAsLong(String param_name, long val)
// type is float
public void addParamAsFloat(String param_name, float val)
// type is double
public void addParamAsDouble(String param_name, double val)
// type is char
public void addParamAsChar(String param_name, char val)
// type is boolean
public void addParamAsBoolean(String param_name, boolean val)
// set parameter by number (starting from 1)
public void setParam(int param_number, String param_type, Object
param_value)
/*
* get parameters
*/
// get parameter by name
value public Object getParam(String param_name)
// get parameter by number
value public Object getParam(int param_number)
// invoke method
public long invoke(int mode)
Result codes are:
OK=0
NO_OBJECT=1
NO_METHOD=2
CANNOT_RUN=3
Modes are:
NORMAL=0
ONEWAY=1
DEFERRED=2
NORMAL mode - call method, wait results
ONEWAY mode - just call method and return
DEFERRED mode - allows you to call method and poll results later
in the last case you can poll resuts later:
ro=new RemoteObject(...);
ro.setMethod(...);
long res=ro.invoke(ro.DEFERRED);
... / / continue to execute
Poll p=ro.poll(res,true);
if (p!==null)
{
// check results
}
method invoke(DEFERRED) can return NO_OBJECT, NO_METHOD, CANNOT_RUN or some long Id which can be used for obtainig results.
// obtain results for DEFERRED invocation
// the second parameter allows you to keep results saved on the
server (true) or delete them (false)
// returns new object of class Poll or null if execution not yet
completed
// Saving results means keep them ready for another Poll requests.
Poll poll(long Id, boolean keep)
// get result of invocation
public Object getResult()
// clear parameters list
public void clearParams()
Class Poll
// check method execution.
true - method has been completed,
false - some exception has been generated
public boolean finished()
// get method results
public Object getResult()
// get parameter value (starting from 1)
public Object getParameter(int num)
Remark: we are using parameter names in addParamAs... only
for the keeping your source code more readable. Actual parameters will
be passed to the method in the same order as they were added by addParamAs...
Administrator's console
You can run the same servlet directly from the browser and create/delete objects. The appropriate command is:
http://your_host/servlet/ROSerler?your_password
You can set this password as an initial parameter for servlet. The name of this paramater is admin. E.g.:
# ROServlet (it is for JSDK, your script file is /home/usr/init.txt)
servlet.ROServlet.code=ROServlet
servlet.ROServlet.initArgs=load=/home/user/init.txt,admin=secret_word
By default this parameter is welcome, so ROServlet?welcome should run administrator's page.
Through this page you can delete objects and create new objects. For
doing last action just set object name, class name and parameters string
(if you need to run non-default constructor).
What is new in 2.32:
- performance issue
- some bugs fixed
What is new in 2.31:
- some bugs fixed
What is new in 2.3:
- new API calls
- workarounds for JServ bugs
What is new in 2.2:
- own class loader
- some bugs fixed
What is new in 2.1:
- administrative console
What is new in 2.0:
- new schema
- new API calls
What is new in 1.13:
- new invocation modes
What is new in 1.12:
- new API calls
What is new in 1.11:
- new API calls
- some bugs fixed
For downloading:
clients part: RemoteObject.jar
server part: ROServlet.class
Kernel.jar
for testing: A.java TestRemote.java