| Sign In/My Account | View Cart |
J2EE provides a great deal of functionality besides servlets. Servlet developers may be reluctant to use such features, neither willing nor having time to replace their simple servlet containers with a big J2EE server that provides more than what they need. However, given the modular nature of J2EE, it is possible to enhance web applications by integrating small components responsible for specific J2EE features into servlet containers. One such feature is transactions.
For a complete description of J2EE transactions, you should have a look at the three ONJava articles about it. For now, just keep in mind that a transaction is a sequence of operations on resources (for example, a database) defined by four properties, often referred to as ACID due to their initials:
JOTM (Java Open Transaction Manager) is a fully functional, open source standalone transaction manager developed by the ObjectWeb consortium. It provides transaction support for Java applications and is compliant with JTA, the Java Transaction API. You can find out more details on the JOTM home page. Integrating JOTM in Tomcat (or any servlet container) makes it possible for JSP and servlet developers to take advantage of transactions in a lightweight way to create more robust web applications.
To highlight how transactions can enhance web applications, consider the classical scenario of an ATM that uses a web browser to interact with the client.
The use case is simple: a client wants to withdraw money from an ATM. He
gives his client name, john_doe, and the amount of money he wants
to withdraw, $50. If he has enough money on his bank account and
if there is enough available cash in the ATM, the application gives him the
cash and withdraws the amount from his bank account. Otherwise, the operation
aborts and nothing happens except an error message. To focus on transactions
and to keep things simple, we will not worry about security issues, instead
assuming that the user is correctly authenticated.
This very simple example is surprisingly hard to implement in a robust way without transactions. One client operation involves two different resources: the ATM and the client's bank account. This automatically introduces ACIDity issues in the application design. For example, if the operation succeeds on the ATM and fails on the bank account (perhaps due to a communication failure), the client will have the cash but his account won't be updated. Bad news for the bank.
Even worse, if the bank account is correctly updated but an error prevents the ATM from delivering the money, the client won't have the cash, but the money will be withdrawn from his account.
To prevent such cases, in your application, you can 1) contact the two resources and inform them about all of the current operations performed by the client, 2) ask them if they can perform the operations, and, 3) if they both agree, ask them to perform the operations. Even this solution is not robust enough, however, if money is withdrawn from the client's bank account by another operation between the second and third steps. It is possible that the money withdrawal fails, for example, if the client can't have a negative balance.
That's where transactions can make your application more simple and robust: by performing all of the operations on the two resources within one transaction, they will solve the ACIDity issues (especially Atomicity) for you.
Data Layer
At the data layer, we have two different databases and one table in each database. To make the example more realistic, we've used two different databases because it is possible to withdraw from an ATM not owned by the client's bank (see below to configure the databases).
banktest contains the account table, representing
client accounts.atmtest contains the atm table, representing the
ATM.Logic Layer
At the logic layer, we have three classes accessing the resources and performing operations on them:
foo.BankAccount represents the bank account of a given client
and performs database operations on the account table through
JDBC.bar.ATM represents the ATM and performs the JDBC operations on
the atm table.bar.CashDelivery uses the two previous classes to perform a
client operation.All of the logic is done in the deliverCash method of
CashDelivery.java.
The javax.transaction.UserTransaction interface is used to
demarcate the transaction. All of the operations between utx.begin()
and utx.commit() (or utx.rollback()) are executed
within one transaction. This ensures that your web application won't suffer of
the shortcomings discussed previously.
Thanks to transactions, the application logic is much simpler, and consists of these simple steps:
Example 1. CashDelivery.java
public boolean deliver(String client, int value) {
InitialContext ctx = new InitialContext();
UserTransaction utx = (UserTransaction)
ctx.lookup("java:comp/UserTransaction");
...
boolean success = false;
try {
// begin the transaction
utx.begin();
// contact the bank of the client...
BankAccount account = new BankAccount(client);
// ... and withdraw the value from his account.
account.withdraw(value);
// contact the ATM...
ATM atm = new ATM();
// ... and deliver the cash to the client.
atm.deliverCash(value);
// everything went ok.
success = true;
} catch (Exception e) {
// something went wrong, we have to
// report it to the client
explanation += e.getMessage();
} finally {
try {
if (success) {
/* everything was ok, we commit the transaction.
* only now, the money will be effectively withdrawn
* from the account and the cash delivered to the client.
*/
utx.commit();
} else {
/* something went wrong, we rollback the transaction.
* none of the operations done within the transaction
* have been done.
*/
utx.rollback();
}
} catch (Exception e) {
/* something went wrong during the completion of the transaction.
* we're still guaranteed that none of the operations done within
* the transaction have been done/
*/
// we have to report it to the client
explanation += "\n" + e.getMessage();
// finally, the transaction was not a success
success = false;
} finally {
return success;
}
}
}
Presentation Layer
At the presentation layer, the application is composed of two JSP files:
atm.jsp, the Cash Delivery application, which sends to the
bar.CashDelivery class the client's login and the amount of cash
to withdraw, and displays the result of the client's operation.admin.jsp, the Management Console used to show and update
information related to the two resources. (It is not really a part of the
application design, but has been added to simplify resource updates, such as to
deposit money on a client's account.)
Figure 1. Application Design
Pages: 1, 2 |