|
CS 696 Emerging Technologies: Java Distributed Computing
Spring Semester, 1999
A Simple Transaction Example
|
|
|
Previous   
Lecture Notes Index
   Next    
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 02-May-99
|
|
Contents of Doc 32, A Simple Transaction Example
References
Past
lecture notes.
A
Simple Transaction Example
This
is a simple example that uses the transaction manager. The classes and files
are involved:
ClientLauncher
- This
class uses multicast discovery to contact a Jini lookup service that belongs to
a group. Once it discovers the lookup service it creates an instance
TransactionClient, passing a remote reference to the lookup manager to the
TransactionClient object.
TransactionClient
- Extracts
a remote reference for the transaction manager from the Jini lookup service.
When mahalo, the transaction manager, is started the
-Dcom.sun.jini.mahalo.managerName
flag provides the name of the transaction manager in the lookup service.
TransactionClient performs two different transactions. The first with three
YesParticipants and the second with two YesParticipants and a NoParticipant.
Since the second transaction has a NoParticipant, an exception is thrown.
YesParticipant
- Implements
the four TransactionParticipant methods. Prints a message each time a method is
called. Always accepts a transaction. Since this class has no state, its
prepare method should return NOTCHANGED. However, to show operation of the
transaction manager, it returns PREPARED.
NoParticipant
- Implements
the four TransactionParticipant methods. Prints a message each time a method is
called. Always rejects a transaction.
Service Script – startJini
- This
script file starts an http server, rmid, reggie, and mahalo. Sleep is used
between starting rmid, reggie and mahalo to insure the previous service is
running. The script uses the following file structure. The directory
~whitney/jini_data contains the policy file for the services in the file
policy. The directory ~whitney/jini_data/jini_logs is used for the logs of the
jini services in the subdirectories ~whitney/jini_data/jini_logs/rmid,
~whitney/jini_data/jini_logs/mahalo, ~whitney/jini_data/jini_logs/reggie. The
directory ~whitney/jini_data/jini_http_root contains the files the http server
can access. The script uses a number of variables. The values of these
variables when run on rohan.sdsu.edu from the whitney account are given below.
- httpPort=8789;
- rmidPort=8689;
- user=whitney
- jiniDir=/opt/jini1_0/lib
- jiniLog=/home/ma/whitney/jini_data/jini_logs
- jiniData=/home/ma/whitney/jini_data
- jiniHTTPRoot
=/home/ma/whitney/jini_http_root
- host=rohan.sdsu.edu
- groupName=whitney.rohan.sdsu.edu
- codebase=http://rohan.sdsu.edu:8789
Running
the Example
No
Package
Files
/opt/java/jre/lib/ext/
- The
table below contains the files in this directory. Being in this location makes
the jar files below extensions to java 1.2 on rohan. This means that these jar
file do not have to be in your classpath to use classes in the jar files. In
particular, jini clients will have access to all the jini files. Hence, clients
will not have to dynamically download the
reggie-dl.jar,
mahalo-dl.jar files. This was done to make developing jini programs on rohan a
bit easier (so you don’t need for the http server to be working correctly).
iiimp.jar
|
mahalo.jar
|
sdsuLibJKD12.jar
|
jini-core.jar
|
outrigger.jar
|
sun-util.jar
|
jini-ext.jar
|
reggie.jar
|
transient-outrigger.jar
|
/home/ma/whitney/jini_data/
- Contains
the file “policy”, which is policy file used by the jini services
/home/ma/whitney/jini_data/jini_logs/
- Contains
the subdirectories mahalo, reggie, rmid which are used by the Jini services to
store the log files. This is set up in the startJini script
/home/ma/whitney/jini_data/jini_http_root/
- Contains
the files: NoParticipant_Stub.class, YesParticipant_Stub.class, reggie-dl.jar,
mahalo-dl.jar. These files are downloaded on demand to clients by the http
server. These stub files were moved here after the stubs were generated.
/home/ma/whitney/jini/examples/transaction/noPackage/
- Before
compiling the example this directory contains the files in the table below.
ClientLauncher.java
|
TransactionClient.java
|
NoParticipant.java
|
YesParticipant.java
|
/home/ma/whitney/bin/
- Contains
the script file startJini. The directory is in my path.
Command
to Run with No Packages
- This
is done by running the script startJini. This is not done in the directory that
contains the class files for the example. This only needs to be done once.
- In
/home/ma/whitney/jini/examples/transaction/noPackage I compiled the files using:
javac *.java
- Create
the stub & skeleton class files
- The
transaction manager sends message to all TransactionParticipants. The
TransactionParticipants interface extends java.rmi.Remote. This means all
TransactionParticipants need stubs and skeletons. This is done in this example
using the commands below. Note for some reason that I do not understand, I have
to add the jini jar files to my path for rmic to generate the stubs and
skeleton classes for any jini code. Since the jini jar files are extensions to
the JVM I should not have to do this.
rmic NoParticipant
rmic YesParticipant
- Copy
the stub classes to the http root directory
- I
used the following command to do this. This assumes the current directory is
/home/ma/whitney/jini/examples/transaction/noPackage
cp *stub.class /home/ma/whitney/jini_data/jini_http_root/
- I
used the following command. It assumes the group of my reggie is
whitney.rohan.sdsu.edu.
java ClientLauncher –group=whitney.rohan.sdsu.edu
Using
Packages
I
ran the example placing the classes in a package. The package for all four
classes is whitney.jini.examples.transaction.
Files
/opt/java/jre/lib/ext/
- The
table below contains the files in this directory. This makes the jar files
below extensions to java 1.2 on rohan. This means that these jar files do not
have to be in your classpath to use classes in the jar files. In particular,
jini clients will have access to all the jini files. Hence, clients will not
have to dynamically download the
reggie-dl.jar,
mahalo-dl.jar files. This was done to make developing jini programs on rohan a
bit easier (reduce need for the http server to be working correctly).
iiimp.jar
|
mahalo.jar
|
sdsuLibJKD12.jar
|
jini-core.jar
|
outrigger.jar
|
sun-util.jar
|
jini-ext.jar
|
reggie.jar
|
transient-outrigger.jar
|
/home/ma/whitney/jini_data/
- Contains
the file “policy”, which is policy file used by the jini services
/home/ma/whitney/jini_data/jini_logs/
- Contains
the subdirectories mahalo, reggie, rmid which are used by the Jini services to
store the log files. This is set up in the startJini script
/home/ma/whitney/jini_data/jini_http_root/
- Contains
the files: reggie-dl.jar, mahalo-dl.jar. These files are downloaded on demand
to clients by the http server.
/home/ma/whitney/jini_data/jini_http_root/whitney/jini/examples/transaction/
- Contains
the files: NoParticipant_Stub.class and YesParticipant_Stub.class. These stub
files were moved here after the stubs were generated.
/home/ma/whitney/jini/examples/transaction/
- Before
compiling the example this directory contains the files in the table below.
ClientLauncher.java
|
TransactionClient.java
|
NoParticipant.java
|
YesParticipant.java
|
/home/ma/whitney/bin/
- Contains
the script file startJini. The directory is in my path.
Command
to Run with Packages
- This
is done by running the script startJini. This is not done in the directory that
contains the class files for the example. This only needs to be done once.
- In
/home/ma/whitney/jini/examples/transaction/ I compiled the files using:
javac *.java
- Create
the stub & skeleton class files
- The
transaction manager sends message to all TransactionParticipants. The
TransactionParticipants interface extends java.rmi.Remote. This means all
TransactionParticipants need stubs and skeletons. This is done in this example
using the commands below. Note for some reason that I do not understand, I have
to add the jini jar files to my path for rmic to generate the stubs and
skeleton classes for any jini code. Since the jini jar files are extensions to
the JVM I should not have to do this.
rmic whitney.jini.examples.transaction.NoParticipant
rmic whitney.jini.examples.transaction.YesParticipant
- Copy
the stub classes to the http root directory
- I
used the following command to do this. This assumes the current directory is
/home/ma/whitney/jini/examples/transaction/noPackage
cp *stub.class ~/jini_data/jini_http_root/whitney/jini/examples/transaction
- I
used the following command. It assumes the group of my reggie is
whitney.rohan.sdsu.edu.
-
- java
whitney.jini.examples.transaction.ClientLauncher
–group=whitney.rohan.sdsu.edu
Rohan
& Moria
I
was able to run the example on rohan. This means the Jini services were running
on rohan and the ClientLauncher was run on rohan. When I ran the ClientLauncher
on moria, it found the reggie service on rohan, but an exception was thrown
when the client tried to contact the transaction manager. This appears to be a
problem with the host names of the machines not being properly read by the java
VM.
Source
Code
ClientLauncher
import java.io.IOException;
import java.rmi.RMISecurityManager;
import net.jini.core.discovery.LookupLocator;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.discovery.DiscoveryEvent;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.LookupDiscovery;
import sdsu.util.ProgramProperties;
public class ClientLauncher implements DiscoveryListener
{
public static void main (String[] args) throws Exception
{
System.setSecurityManager (new RMISecurityManager ());
ProgramProperties flags = new ProgramProperties( args);
if ( !flags.containsKey( "group") )
{
System.out.println( "Usage: java ClientLauncher -group=groupName" );
System.exit(0);
}
String groupsString = flags.getString( "group" );
new ClientLauncher( groupsString );
Thread.currentThread().sleep( 1000 * 60 * 2 );
}
public ClientLauncher( String group ) throws IOException
{
String[] serverGroup = { group };
LookupDiscovery findAllLookupServices =
new LookupDiscovery( serverGroup );
findAllLookupServices.addDiscoveryListener( this );
}
public void discovered(DiscoveryEvent lookupService )
{
startClient( lookupService);
}
public void discarded(DiscoveryEvent lookupService)
{
}
private void startClient( DiscoveryEvent event)
{
try
{
ServiceRegistrar lookupServices[] = event.getRegistrars();
if ( lookupServices.length > 0 )
{
TransactionClient aClient = new TransactionClient( lookupServices[0] );
}
}
catch (Exception lookupProblem)
{
lookupProblem.printStackTrace();
}
}
}
TransactionClient
import java.rmi.RemoteException;
import net.jini.core.entry.Entry;
import net.jini.core.lease.Lease;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;
import net.jini.core.transaction.server.TransactionManager.Created;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.lookup.entry.Name;
public class TransactionClient
{
TransactionManager manager;
public TransactionClient( ServiceRegistrar registrar ) throws RemoteException
{
System.out.println( "New Client" );
Entry[] serverAttributes = new Entry[1];
serverAttributes[0] = new Name ("TransactionManager");
ServiceTemplate template = new ServiceTemplate (null, null, serverAttributes);
System.out.println( "Get Transaction M" );
manager = (TransactionManager) registrar.lookup (template);
if (manager == null )
System.out.println( "Null manager" );
else
{
System.out.println( "Got a good manager" );
startExample();
}
}
public void startExample()
{
try
{
System.out.println( "Start transcation with three YesParticipants" );
Created leasedTransaction = manager.create( 1000 * 60 * 2 );
manager.join( leasedTransaction.id, new YesParticipant( "A"), 0 );
manager.join( leasedTransaction.id, new YesParticipant( "B"), 0 );
manager.join( leasedTransaction.id, new YesParticipant( "C"), 0 );
System.out.println( "Start commit" );
manager.commit( leasedTransaction.id );
Thread.sleep( 1000 * 10 );
System.out.println( "Start transcation with 2 YesParticipants & 1 no" );
leasedTransaction = manager.create( 1000 * 60 * 2 );
manager.join( leasedTransaction.id, new YesParticipant( "D"), 0 );
manager.join( leasedTransaction.id, new NoParticipant( "E"), 0 );
manager.join( leasedTransaction.id, new YesParticipant( "F"), 0 );
System.out.println( "Start commit" );
manager.commit( leasedTransaction.id );
System.out.println( "Good bye" );
}
catch (Exception leaseDenied )
{
leaseDenied.printStackTrace();
}
}
}
NoParticipant
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.server.TransactionParticipant;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
public class NoParticipant extends UnicastRemoteObject implements TransactionParticipant
{
String name;
public NoParticipant( String aName ) throws RemoteException
{
super();
name = aName;
}
public synchronized void abort(TransactionManager mgr, long transactionID)
{
System.out.println( "Abort called on NoParticipant " + name );
}
public synchronized void commit(TransactionManager mgr, long transactionID)
{
System.out.println( "Commit called on NoParticipant " + name );
}
public int prepare(TransactionManager mgr, long transactionID)
{
System.out.println( "Prepare called on NoParticipant " + name );
return ABORTED;
}
public int prepareAndCommit(TransactionManager mgr, long transactionID)
{
System.out.println( "prepare & commit called on NoParticipant " + name );
int result = prepare( mgr, transactionID );
if ( result == PREPARED )
{
commit( mgr, transactionID );
result = COMMITTED;
}
return result;
}
}
YesParticipant
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.server.TransactionParticipant;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
public class YesParticipant extends UnicastRemoteObject implements TransactionParticipant
{
String name;
public YesParticipant( String aName ) throws RemoteException
{
super();
name = aName;
}
public synchronized void abort(TransactionManager mgr, long transactionID)
{
System.out.println( "Abort called on YesParticipant " + name );
}
public synchronized void commit(TransactionManager mgr, long transactionID)
{
System.out.println( "Commit called on YesParticipant " + name );
}
public int prepare(TransactionManager mgr, long transactionID)
{
System.out.println( "Prepare called on YesParticipant " + name );
return PREPARED;
}
public int prepareAndCommit(TransactionManager mgr, long transactionID)
{
System.out.println( "prepare & commit called on YesParticipant " + name );
int result = prepare( mgr, transactionID );
if ( result == PREPARED )
{
commit( mgr, transactionID );
result = COMMITTED;
}
return result;
}
}
Service
Script – startJini
#/bin/csh
#Start jini services
set httpPort=8789;
set rmidPort=8689;
set user=´whoami´
set jiniDir=/opt/jini1_0/lib
set jiniLog=~$user/jini_data/jini_logs
set jiniData=~$user/jini_data
set jiniHTTPRoot = $jiniData/jini_http_root
set host=´hostname´"."´domainname´
set groupName=´whoami´"."´hostname´"."´domainname´
set codebase=http://${host}:$httpPort
java -jar $jiniDir/tools.jar -port $httpPort -dir $jiniHTTPRoot -verbose &
echo "http server started"
echo ""
echo "Remove old log files"
echo ""
rm -Rf $jiniLog/rmid
rm -Rf $jiniLog/mahalo
rm -Rf $jiniLog/reggie
rmid -C-Djava.rmi.server.codebase=$codebase \
-C-Djava.rmi.server.hostname=$host \
-C-Djava.rmi.activation.port=$rmidPort \
-log $jiniLog/rmid -port $rmidPort &
echo "rmid started"
echo ""
sleep 5
java -Djava.rmi.server.hostname=$host -Djava.rmi.activation.port=$rmidPort
-jar $jiniDir/reggie.jar $codebase/reggie-dl.jar
$jiniData/policy $jiniLog/reggie $groupName &
echo "reggie started"
echo ""
sleep 5
java -Djava.rmi.server.hostname=$host -Djava.rmi.server.codebase=$codebase
-Djava.rmi.activation.port=$rmidPort -Djava.security.policy=$jiniData/policy
-Dcom.sun.jini.mahalo.managerName=TransactionManager
-jar $jiniDir/mahalo.jar $codebase/mahalo-dl.jar
$jiniData/policy $jiniLog/mahalo $groupName &
echo "mahalo started"
Policy
File
grant codebase "file:${java.class.path}" {
permission java.io.FilePermission "/export/home/whitney/jini_data/jini_logs/-",
"read,write,delete";
permission java.io.FilePermission "<<ALL FILES>>", "read";
permission java.lang.RuntimePermission "modifyThreadGroup";
permission java.lang.RuntimePermission "modifyThread";
permission java.net.SocketPermission "*:1024-", "connect,accept";
// for http: codebases
permission java.net.SocketPermission "*", "connect,accept";
permission java.net.SocketPermission "224.0.1.85", "connect,accept";
permission java.util.PropertyPermission "java.rmi.server.hostname", "read";
permission java.util.PropertyPermission "com.sun.jini.reggie.*", "read";
permission java.util.PropertyPermission "net.jini.discovery.*", "read";
permission net.jini.discovery.DiscoveryPermission "*";
};
Copyright ©, All rights reserved.
1999 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.
Previous   
visitors since 02-May-99
   Next