9.3. Web Counter Revisited

With this groundwork behind us, it is now time for an example. Below we've taken the web counter applet and updated it to use transactions; you might first turn back to the previous version (see Section 3.2.3) to refamiliarize yourself with the original code before taking a look at this version. After we have stepped through this example, and have a feel for how transactions are used, we will study the various APIs and semantics of transactions in detail.

Here is the code for the transaction-based web counter applet:

public class WebCounterClient extends Applet {
  private WebCounter counter;

  public void init() {
    JavaSpace space = SpaceAccessor.getSpace();
    String url = getDocumentBase().toString();

    TransactionManager mgr =
      TransactionManagerAccessor.getManager();

    Transaction.Created trc = null;
    try {
       trc = TransactionFactory.create(mgr, 3000);
    } catch (Exception e) {
      System.err.println(
        "Could not create transaction " + e);
      return;
    }

    Transaction txn = trc.transaction;

    WebCounter template = new WebCounter(url);
    try {
       try {
          // take counter under a transaction
          counter = (WebCounter)
            space.take(template, txn, Long.MAX_VALUE);

          counter.increment();

          // write back counter under a transaction
          space.write(counter, txn, Lease.FOREVER);
        } catch (Exception e) {
           System.err.println("Not written into space " + e);
           txn.abort();
           return;
        }

           txn.commit();
        } catch (Exception e) {
           System.err.println("Transaction failed");
           return;
        }
      }

      public void paint(java.awt.Graphics gc) {
        if (counter != null) {
           Integer count = counter.getCount();
           gc.drawString("Page visited " +
              count +  " times before.", 20, 20);
      }
    }
  }

If you refer back to the original code, you'll see the changes we made to add transactions are fairly minimal. Stepping through the code, we first obtain a reference to a space and then obtain the URL of the web page for which we are displaying the counter.

We then obtain a transaction using the same steps we described in the previous section: We obtain a reference to a transaction manager, ask it to create a transaction and then obtain a reference txn to the transaction object.

Once we have a transaction in hand, we are ready to retrofit the space operations to work under it. Before doing so, we first create a template that will be used for taking the counter entry from the space. Then we call the take method: Instead of passing a null transaction parameter, as we've been doing, we specify the transaction txn. Then we increment the counter (a local operation) and write it back to the space, again supplying txn for the transaction parameter.

When we execute the take and write operations under the txn transaction, three things can happen. One possibility is that the operations complete without any exceptions, and we attempt to commit the transaction by calling the transaction's commit method:

txn.commit();

When this method is called, the transaction manager is asked to commit the transaction. If the commit is successful, then the operations invoked under the transaction occur in the space as one atomic operation.

The second possibility is that an exception may occur during the write or take operations, and in this case we attempt to abort the transaction in the catch clause. If the abort is successful, then no operation occurs in the space.

A third possibility is that an exception may be thrown in the process of committing or aborting the transaction. In these cases, the outer catch clause catches the exception and prints a message indicating the transaction failed. The transaction will expire when its lease time ends (in this case after three seconds), and no operations will occur. The transaction will also expire if this client unexpectedly dies or becomes disconnected from the network during the sequence of calls.

In a short amount of code we've seen the steps needed to use transactions with spaces:

  • Obtain a reference to a transaction manager.

  • Create a transaction by specifying a manager and lease time to the TransactionFactory.create method, which returns a Transaction.Created object.

  • Obtain a reference to the transaction through the Created object.

  • Pass the transaction to all operations you'd like performed under it.

  • Commit the transaction when finished, or abort it if something goes wrong.

Now that we've had a taste of transactions, let's understand the details a little better.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset