SDSU CS 696 Emerging Technologies: Java Distributed Computing
Spring Semester, 1999
Jini Transactions
Previous    Lecture Notes Index    Next    
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 20-Apr-99

Contents of Doc 28, Jini Transactions


References

Jini Transaction Specification 1.0 January 25, 1999
This document is available at: http://www.sun.com/jini/specs/index.html

Jini API, Local on-line version at: http://www-rohan.sdsu.edu/doc/jini/doc/api/index.html

Doc 28, Jini Transactions Slide # 2

Some Transaction Classes

TransactionManager Interface

Package: net.jini.core.transaction.server

The interface used for managers of the two-phase commit protocol for top-level transactions. Extends remote. Mahalo implements this interface.

Methods
abort(long id) 
abort(long id, long waitFor) 
commit(long id) 
commit(long id, long waitFor) 
create(long lease) 
getState(long id) 
join(long id, TransactionParticipant part,  long crashCount) 

TransactionManager.Created

Package net.jini.core.transaction.server

Class that holds return values from TransactionManager create method.

Fields
long
id
The transaction id.
Lease
lease
The lease.


Doc 28, Jini Transactions Slide # 3

TransactionConstants

Package net.jini.core.transaction.server

Fields- all ints
ABORTED
Transaction has been aborted
ACTIVE
Transaction is currently active
COMMITTED
Transaction has been committed
NOTCHANGED
Transaction has been prepared with nothing to commit
PREPARED
Transaction has been prepared but not yet committed
VOTING
Transaction is determining if it can be committed

TransactionParticipant Interface


Package net.jini.core.transaction.server
Extends Remote, TransactionConstants

Methods
void abort(TransactionManager mgr, long id) 
Requests that the participant rolls back any changes for the specified transaction and unlock any resources locked by the transaction.
void commit(TransactionManager mgr, long id) 
Requests that the participant makes all of its PREPARED changes for the specified transaction visible outside of the transaction and unlocks any resources locked by the transaction.
int prepare(TransactionManager mgr, long id) 
Requests that the participant prepare itself to commit the transaction, and to vote on the outcome of the transaction.
int prepareAndCommit(TransactionManager mgr, long id) 
A combination of prepare and commit, which can be used by the manager when there is just one participant left to prepare and all other participants (if any) have responded with NOTCHANGED.

Doc 28, Jini Transactions Slide # 4

A Simple Example

Source Code

Count

package whitney.jini.examples.transaction;
import java.rmi.Remote;
import java.rmi.RemoteException;
import net.jini.core.transaction.CannotJoinException;
import net.jini.core.transaction.server.CrashCountException;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.UnknownTransactionException;
public interface Count extends Remote  {
   public void increase( int amount, TransactionManager manager, 
            long transactionID) throws RemoteException, 
               UnknownTransactionException, CannotJoinException, 
               CrashCountException;
   public int count( ) throws RemoteException;
}

Doc 28, Jini Transactions Slide # 5

CountServer

package whitney.jini.examples.transaction;
import com.sun.jini.lease.LeaseRenewalManager;
import com.sun.jini.lookup.JoinManager;
import com.sun.jini.lookup.ServiceIDListener;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import net.jini.core.entry.Entry;
import net.jini.core.lookup.ServiceID;
import net.jini.core.transaction.CannotJoinException;
import net.jini.core.transaction.server.CrashCountException;
import net.jini.core.transaction.server.TransactionConstants;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.server.TransactionParticipant;
import net.jini.core.transaction.UnknownTransactionException;
import net.jini.discovery.LookupDiscovery;
import net.jini.lookup.entry.Name;
import sdsu.util.ProgramProperties;
public class CountServer extends UnicastRemoteObject 
   implements Count, ServiceIDListener, TransactionParticipant {
   private ServiceID myID;
   private int count = 0;
   
   Map pendingBids = Collections.synchronizedMap( new HashMap());
   public CountServer() throws RemoteException  { }
   public int count() { return count; }
      
   public void increase( int amount, TransactionManager manager, 
               long transactionID) throws RemoteException, 
                  UnknownTransactionException, CannotJoinException, 
                  CrashCountException {
      System.out.println( "Increase: " + amount );
      manager.join( transactionID, this, 0 );
      System.out.println( "Increase joined" );
      pendingBids.put( new Long( transactionID ), new Integer( amount ) );
      }
      
   public void abort(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "Abort" );
      pendingBids.remove( new Long( transactionID ) );
   }

