The NetRexx Tutorial
- Advanced Networking
NetRexx Tutorial - Advanced Networking


Advanced Networking

In this chapter we will analyse some of the most recent goodies available in JDK 1.1, and consequently in NetRexx.

In this chapter we will analyse:

Basic Concepts

Remote Method Invocation

The RMI (Remote Method Invocation) is a technique by which an object on SYSTEM A can call a method in an object on SYSTEM B, located somewhere else in the network.

All the sending of parameters, and retrieving of the result will happen in a transparent way, so that the user (and, before him, the application developper) has the feeling that the method was called locally (like any other method we saw so far).

So far we saw how the methods are pieces of code run locally by an object:

 
   MACHINE A
   ---------

   object OBJ

     method METHOD
       (...)

       code for METHOD  <--- runs
                             locally

       (...)                 

 

Using RMI we move code for METHOD to be remote.

 
   MACHINE A                 MACHINE B
   ---------                 ---------

   object OBJ

     method METHOD             method METHOD
       (...)
                   ========>
                                 code for METHOD  <--- runs
                                                       remote
                   <=======
       (...)                                           

 

This "extention" of the method across the Network is done using sockets; but all the programming details are hidden to the programmer, who just have to realize that, being the call remote, the chances that "something-goes-wrong" are bigger, so he MUST be more carefull for error handling.

The Client/Server Model

The following picture might help understanding the Client/Server in the RMI implementation.

 

+-----------------------+             +------------------------+
| CLIENT    rmicl.nrx   |             | SERVER   rmise.nrx     |
|                       |             |                        |
| a = obj.method()   +-------+    +-----+                      |
|                    |rem obj|    |     |                      |
|                    | method|===>|     |    +---------------+ |
|                    |       | S  |     |    | actual OBJ    | |
|                    |       | O  |     |===>|   method      | |
|                   S|       | C  |     |<===|     return    | |
|                   T|       | K  |     |    +---------------+ |
|      return       U| return|<===|     |S                     |
|                   B|       | E  |     |T                     |
|                    +-------+ T  +-----+U                     |
|                       |      S      |  B                     |
+-----------------------+             +------------------------+

 

As you see, the REAL object exists on the SERVER; from the SERVER's point of view, the object IS the SERVER.

First example: a time RMI.

This is probably the simplest code you can try, in order to implement an application using the Remote Method Invocation.

We'll write a program to grab the time information from another machine (even if, for practical purposes, the example will run Client and Server on the same machine).

Define the remote interface

 
+----------------------------------------------------------------------+
| class Time public implements java.rmi.Remote interface               |01
|                                                                      |02
|   method sayTime() returns String signals java.rmi.RemoteException   |03
+----------------------------------------------------------------------+
                                                                Time.nrx
Download the source for the Time.nrx example

Write the Implementation Class

 
+----------------------------------------------------------------------+
| import java.rmi.                                                     |01
| import java.rmi.server.UnicastRemoteObject                           |02
|                                                                      |03
| class TimeImpl public extends UnicastRemoteObject implements Time    |04
|                                                                      |05
|   properties private                                                 |06
|     myname                                                           |07
|                                                                      |08
|   method TimeImpl(s=String) signals RemoteException                  |09
|     super();                                                         |10
|     myname = s;                                                      |11
|                                                                      |12
|   method sayTime() returns String                                    |13
|     return 'Hello from' myname 'at' xsys.time('N')                   |14
|                                                                      |15
|   method main(a=String[]) public static                              |16
|                                                                      |17
|     -- Create and install a security manager                         |18
|     System.setSecurityManager(RMISecurityManager());                 |19
|                                                                      |20
|     do                                                               |21
|       obj = TimeImpl("TimeServer");                                  |22
|       Naming.rebind("//pcl307/TimeServer", obj);                     |23
|       say "TimeServer bound in registry";                            |24
|     catch e=Exception                                                |25
|       say "TimeImpl err: " + e.getMessage();                         |26
|     end                                                              |27
|                                                                      |28
+----------------------------------------------------------------------+
                                                            TimeImpl.nrx
Download the source for the TimeImpl.nrx example

Write an application that uses the Remote Service

 
+----------------------------------------------------------------------+
| import java.rmi.         -- MUST be here!                            |01
|                                                                      |02
| class TimeCl public                                                  |03
|                                                                      |04
|   method main(arg=String[]) public static                            |05
|     arg = arg      -- keep NR silent                                 |06
|                                                                      |07
|     do                                                               |08
|       obj = Time Naming.lookup("//pcl307/TimeServer")                |09
|       message = obj.sayTime();                                       |10
|     catch e=Exception                                                |11
|        say "TimeCl exception:" e.getMessage()                        |12
|     end                                                              |13
|     say  message                                                     |14
|     exit                                                             |15
+----------------------------------------------------------------------+
                                                              TimeCl.nrx
