 |
CS 696 Emerging Technologies: Distributed Objects |
|
|---|
Spring Semester, 1998
RMI Server Methods
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98
Contents of Doc 11, RMI Server Methods
- References
- Server Parent Classes
- java.rmi.server.RemoteObject
- java.rmi.server.RemoteServer
- java.rmi.server.UnicastRemoteObject
- Simple (But Long) Example
- ServerMethods Interface
- Client
- Client Output
- Server
- Command line to Start Server
- Server Output - Screen
- Server Output - log file
- Snooping on RMI Wire
- Logging - A More General System
- Remotes without UnicastRemoteObject
- Echo Example
- Remote Echo Interface
- EchoImpl
- EchoExample: Server Interface
- Server Implementation
- Client
- Output
- Roaming Remotes- Distributed Garbage Collection
Java RMI API
Java Remote Method Invocation Specification
RMI Users Mailing list
Servers typically extend UnicastRemoteObject:
public class HelloServer
extends UnicastRemoteObject
implements Hello
{
}
The class Structure
java.lang.Object
|
+----java.rmi.server.RemoteObject
|
+----java.rmi.server.RemoteServer
|
+----java.rmi.server.UnicastRemoteObject
Implements java.lang.Object behavior for remote objects
Methods
equals(Object proxy)
- Returns true if two java.rmi.Remote objects (or proxies) refer to the same
remote object
hashCode()
- If two proxies that refer to the same remote object are equal, then the
normal way to compute hashCode needs to be modified, Returns a hashcode for a
remote object.
toString()
- Returns a String that represents the value of this remote object,
implementation-specific
public static String getClientHost() throws ServerNotActiveException
- Return the hostname of the current client. When called from a thread
actively handling a remote method invocation the hostname of the client is
returned.
- Throws: ServerNotActiveException
- If called outside of servicing a remote method invocation.
public static void setLog(OutputStream out)
- Log RMI calls to the output stream out. If out is null, call logging is
turned off.
public static PrintStream getLog()
- Returns stream for the RMI call log.
Constructor
UnicastRemoteObject()
- Create and export a new UnicastRemoteObject object using an anonymous port.
Methods
clone()
- Returns a clone of the remote object that is distinct from the original.
exportObject(Remote)
- Export the remote object to make it available to receive incoming calls.
package whitney.rmi.examples.server;
import java.rmi.server.ServerNotActiveException;
public interface ServerMethods extends
java.rmi.Remote
{
public ServerMethods tryMe( int callNumber )
throws java.rmi.RemoteException,
ServerNotActiveException;
}
package whitney.rmi.examples.server;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.net.MalformedURLException;
import java.io.IOException;
import sdsu.util.ProgramProperties;
public class ServerMethodsClient
{
public static void main(String args[])
{
try
{
String serverLabel = ServerMethodsServer.RMI_NAME;
String server = getServerURL( args, serverLabel );
ServerMethods first =
(ServerMethods) Naming.lookup( server );
ServerMethods second =
(ServerMethods) Naming.lookup( server );
ServerMethods third = first.tryMe( 1 );
first.tryMe( 2 );
second.tryMe( 3 );
if ( first == second )
System.out.println( "1 = 2" );
else
System.out.println( "1 != 2" );
if ( first == third )
System.out.println( "1 = 3" );
else
System.out.println( "1 != 3" );
System.out.println( "1 " + first.hashCode() );
System.out.println( "2 " + second.hashCode() );
System.out.println( "3 " + third.hashCode() );
}
catch ( Exception error)
{
error.printStackTrace();
}
}
//CLIENT CONTINUED
private static String getServerURL( String args[], String serverLabel ) throws IOException
{
String hostKey = "h";
String portKey = "p";
ProgramProperties flags = new ProgramProperties( args );
String host = null;
if ( flags.containsKey( hostKey ) )
host = flags.getString( hostKey );
else
{
System.out.println( "Missing flag " + hostKey );
System.exit( 0 );
}
int defaultPort = Registry.REGISTRY_PORT;
int port = flags.getInt( portKey, defaultPort );
return "rmi://" + host + ":" + port + "/" + serverLabel;
}
}
1 != 2
1 != 3
1 0
2 0
3 0
package whitney.rmi.examples.server;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.ServerNotActiveException;
import java.rmi.registry.Registry;
import sdsu.rmi.registry.Registrar;
import sdsu.util.ProgramProperties;
import java.io.*;
public class ServerMethodsServer
extends UnicastRemoteObject
implements ServerMethods
{
public ServerMethodsServer() throws RemoteException, IOException
{
FileOutputStream log = new FileOutputStream( "MyLog");
setLog ( new BufferedOutputStream( log ) );
}
public ServerMethods tryMe( int callNumber )
throws RemoteException, ServerNotActiveException
{
System.out.println( "Call " + callNumber + " from: " +
getClientHost() );
PrintStream logStream = getLog();
if (logStream == null )
System.out.println( "Null logger" );
else
logStream.println( "Call " + callNumber + " from: " +
getClientHost() );
setLog( null ); // turns logging off
logStream = getLog();
if (logStream == null )
{
System.out.println( "Null logger" );
setLog( System.out );
}
else
System.out.println( "You can still log");
return this;
}
// Server Continued
public static String RMI_NAME = "cs696/ServerMethods";
public static void main(String args[]) throws RemoteException, IOException
{
int port = getPort( args );
ServerMethodsServer serverObject = new ServerMethodsServer();
Naming.rebind("//:" + port + "/" + RMI_NAME, serverObject );
System.out.println("ServerMethodsServer bound in registry");
}
private static int getPort( String args[] ) throws IOException
{
ProgramProperties flags = new ProgramProperties( args );
int defaultPort = Registry.REGISTRY_PORT;
int port = flags.getInt( "p", defaultPort );
return port;
}
}
java -Djava.rmi.server.logCalls=true
whitney.rmi.examples.server.ServerMethodsServer -p=7676
Note I am not using the UniVMRegistry
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost:
sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease
dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost:
whitney.rmi.examples.server.ServerMethodsServer[0]:
whitney.rmi.examples.server.ServerMethods tryMe(int)]
Call 1 from: localhost
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:Call 1 from: localhost
Null logger
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost:
whitney.rmi.examples.server.ServerMethodsServer[0]:
whitney.rmi.examples.server.ServerMethods tryMe(int)]
Call 2 from: localhost
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:Call 2 from: localhost
Null logger
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:[localhost:
whitney.rmi.examples.server.ServerMethodsServer[0]:
whitney.rmi.examples.server.ServerMethods tryMe(int)]
Call 3 from: localhost
Sun Feb 15 19:19:14 PST 1998:RMI:TCP Accept-4:Call 3 from: localhost
Null logger
Sun Feb 15 19:17:37 PST 1998:RMI:TCP Accept-1:[localhost:
sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease
dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Sun Feb 15 19:18:38 PST 1998:RMI:TCP Accept-2:[localhost:
sun.rmi.transport.DGCImpl[0:0:0, 2]: java.rmi.dgc.Lease
dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)]
Sun Feb 15 19:18:38 PST 1998:RMI:TCP Accept-2:[localhost:
whitney.rmi.examples.server.ServerMethodsServer[0]:
whitney.rmi.examples.server.ServerMethods tryMe(int)]
Sun Feb 15 19:18:38 PST 1998:RMI:TCP Accept-2:Call 1 from: localhost
Source: Robert Penny [rpenny@gensym.com]
Via: Andres Aguiar <aaguiar@GENEXUS.ES>
Warning: I tried this, got a great crash & core dump
Run rmic with the -keepgenerated option, you can change the .java generated
files for the stub and the skeleton.
In the skeleton, some of the code looks like this:
java.io.ObjectOutput out = call.getResultStream(true);
out.writeObject($result);
you must add :
java.io.ObjectOutputStream log =
new java.io.ObjectOutputStream(
new java.io.FileOutputStream("return.log", true));
log.writeObject($result);
In the stub the code looks like this:
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($_arrayOf__Object_1);
you must add :
java.io.ObjectOutputStream log = new
java.io.ObjectOutputStream(new
java.io.FileOutputStream("call.log", true));
log.writeObject($_arrayOf__Object_1);
That creates a file called "call.log" in the client with the serialized
parameters, and another one, "return.log" in the server with the serialized
return values.
Neil Harrison in Pattern Languages of Program
Design 3 Eds Martin, Riehle, Buschman, 1998, pp 277-289.
sdsu.logging.Logger
Defines types of logging messages
- log
- debug
- warning
- error
You can define your own type of logging message
Logging of each type can be turn off, without having to remove the logging
statements from code
Different Loggers
ScreenLogger
- Send log data to screen
FileLogger
- Send log data to a file
NullLogger
- Ignores log data
Sample Use of Logger
import sdsu.logging.*;
public class Tester
{
public static void main( String[] args) throws
LoggerCreationException
{
FileLogger myLog =
FileLogger.register( "LogFile");
myLog.debugOff();
myLog.warningOff();
// Some where else in the program
Logger.debug( "I am lost, This does not work");
Logger.log( "Routine log stuff" );
}
}
There may be times when you want a remote object to have a parent other than
UnicastRemoteObject
There are performance reasons for doing this:
- Reduce the time for serialization
The following example also shows passing around references to remote objects
This can be done when an object is s child of UnicastRemoteObject
The Players in the Example
Echo
- A remote interface
EchoImpl
- Implements Echo, but is not child of UnicastRemoteObject
EchoExample
- Interface for EchoServer
EchoServer
- Server that exports Echo objects
EchoClient
- Client that interacts with EchoServer
-
- Client also exports Echo objects
-
- Needs to have rmiregistry running on same machine as client
package whitney.rmi.examples.server;
import java.rmi.*;
public interface Echo extends Remote
{
public void print( String message )
throws RemoteException;
}
package whitney.rmi.examples.server;
import java.rmi.RemoteException;
public class EchoImpl implements Echo
{
private static int NEXT_ID = 1;
private int id = NEXT_ID++;
private String name;
public EchoImpl( String name)
{ this.name = name; }
public void print( String message ) throws RemoteException
{
System.out.println( "From name: " + name + " " + id + " : " +
message);
}
//These are needed to replace UnicastRemoteObject parent
public int hashCode()
{ return id; }
public boolean equals( Object anEcho )
{
if ( !(anEcho instanceof EchoImpl) )
return false;
if ( id == ((EchoImpl) anEcho).id )
return true;
else
return false;
}
public String toString()
{ return "Echo(" + name + "," + id + ")"; }
}
package whitney.rmi.examples.server;
import java.rmi.RemoteException;
public interface EchoExample extends java.rmi.Remote
{
public Echo getNewEcho( ) throws RemoteException;
public void setRemoteEcho( Echo fromClient )
throws RemoteException;
public Echo getRemoteEcho() throws RemoteException;
}
package whitney.rmi.examples.server;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.Registry;
import sdsu.util.ProgramProperties;
import java.io.*;
public class EchoServer
extends UnicastRemoteObject
implements EchoExample
{
Echo remoteEcho;
public EchoServer() throws RemoteException { }
public Echo getNewEcho( ) throws RemoteException
{
Echo registerFirst = new EchoImpl( "ServerSam");
registerFirst.print( "In Server.getNewEcho");
UnicastRemoteObject.exportObject( registerFirst);
return registerFirst;
}
public void setRemoteEcho( Echo fromClient )
throws RemoteException
{
remoteEcho = fromClient;
fromClient.print( "In Server.setRemoteEcho");
}
public Echo getRemoteEcho() throws RemoteException
{
remoteEcho.print( "In Server.getRemoteEcho");
return remoteEcho;
}
public static String RMI_NAME = "cs696/EchoServer";
public static void main(String args[]) throws RemoteException, IOException
{
int port = getPort( args );
EchoServer serverObject = new EchoServer();
Naming.rebind("//:" + port + "/" + RMI_NAME, serverObject );
System.out.println("EchoServer bound in registry");
}
private static int getPort( String args[] ) throws IOException
{
ProgramProperties flags = new ProgramProperties( args );
int defaultPort = Registry.REGISTRY_PORT;
int port = flags.getInt( "p", defaultPort );
return port;
}
}
package whitney.rmi.examples.server;
import java.rmi.*;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.net.MalformedURLException;
import java.io.IOException;
import sdsu.util.ProgramProperties;
import sdsu.logging.Debug;
public class EchoClient {
public static void main(String args[]) {
try {
String serverLabel = EchoServer.RMI_NAME;
String server = getServerURL( args, serverLabel );
EchoExample echoServer =
(EchoExample) Naming.lookup( server );
Debug.println("First getNewEcho");
Echo fromServer = echoServer.getNewEcho();
fromServer.print( "In Client");
Echo clientEcho = new EchoImpl( "ClientClem");
clientEcho.print( "In Client");
UnicastRemoteObject.exportObject( clientEcho);
Debug.println( "First setRemoteEcho");
echoServer.setRemoteEcho( clientEcho );
Debug.println( "First getRemoteEcho");
fromServer = echoServer.getRemoteEcho();
fromServer.print( "In Client");
Debug.println( "Done");
System.exit( 0 );
}
catch ( Exception error) { error.printStackTrace(); }
}
//Client Continued
private static String getServerURL( String args[],
String serverLabel ) throws IOException
{
String hostKey = "h";
String portKey = "p";
ProgramProperties flags = new ProgramProperties( args );
String host = null;
if ( flags.containsKey( hostKey ) )
host = flags.getString( hostKey );
else
{
System.out.println( "Missing flag " + hostKey );
System.exit( 0 );
}
int defaultPort = Registry.REGISTRY_PORT;
int port = flags.getInt( portKey, defaultPort );
return "rmi://" + host + ":" + port + "/" + serverLabel;
}
}
One client was run once
Server Side Output
From name: ServerSam 1 : In Server.getNewEcho
From name: ServerSam 1 : In Client
Client Side Output
Debug server.EchoClient.main(Compiled Code): First getNewEcho
From name: ClientClem 1 : In Client
Debug server.EchoClient.main(Compiled Code): First setRemoteEcho
From name: ClientClem 1 : In Server.setRemoteEcho
Debug server.EchoClient.main(Compiled Code): First getRemoteEcho
From name: ClientClem 1 : In Server.getRemoteEcho
From name: ClientClem 1 : In Client
Debug server.EchoClient.main(Compiled Code): Done
Each remote object has a referenced set
Each time a remote object is passed as a parameter or returned as a
result of a remote request the identifier for the virtual machine to which it
was passed is added to its referenced set
Once the remote virtual machine no longer has a reference to the remote object,
it will be removed from the objects reference set
If the remote object implements the
java.rmi.server.Unreferenced interface
when its referenced set becomes empty it's unreferenced method will be
called
The unreferenced method can be called more than once
It is not called the instance the last client reference is deleted
Delays of 10 - 15 minutes have been reported
When an remote object has no remote or local references it can be garbage
collected
A remotes finalize method will be called when it is garbage collected
If you really need to know when a client(s) is done with a remote reference it
is a good idea to :
- have the client explicitly inform the server
-
- catch java.rmi.ConnectException for the cases when the connection goes down
-
- use unreferenced as a back up
visitors since 17-Feb-98