Doc 28, Jini Transactions Slide # 6
CountServer Continued
   public void commit(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "commit" );
      int bid = getBid( transactionID );
      count = count +  bid;
      System.out.println( "commit: bid " + bid + " count " + count );
      pendingBids.remove( new Long( transactionID ) );
   }
      
   public int prepare(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "prepare" );
      
      if ( !pendingBids.containsKey( new Long( transactionID ) ) )
         throw new UnknownTransactionException();
         
      int bidValue = getBid( transactionID );
      System.out.println( "prepare bidValue: " + bidValue );
      
      if ( bidValue == 0 )
         return NOTCHANGED;
      System.out.println( "prepare maxBid: " + getMaxBid()  );
      
      if ( bidValue < getMaxBid() ) {
         abort( mgr, transactionID );
         return ABORTED;
      }
         
      return PREPARED;
   }

Doc 28, Jini Transactions Slide # 7
CountServer Continued
   public int prepareAndCommit(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "prepare & commit" );
      int result = prepare( mgr, transactionID );
      if ( result == PREPARED ) {
         commit(  mgr, transactionID );
         result = COMMITTED;
      }
      return result;
   }
   private int getBid(long bidID) {
      Integer bid =(Integer) pendingBids.get( new Long( bidID ) );
      return bid.intValue();
   }
      
   private int getMaxBid() {
      Integer maxBid;
      synchronized (pendingBids) {
         Collection values = pendingBids.values();
         maxBid = (Integer) Collections.max( values );
      }
      return maxBid.intValue();
   }
   public void serviceIDNotify (ServiceID uniqueID) {
      myID = uniqueID;
      System.out.println("server: ID set: " + myID );
   }

Doc 28, Jini Transactions Slide # 8
CountServer Continued
   public static void main (String[] args) throws Exception {
      System.setSecurityManager (new RMISecurityManager ());
      CountServer myServer = new CountServer();
      ProgramProperties flags = new ProgramProperties( args);
      String groupsString = flags.getString( "groups", "ALL" );
      String[] groups = formateGroupList( groupsString );
      Entry[] identityingAttributes = new Entry[1];
      identityingAttributes[0] = new Name("CountServer");
      JoinManager myManager = new JoinManager 
            (
            myServer, 
            identityingAttributes,
            groups,
            null, 
            myServer, 
            new LeaseRenewalManager ()
            );
      System.out.println ("Server has been Joined!");
   }

Doc 28, Jini Transactions Slide # 9
CountServer Continued
   private static String[] formateGroupList( String groupList ) {
      if (groupList.equals( "NONE") ) {
         System.out.println( "Usage: java HelloServer -groups=group1,group2 " );
         System.exit( 0 );
      }
      if (groupList.equals( "ALL") )
         return LookupDiscovery.ALL_GROUPS;
      
      if ( groupList.indexOf( ',' ) < 0 )
         return new String[] { groupList.trim() };
      
      StringTokenizer groups = new StringTokenizer( groupList, ",'");
      
      String[] formatedGroups = new String[ groups.countTokens() ];
      
      for ( int k = 0; k < formatedGroups.length; k++ ) {
         formatedGroups[k] = groups.nextToken().trim();
      }
      return formatedGroups;
   }      
}

Doc 28, Jini Transactions Slide # 10

TransactionClient

package whitney.jini.examples.transaction;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import net.jini.core.discovery.LookupLocator;    
import net.jini.core.entry.Entry;
import net.jini.core.lease.Lease;
import net.jini.core.lease.LeaseDeniedException;
import net.jini.core.lookup.ServiceRegistrar; 
import net.jini.core.lookup.ServiceTemplate; 
import net.jini.core.transaction.server.TransactionConstants;
import net.jini.core.transaction.server.TransactionManager.Created;
import net.jini.core.transaction.server.TransactionManager;
import net.jini.core.transaction.server.TransactionParticipant;
import net.jini.core.transaction.UnknownTransactionException;
import net.jini.lookup.entry.Name;
import sdsu.util.ProgramProperties;
public class TransactionClient extends Thread implements TransactionParticipant {
   TransactionManager manager;
   Count aCounter;
   int bid;
   
   public static void main (String[] args) throws Exception {
      System.out.println( "Start" );
      ProgramProperties flags = new ProgramProperties( args);
      
      int commandBid = flags.getInt( "bid", 5 );
      System.setSecurityManager (new RMISecurityManager ());
      LookupLocator lookup = new LookupLocator ("jini://eli.sdsu.edu");
      ServiceRegistrar registrar = lookup.getRegistrar ();
      TransactionClient aClient = new TransactionClient( commandBid, registrar );
      aClient.start();
   }
      

Doc 28, Jini Transactions Slide # 11
TransactionClient
   public TransactionClient( int bid, ServiceRegistrar registrar ) 
      throws RemoteException {
      System.out.println( "New Client" );
      this.bid = bid;
      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);
      
      serverAttributes[0] = new Name ("CountServer");
      System.out.println( "Get count" );
      aCounter = (Count) registrar.lookup (template);
      System.out.println( "export" );
      UnicastRemoteObject.exportObject( this );
   }
      
   public void abort(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "Abort" );
   }
      
   public void commit(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "commit" );
   }