Download the source for the TimeCl.nrx example

Putting all those pieces together

Provided you have the three above .nrx files stored in the same directory, in order to run the example, you have to issue the following commands, in your shell

 
.............................................................
  -- 1. edit the sources and change "pcl307" to your
  --    node name

> edit TimeCl.nrx
> edit TimeImpl.nrx

  -- 2. Compile the 3 programs
  --

> java COM.ibm.netrexx.process.NetRexxC Time.nrx
> java COM.ibm.netrexx.process.NetRexxC TimeCl.nrx
> java COM.ibm.netrexx.process.NetRexxC TimeImpl.nrx

  -- 3. Generate the stubs
  --

> rmic TimeImpl

  -- 4. Start the registry
  --         (WNT;W95)  start rmiregistry
  --         (ditto)    javaw rmiregistry
  --         (UNIX)     rmiregistry &

> start rmiregistry

  -- 5. Start the Server part
  --

> java TimeImpl

  -- 6. On another window, you can run the
  --    client

> java TimeCl
.............................................................

First real example: a remote controlled VOLTAGE controller

What we saw so far might appear a little "too much" for such a simple application. In fact, it is.

In the following example we use what we have learnt to build an application where objects last LONGER than the lifetime of the client application.

The code for Interface, Server and Client

 
+----------------------------------------------------------------------+
| class volt public implements java.rmi.Remote interface               |01
|                                                                      |02
|   method get(ch=int) returns int signals java.rmi.RemoteException    |03
|   method set(ch=int,value=int) signals java.rmi.RemoteException      |04
+----------------------------------------------------------------------+
                                                                volt.nrx
Download the source for the volt.nrx example

 
+----------------------------------------------------------------------+
| -- voltimpl.nrx                                                      |01
| -- voltage controller implementation                                 |02
| --                                                                   |03
|                                                                      |04
| import java.rmi.                                                     |05
| import java.rmi.server.UnicastRemoteObject                           |06
|                                                                      |07
| class voltimpl public extends UnicastRemoteObject implements volt    |08
|                                                                      |09
|   properties private                                                 |10
|     myname                                                           |11
|     channel = int[100]                                               |12
|                                                                      |13
|   method voltimpl(s=String) signals RemoteException                  |14
|     super();                                                         |15
|     myname = s;                                                      |16
|                                                                      |17
|   -- set a channel                                                   |18
|   method set(ch=int,value=int)                                       |19
|     say myname 'channel:' ch 'set to:' value                         |20
|     channel[ch] = value                                              |21
|                                                                      |22
|   -- fetch a value                                                   |23
|   method get(ch=int) returns int                                     |24
|     return channel[ch]                                               |25
|                                                                      |26
|   -- main method                                                     |27
|   method main(a=String[]) public static                              |28
|                                                                      |29
|     -- Create and install a security manager                         |30
|     System.setSecurityManager(RMISecurityManager());                 |31
|                                                                      |32
|     do                                                               |33
|       obj = voltimpl("voltageserver");                               |34
|       Naming.rebind("//pcl307/voltageserver", obj);                  |35
|       say "voltageserver bound in registry";                         |36
|     catch e=Exception                                                |37
|       say "voltimpl err: " + e.getMessage();                         |38
|     end                                                              |39
|                                                                      |40
+----------------------------------------------------------------------+
                                                            voltimpl.nrx
Download the source for the voltimpl.nrx example

 
+----------------------------------------------------------------------+
| -- voltcl.nrx                                                        |01
| -- client example                                                    |02
| --                                                                   |03
| import java.rmi.         -- MUST be here!                            |04
|                                                                      |05
| class voltcl public                                                  |06
|                                                                      |07
|   method main(args=String[]) public static                           |08
|     arg = rexx(args)                                                 |09
|     parse arg act ch val   -- get args                               |10
|     act = act.upper()      -- upperacase the action                  |11
|                                                                      |12
|     do                                                               |13
|       -- get the remote object                                       |14
|       obj = volt Naming.lookup("//pcl307/voltageserver")             |15
|                                                                      |16
|       -- do the job                                                  |17
|       if act = 'SET' then  -- set a channel                          |18
|         do                                                           |19
|           obj.set(ch,val)                                            |20
|           n = obj.get(ch)                                            |21
|         end                                                          |22
|       if act = 'GET' then  -- get a channel                          |23
|         do                                                           |24
|           n = obj.get(ch)                                            |25
|         end                                                          |26
|     catch e=Exception                                                |27
|        say "voltcl exception:" e.getMessage()                        |28
|     end                                                              |29
|     say 'Channel' ch 'value:' n'.'                                   |30
|     exit 0                                                           |31
+----------------------------------------------------------------------+
                                                              voltcl.nrx
