Sponsored Link •
The JavaSpaces application programming interface integrates Jini transactions in a clean and well-thought-out manner. As a result, introducing transactional security into your JavaSpaces applications is usually fairly painless. To use transactions with space-based operations, typically you first ask a transaction manager to create a transaction and manage it for a specified lease time. Then, you pass the transaction to each space operation you'd like to occur under the transaction (which may include operations over more than one space). Assuming there are no problems along the way, you then explicitly commit the transaction, which results in all operations completing. If any problems occur, you can abort the transaction, which will leave the space unchanged. The transaction might also be aborted by the transaction manager if, for instance, the transaction's lease expires.
When you write an entry into a space under a transaction, the entry is only seen "within" the transaction until it commits. This means that the entry is invisible to any client attempting to read, take, or notify it outside of the transaction. If the entry is taken within the transaction, it will never be seen outside of the transaction. If the transaction aborts, the entry is discarded. Once the transaction commits, the entry is available for reads, takes, and notifications outside of the transaction. For more details, let's look at each space operation and how it operates under a transaction.
Let's start with the
write operation, which takes an entry, a transaction, and a lease:
space.write(Entry entry, Transaction txn, Lease lease);
The operation writes the lease into the space, under the given transaction, and requests the specified lease time for the entry.
You might recall that, up to now in the JavaSpaces series, we've always used a
null transaction as the second parameter to
write, which assumes the operation consists of one indivisible action (the operation itself). As soon as the operation completes, the entry is visible to all clients of the space. On the other hand, when we write an entry under a non-
null transaction, the entry is not accessible to operations outside of the transaction until the transaction commits. If the transaction commits, then all the entries written under the transaction become visible to the entire space. However, if the transaction aborts, the entries written under the transaction are removed. In effect, after the transaction aborts, the space reflects that the operations never occurred.
Now let's look at
read. You will recall that both
read take a template and return a matching entry from the space, if one exists. The
take operation removes the entry before returning it, while the
read operation returns a copy of the entry. When you take or read entries from the space under a transaction, they can come from entries written under or outside the transaction. If the transaction aborts, any entries taken under the transaction are returned to the space (and of course, any entries written under it are removed), leaving the space as if the operations never occurred.
Finally, you can also use
notify under a transaction. When you register for a
notify under a transaction, you receive notifications of entries that are written within the transaction and to the general space. When the transaction completes (whether it commits or aborts), all notification registrations under the transaction are withdrawn. If the transaction commits, the entries remaining in the transaction may result in notifications as response to registrations in the general space. The entries also become eligible for
take operations from the space.
Now that you understand the semantics of using transactions with the space operations, let's move on to creating transactions via the transaction manager, and then write code that makes use of transactions and spaces.