|
|
|
Advertisement
|
To illustrate the default transaction semantics' goals, let's revisit the Jini bookstore's service interface introduced in Part 2 of this series:
public interface BookStore {
public Collection findBooks(Book template)
throws RemoteException;
public OrderConfirmation buyBook(Book book,
CreditCard card,
Customer customer,
Address shipTo,
int daysToDelivery,
Transaction txn)
throws NoSuchBookException, CreditCardException,
DeliveryException, RemoteException, TransactionException;
}
The bookstore uses two other Jini services for credit card processing and shipping. These services have the following interfaces:
public interface CreditCard {
public ChargeConfirmation debit(Account account,
Charge charge,
Transaction txn)
throws NoSuchAccountException, CannotChargeException,
CreditCardException, RemoteException, TransactionException;
public PaymentConfirmation pay(Account account,
Payment payment,
Transaction txn)
throws NoSuchAccountException, CreditCardException,
RemoteException, TransactionException;
public CurrentBalance getBalance(Account account)
throws NoSuchAccountException, CreditCardException,
RemoteException;
and
public interface ShippingCompany {
public PickupGuarantee checkPickup(Address origin,
Address destination,
PackageDesc package,
int daysToShip)
throws ShippingException, RemoteException;
public PickupConfirmation schedulePickup(PickupGuarantee guar,
Transaction txn)
throws NoSuchGuaranteeException, ShippingException,
RemoteException, TransactionException; }
Regardless of any particular implementation, these services provide interfaces to persistent information. While some method calls in the service interfaces need read-only access to persistent data, other method invocations modify data. For instance, the CreditCard service's getBalance() method only reads the credit card's current balance. The debit() method, on the other hand, modifies persistent data -- it increases the account's balance, and can log a purchase onto persistent store.
You can imagine service-performed operations on persistent data in terms of read and write actions. While transactions are units of state transformation (write actions), their importance extends to read actions as well. You can assume outputs from transaction-performed actions only when the transaction commits. This notion is key to understanding the default transaction semantics for Jini services. To solidify this notion, consider the following steps in arranging a book payment:
Figure 1. Perform a transactional method invocation in Jini
|
Figure 1 illustrates these steps:
BookStore's buyBook() method. BookStore then discovers and obtains a reference to a CreditCard service.
BookStore next calls a CreditCard service's debit() method, passing in the customer's account information.
debit() consumes a Transaction object, CreditCard implements the net.jini.core.transaction.server.TransactionParticipant interface. TransactionParticipant is a remote interface; it extends java.rmi.Remote, making its methods available for calls from remote virtual machines.
debit(), CreditCard joins the transaction instance passed in as a parameter. It first casts the Transaction parameter to a net.jini.core.transaction.server.ServerTransaction; then it calls the join() method on that object, passing a reference to itself (a TransactionParticipant).
CreditCard as a transaction participant. When the transaction commits, the manager calls the commit() method that TransactionParticipant mandates and an instance of CreditCard implements. If the transaction aborts, then the transaction manager calls abort() instead of commit.
In the simplest terms, BookStore calls CreditCard's debit(), waits for a ChargeConfirmation, and then calls commit() in the Transaction object. Thus, although debit() returns a ChargeConfirmation, that ChargeConfirmation cannot be relied upon until the transaction commits.
Therefore, there are two interaction levels between CreditCard and BookStore: method invocation and a transaction. Method invocation outputs are not reliable -- not final -- until the transaction commits. This is because a transaction is an indivisible set of actions, performed atomically; either all transaction steps succeed, or it must appear to the user that the transaction never took place. For instance, if your credit card charge is accepted, but then the shipping company fails to confirm a book's delivery, you don't want that credit card charge to take effect. In that case, the transaction aborts, causing the credit card charge to appear as though it never took place.
|
Sponsored Links
|