Download the source for the voltcl.nrx example

Build it

We saw already how to build an RMI application, so I just show again the commands.

 
.............................................................
> edit voltcl.nrx
> edit voltimpl.nrx
> java COM.ibm.netrexx.process.NetRexxC volt.nrx
> java COM.ibm.netrexx.process.NetRexxC voltCl.nrx
> java COM.ibm.netrexx.process.NetRexxC voltimpl.nrx
> rmic voltimpl
> start rmiregistry
> java voltimpl
> java voltcl set 2 33
> java voltcl get 2
  33         <===  This is MAGIC!
.............................................................

Remote File Access

Let's now analyse a real case study. We want to implement some (tough primitive) file access method. Our client application will then be capable to access a Server's file just like if the file was local.

The files

For this project we again need 4 files, which are:

 
 rfile.nrx         - the Interface
 rfileimpl.nrx     - the Implementation
 rfileserv.nrx     - the Server's part
 rfileclie.nrx     - the Client's part
 

Interface

 
+----------------------------------------------------------------------+
| -- rfile.nrx                                                         |01
| --    Remote File Access                                             |02
| --    Interface part                                                 |03
| --                                                                   |04
|                                                                      |05
| class rfile public implements java.rmi.Remote interface              |06
|   method setfilename(s=String) signals java.rmi.RemoteException      |07
|   method exists() returns int signals java.rmi.RemoteException       |08
|   method list() returns String[] signals java.rmi.RemoteException    |09
|   method cat() returns String[] signals java.rmi.RemoteException     |10
+----------------------------------------------------------------------+
                                                               rfile.nrx
Download the source for the rfile.nrx example

Implementation

 
+----------------------------------------------------------------------+
| -- rfileimpl.nrx                                                     |01
| --   Remote File Access                                              |02
| --   Implementation part                                             |03
| --                                                                   |04
|                                                                      |05
| import java.rmi.                                                     |06
| import java.rmi.server.UnicastRemoteObject                           |07
|                                                                      |08
| class rfileimpl public extends UnicastRemoteObject implements rfile  |09
|                                                                      |10
|   --                                                                 |11
|   properties private                                                 |12
|     myname                                                           |13
|     fid = File                                                       |14
|     fname                                                            |15
|                                                                      |16
|   -- constructor                                                     |17
|   method rfileimpl(s=String) signals RemoteException                 |18
|     super();                                                         |19
|     myname = s;                                                      |20
|                                                                      |21
|   -- set the filename                                                |22
|   method setfilename(fn=String)                                      |23
|     say myname 'selects' fn                                          |24
|     fname = fn                                                       |25
|     fid = File(fn)                                                   |26
|                                                                      |27
|   -- check if file exists                                            |28
|   method exists() returns int                                        |29
|     return fid.exists()                                              |30
|                                                                      |31
|   -- list a directory                                                |32
|   method list() returns String[]                                     |33
|     return fid.list()                                                |34
|                                                                      |35
|   -- cat a file                                                      |36
|   method cat() returns String[]                                      |37
|     d = xfile(fname)        -- use xfile                             |38
|     rc = d.read()           --                                       |39
|     say '(cat) File "'fname'" read rc:' rc'.'                        |40
|                                                                      |41
|     -- I need this till I cannot return REXX                         |42
|     nl = d.lines                                                     |43
|     s = String[nl]                                                   |44
|     loop i = 1 to d.line[0]                                          |45
|       s[i-1] = d.line[i]                                             |46
|     end                                                              |47
|     return s                                                         |48
+----------------------------------------------------------------------+
                                                           rfileimpl.nrx
Download the source for the rfileimpl.nrx example

Server

 
+----------------------------------------------------------------------+
| -- rfileserv.nrx                                                     |01
| --   Remote File Access                                              |02
| --   Server code                                                     |03
| --                                                                   |04
|                                                                      |05
| import java.rmi.                                                     |06
| import java.rmi.server.UnicastRemoteObject                           |07
|                                                                      |08
| class rfileserv public                                               |09
|                                                                      |10
|   -- main method                                                     |11
|   method main(a=String[]) public static                              |12
|                                                                      |13
|     myname = "remfileaccess"                                         |14
|     mynode = "pcl307"                                                |15
|                                                                      |16
|     -- Create and install a security manager                         |17
|     System.setSecurityManager(RMISecurityManager());                 |18
|                                                                      |19
|     do                                                               |20
|       obj = rfileimpl(myname);                                       |21
|       Naming.rebind('//'mynode'/'myname, obj);                       |22
|       say 'Bind of' myname 'OK.'                                     |23
|       say 'Node is' mynode '.'                                       |24
|       say 'SERVER now ready for connections.'                        |25
|       say 'HIT CNTRL-C to ABORT'                                     |26
|     catch e=Exception                                                |27
|       say 'rfileserv error:' + e.getMessage();                       |28
|     end                                                              |29
|                                                                      |30
+----------------------------------------------------------------------+
                                                           rfileserv.nrx