Doc 28, Jini Transactions Slide # 12
TransactionClient
   public int prepare(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "prepare" );
      return PREPARED;
   }
   public int prepareAndCommit(TransactionManager mgr, long transactionID) 
      throws UnknownTransactionException, RemoteException {
      System.out.println( "prepare & commit" );
      int result = prepare( mgr, transactionID );
      if ( result == PREPARED ) {
         commit(  mgr, transactionID );
         result = COMMITTED;
      }
      return result;
   }

Doc 28, Jini Transactions Slide # 13
TransactionClient
   public void run() {
      try {
         System.out.println( "Get a transaction" );
         Created leasedTransaction = manager.create( 1000 * 60 * 2 );
         Lease aLease = leasedTransaction.lease;
         
         System.out.println( "Lease duration: " + (aLease.getExpiration() - now()) );
         manager.join( leasedTransaction.id, this, 0 );
         
         System.out.println( "Call increase" );
         aCounter.increase( bid, manager, leasedTransaction.id );
         
         System.out.println( "Sleep" );
         Thread.sleep( 1000 * 10 );
         System.out.println( "Start commit" );
         manager.commit( leasedTransaction.id );
         System.out.println( "Done with commit" );
         Thread.sleep( 1000 * 2 );
         System.out.println( "Count value: " + aCounter.count());
      } catch (RemoteException rmiError ) {
         rmiError.printStackTrace();
      }   catch (LeaseDeniedException leaseDenied ) {
         leaseDenied.printStackTrace();
      } catch (Exception leaseDenied ) {
         leaseDenied.printStackTrace();
      } finally {
         finalize();
      }
   }

Doc 28, Jini Transactions Slide # 14
TransactionClient
   public void finalize() {
      try {
         UnicastRemoteObject.unexportObject( this, true );
      } catch (Exception problem ) {
         problem.printStackTrace();
      }
   }
   private long now() {
      return System.currentTimeMillis();
   }
}

Doc 28, Jini Transactions Slide # 15

Running the Example


You must set -C-Djava.rmi.server.codebase on rmid to allow mahalo to download the stubs for TransactionParticipants in transactions. Here is the script I use:

#/bin/csh
#Start jini services
set httpPort=8880;
set jiniDir=~whitney/lib/jini/lib
set jiniLog=~whitney/jini_data/jini_logs
set jiniData=~whitney/jini_data
rm -R $jiniLog/rmid
rmid -C-Djava.rmi.server.codebase=http://eli.sdsu.edu:8880 
   -log $jiniLog/rmid &
echo "rmid started"
echo ""
java -jar $jiniDir/tools.jar -port $httpPort -dir $jiniData/jini_http_root -verbose & 
echo "http server started"
echo ""


Doc 28, Jini Transactions Slide # 16
Running the Example Continued
Here a script file that does that
#/bin/csh
#Start reggie
switch ($#) 
   case 0:
   case 1:
      echo "Usage: reggie httpPort rmidPort"
      exit 2
endsw
set httpPort=$1;
set rmidPort=$2;
set jiniDir=/opt/jini1_0/lib
set jiniLog=~whitney/jini_data/jini_logs
set jiniData=~whitney/jini_data
rm -R $jiniLog/reggie 
java    -Djava.rmi.activation.port=$rmidPort -jar $jiniDir/reggie.jar 
   http://eli.sdsu.edu:$httpPort/reggie-dl.jar $jiniData/policy    $jiniLog/reggie ´whoami´"."´hostname´"."´domainname´ &

echo "reggie started"

Doc 28, Jini Transactions Slide # 17
Running the Example Continued
Here a script file that does that

#/bin/csh
#Start jini services
switch ($#) 
   case 0:
   case 1:
      echo "Usage: mahalo httpPort rmidPort"
      exit 2
endsw
set httpPort=$1;
set rmidPort=$2;
set jiniDir=~whitney/lib/jini/lib
set jiniLog=~whitney/jini_data/jini_logs
set jiniData=~whitney/jini_data
rm -R $jiniLog/mahalo 
java    -Djava.rmi.activation.port=$rmidPort 
   -Djava.security.policy=$jiniData/policy
   -Dcom.sun.jini.mahalo.managerName=TransactionManager
   -jar $jiniDir/mahalo.jar http://eli.sdsu.edu:$httpPort/reggie-dl.jar 
   $jiniData/policy $jiniLog/mahalo 
   ´whoami´"."´hostname´"."´domainname´ &
echo "mahalo started"

Doc 28, Jini Transactions Slide # 18
Running the Example Continued

These are needed for both CountServer & TransactionClient




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 20-Apr-99    Next