Download the source for the rfileserv.nrx example

Client

 
+----------------------------------------------------------------------+
| -- rfileclie.nrx                                                     |01
| --   Remote file Access                                              |02
| --   Client part                                                     |03
| --                                                                   |04
| import java.rmi.         -- MUST be here!                            |05
|                                                                      |06
| class rfileclie public                                               |07
|                                                                      |08
|   properties public static                                           |09
|     fn                                                               |10
|                                                                      |11
|   method help() public static                                        |12
|     say 'implemented commands are:'                                  |13
|     say 'java rfileclie ls <FILE>'                                   |14
|     say '               state <FILE>'                                |15
|     say '               cat <FILE>'                                  |16
|     exit 6                                                           |17
|                                                                      |18
|   method ls(fid=rfile) public static                                 |19
|     if fid.exists() = 0 then                                         |20
|       do                                                             |21
|         say 'Sorry: remote file "'fn'" does not exist.'              |22
|         exit 1                                                       |23
|       end                                                            |24
|     dd = String[]                                                    |25
|     dd = fid.list()                                                  |26
|     loop i = 0 to dd.length - 1                                      |27
|       say dd[i]                                                      |28
|     end                                                              |29
|                                                                      |30
|   method cat(fid=rfile) public static                                |31
|     if fid.exists() = 0 then                                         |32
|       do                                                             |33
|         say 'Sorry: remote file "'fn'" does not exist.'              |34
|         exit 1                                                       |35
|       end                                                            |36
|     dd = String[]                                                    |37
|     dd = fid.cat()                                                   |38
|     loop i = 0 to dd.length - 1                                      |39
|       say dd[i]                                                      |40
|     end                                                              |41
|                                                                      |42
|                                                                      |43
|   method main(args=String[]) public static                           |44
|     arg = rexx(args)                                                 |45
|     parse arg cmd fn                                                 |46
|                                                                      |47
|     if cmd = 'help' then                                             |48
|       do                                                             |49
|         help()                                                       |50
|       end                                                            |51
|     do                                                               |52
|       -- get the remote object                                       |53
|       fid = rfile Naming.lookup("//pcl307/remfileaccess")            |54
|                                                                      |55
|       -- do the job                                                  |56
|       if fn = '' then fn = '.'                                       |57
|       fid.setfilename(fn)                                            |58
|       select                                                         |59
|         when cmd = 'ls' then ls(fid)                                 |60
|         when cmd = 'cat' then cat(fid)                               |61
|         otherwise say 'Unimplemented command.'                       |62
|       end                                                            |63
|     catch e=Exception                                                |64
|        say "rfileclie exception:" e.getMessage()                     |65
|     end                                                              |66
|     exit 0                                                           |67
+----------------------------------------------------------------------+
                                                           rfileclie.nrx
Download the source for the rfileclie.nrx example

Additional sources of documentation.

RMI is a rather new topic (at least it is in June 1997). You might find some additional information at:

 
http://chatsubo.javasoft.com/current/doc/tutorial/getstart.doc.html
http://www.widget.com/ggainey/java/rmi_talk/rmi_talk.html
 

Problems and limitations

Stubs not updated.

If you forget to update the stubs, since you forgot to run "rmic IMPLEMENTATION_FILE", you get a message like:

 
java.lang.IllegalAccessError: unimplemented interface method
  at ...
  (... follows tracedump ...)
  ...
 

You should then run rmic IMPLEMENTATION_FILE to have the correct interface.

rmiregistry problem

You might get an error like:

 
java.lang.NumberFormatException: SERVER error
  at (TRACE)
 

You usually clear it stopping and restarting the rmiregistry program.

Method returning REXX variable

There are currently problems if the method returns a REXX type. The message you get is something like:

 
client exception:
  Error unmarshaling return
  nested exception is:
  java.io.NotSerializableException: netrexx.lang.Rexx
 
 
 *** This section is: 
  
 *** and will be available in next releases


File: nr_23.html.

The contents of this WEB page are Copyright © 1997 by Pierantonio Marchesini / ETH Zurich.

Last update was done on 18 May 1998 21:47:59(GMT +2).