Transactions and Security

In this subject we discuss transactions and examine container-managed and bean-managed transactions support in EJB, we also discuss EJB security.

A transaction is a grouping of tasks that must be processed as an inseparable unit, this means every task that is part of the transaction must succeed in order for the transaction to succeed, if any of the tasks fail the transaction fails as well. Transactions properties consist of the atomicity, consistency, isolation and durability, otherwise known as the ACID tests (see below table for more information). If a transaction is successful then the transaction is committed otherwise it is rolled back.

Atomicity This means that all parts of the transaction must complete successfully for the transaction to succeed, if any part fails then the transaction fails.
Consistency This states that if a system is in a state consistent with the business rules before a transaction begins, it must remain in a consistent state after the transaction is either rolled back or committed. However the system can be in a in-consistent state during a transaction. You are protected against the business rules while inside a transaction but as long as you make sure all the business rules are intact after the last line of code in the transaction is executed. Examples of business rules include primary keys, foreign key relationships and field constraints which ensure consistency so that transactions encountering errors conditions are rejected and the system is returned to its pre-transactional state.
Isolation

Isolation means that while you are in your transaction nobody else can touch it, databases use locking to protect data that you are changing and until you either roll back or commit your work nobody will be able to see it.

There are number of levels of isolation

  • Read Uncommitted - your transaction can read the uncommitted data of other transactions also known as a dirty read.
  • Read Committed - Your transaction will never read uncommitted changes from other transactions
  • Repeatable - The transaction is guaranteed to get the same data on multiple reads of the same rows until the transaction ends
  • Serializable - Guarantees that none of the tables your touch will change during the transaction, including adding new rows.

Serializable would cause the most performance bottlenecks, most databases default to using Read Committed and you should never use Read Uncommitted in a multi-threaded environment.

Durability Durability means that once you commit your transaction it is guaranteed to be made permanent, which means if the system where to crash then your transaction is safe. Databases use log files to keep track of all changes and replay these logs in the event of a system failure.

When using transactions the enterprise transaction management which is the component that takes care of transactions for a particular resource, is called the resource manager, the resource manager may not only attach to a database like Oracle, it could possibly attach to message server. Most applications attach to a single resource (database in this case) and this single resource is called a local transaction. If the application uses multiple resources you need to manage both resources under a single transaction and you use a transaction manager to start commit and roll back transaction, the transaction manager is a component that under the hood coordinates a transaction over multiple distributed resources. To handle a transaction over multiple resources we use a protocol called a two-phase commit. During a two-phase commit each resource manager involved is asked if the current transaction can be successfully committed, if any of the resource managers indicate that it cannot complete the entire transaction is aborted (rolled back).

The protocol that achieves this two-phase commit is the XA protocol, which is developed by the X/Open group.

To recap here is a simple table

Property
Local
Global Transaction
Number of Resources
One
Multiple
Coordinator
Resource Manager
Transaction Manager
Commit protocol
Single-Phase
Two-Phase

Transaction management support in EJB is provided through the Java Transaction API (JTA), it is a small API exposing the transaction manager layer. You will probably only need to know one interface javax.transaction.UserTransaction, this is because the container takes care of most of the transaction management details behind the scenes, you just tell the container were the transaction begins and ends.

There are two ways of using transactions

Container Managed Transactions (CMT)

In a CMT the container starts, commits and rolls back a transaction on our behalf, we however must tell the container how to manage the transaction by using either deployment descriptors or annotations and ask it to rollback the transaction when needed. There are two annotations that you use for transactions

@TransactionManagement

specifies if CMT or BMT is used for a particular bean, the default is CMT, the options are

  • TransactionManagementType.CONTAINER
  • TransactionManagementType.BEAN
@TransactionAttribute

This tells the container how to handle the transaction, there are six choices, see below for more information

  • REQUIRED (MBD only)
  • REQUIRES_NEW
  • SUPPORTS
  • MANDATORY
  • NOT_SUPPORTED (MDB only)
  • NEVER
TransactionAttributes
REQUIRED means the method must always be invoked in a transaction, either creating a new one or joining an existing one, this creates a single umbrella transaction.
REQUIRES_NEW means that the method will always create a new transaction, if the client already has a transaction, it is temporary suspended until our method returns. The success of the newly created transaction has no affect on an existing transaction.
SUPPORTS will inherit whatever transactional environment of the caller is, if it does not have one then no transaction is used, if it joins an already existing transaction it will not cause it to suspend
MANDATORY means that a transaction must already exist if one does not then an EJBTransactionRequiredException error is thrown.
NOT_SUPPORTED means that the method will not run in an transaction, if one already exists then this is suspended until the method completes then resumes., this is useful for an MDB supporting a JMS provider in a non-transactional, autoknowledge mode.
NEVER means that it cannot be invoked by a transactional client, otherwise a EJBException is thrown.
Example
example @Stateless
// Uses CMT
@TransactionManagement(TransactionManagementType.CONTAINER);
public class orderManagerBean {

  // Injects EJB context
  @Resource
  private SessionContext context;


  // Defines transaction attribute for method
  @TransactionAttribute(TransactionAttributeType.REQUIRED);
  public void placeOrder(Item item, Customer customer) {
  
    try {
           ... some code here ...
    } catch (CreditValidationException cve ) {
        context.setRollbackOnly();
    } catch (DatabaseException de ) {
        context.setRollbackOnly();
    }
}

Here is a scenario table

Transaction Attribute
Caller Transaction Exists
Effect
REQUIRED
No
Container creates a new transaction
 
Yes
Method joins the callers transaction
REQUIRES_NEW
No
Container creates a new transaction
 
Yes
Container creates a new transaction and the callers transaction is suspended
SUPPORTS
No
No transaction is used
 
Yes
Method joins the callers transaction
MANDATORY
No
javax.ejb.EJBTransactionRequiredException is thrown
 
Yes
Method joins the callers transaction
NOT_SUPPORTED
No
No transaction is used
 
Yes
The callers transaction is suspended and the method is called without a transaction
NEVER
No
No transaction is used
 
Yes
javax.ejb.EJBException is thrown

A note worth remembering is that when a transaction is marked for rollback, the transaction is not rolled back immediately, but a flag is set for the container to do the actual rollback when it is time for the transaction to end. You can use the EJBContext method getRollbackOnly to obtain if the flag has been set, this will either be true or false, it can only be used if the transaction attributes are either: REQUIRED, REQUIRES_NEWor MANDATORY, try to only use this method when you are going to be running very long resource-intense operations.

getRollbackOnly example if (!context.getRollbackOnly ()) {
  ...
}

You can handle exceptions very well in EJB 3, you can control the transactional outcome through the @javax.ejb.ApplicationException annotation, an example is below, however the more verbose example above removes alot of the guess work and is easier to understand.

@ApplicationException

public void placeOrder(Item item, Customer customer) throws CreditValidationException,
   CreditProcessingException, DatabaseException {

  ......
}

@ApplicationException(rollback=true)
public class CreditValidationException extends Exception {
  ...
}

@ApplicationException(rollback=true)
public class CreditProcessingException extends Exception {
  ...
}

@ApplicationException(rollback=false)
public class DatabaseException extends RuntimeException {
  ...
}

Note: setting the element to true tells the container that it should rollback the transaction before the exception is passed onto the client by default it is set to false

Bean-Managed Transactions

BMT allows you to specify exactly where the transaction starts, ends, commits and rolls back, using the javax.transaction.UserTransaction interface.

BMT example

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class OrderManagerBean {

  // Injects UserTransaction
  @Resource
  private UserTransaction userTransaction;

  public void placeOrder(Item item, Customer customer) {

    try {
        // Starts the transaction
        userTransaction.begin;
        ...
        // Commits the transaction
        userTransaction.commit();
    } catch (CreditValidationException cve ) {
        userTransaction.setRollbackOnly();
    } catch (DatabaseException de ) {
        userTransaction.setRollbackOnly();
    }

A UserTransaction the JTA representation of a BMT is injected and then used explicitly to begin, commit or roll back a transaction, as you can see the transaction is smaller than the entire method. You can also obtain the UserTransaction via either JNDI lookup or EJBContext

UserTransaction - JNDI lookup Context context = new InitialContext();
UserTransaction userTransaction = (UserTransaction) context.lookup("java:comp/UserTransaction");
userTransaction.begin();
...
userTransaction.commit();
UserTransaction - EJBContext @Resource
private SessionContext context;
...
UserTransaction userTransaction = context.getUserTransaction();
userTransaction.begin();
...
userTransaction.commit();

The UserTransaction interface is below

UserTransaction interface

public interface UserTransaction {

  void begin() throws NotSupportedException, SystemException;
  void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,              SecurityException, IllegalStateException, SystemException;

  void rollback() throws IllegalStateException, SecurityException, SystemException;

  void setRollbackOnly() throws IllegalStateException, SystemException;

  int getStatus() throws SystemException;
  void setTransactionTimeout(int seconds) throws SystemException;
}

Note:
begin - creates new low-level transaction behind the scenes and associates it with the current thread
commit - sends a "success" signal to the underlying transaction manager
rollback - abandons the current transaction
setRollbackOnly - marks the transaction for rollback, which means it cannot commit
getStatus - get the status of the transaction of the current thread
setTransactionTimeout - modify the timeout value, a transaction must finish by this time

getStatus() status values
STATUS_ACTIVE The transaction is still active
STATUS_MARKED_ROLLBACK transaction is marked for rollback, possibly due to the setRollbackOnly method being invoked
STATUS_PREPARED the transaction is in the prepare state because all resources have agreed to commit (two-phase commit)
STATUS_COMMITTED the transaction has been committed
STATUS_ROLLEDBACK the transaction has been rolled back
STATUS_UNKNOWN the transaction is in a unknown state
STATUS_NO_TRANSACTION there is no transactions in the current thread
STATUS_PREPARING the transaction is preparing to be committed and awaiting response from subordinate resources
STATUS_COMMITTING the transaction is in the process of committing
STATUS_ROLLING_BACK the transaction is in the process of rolling back

CMT is the default transaction type for EJB transactions, in general BMT should be used sparingly because it is verbose, complex and difficult to maintain.If you are using a stateful session bean and need to maintain a transaction across method calls, BMT is your only option.

Whatever method you use the best tip for transaction is to hold the transaction for the shortest period of time.

EJB Security

I will only touch on this subject as I have already discussed it in my JBoss Enterprise Application section, basically there are two areas that are addressed in security

As with most containers we use users, group and roles to give privileges to, I have covered this concept in my Tomcat Security section.

Java EE security uses the Java Authentication and Authorization Service (JAAS) API, JAAS can also use LDAP, Active Directory or Oracle Internet Directory (OID) to provide the user, group and role information. JAAS is designed so that both the authentication and authorization can be performed at any Java EE tier, including the web and EJB tiers. Most Java EE applications are web accessible and share an authentication system across tiers, the Principle object represents this sharable, validated authentication context. A Principle is associated with one or more roles, and depending on what privileges the role has gives you access to resources, the Principle is passed from the web tier to the EJB tier as needed.

To recap from my other sections there are a number of annotations that can be used, see JBoss Enterprise Application section for examples

@DeclareRoles
Class or Method
it declares what roles can be used within this resource, if no roles are declared, by default, a list is automatically generated by using the @RolesAllowed annotation
@RolesAllowed
Class or Method
specifies what roles are allowed to use this resource, you can override the class definition using method definitions
@PermitAll
Class or Method
specifies that any user can access the class or method, use this sparingly as it is a security hole
@DenyAll
Class or Method
specifies that no users can access the class or method
@RunAs
Class or Method
you can dynamically assign a new role to the existing Principle in the scope of the EJB method invocation, use this sparingly as it is a security hole

There are two methods in the javax.ejb.EJBContext that can be used to obtain security information

getCallerPrinciple() @Resource SessionContext context;
...
public void cancelBid(Bid bid, Item item) {

  if(context.getCallerPrinciple().getName().equals("vallep") {
     ..
  }
}
isCallerInRole(String <rolename>) @Resource SessionContext context;
...
public void cancelBid(Bid bid, Item item) {

  if(!context.isCallerInRole("ADMIN")) {
     ..
  }
}

You can of course use interceptors which is ideal for cross-cutting concerns, I have already discussed interceptors in more detail in my EJB 3 Advanced topic.

security interceptor example # The Interceptor class
public class SecurityInterceptor {

  @AroundInvoke
  public Object checkUserRole(InvocationContext context) throws Exception {
     if (!context.getEJBContext().isCallerInRole("ADMIN")) {
       throw new SecruityException("No permission to update bid");
     }

     return context.proceed();
  }
}

#
@Stateless
public class BidManagerBean implements BidManager {

  @Interceptors(actionbazzar.security.SecurityInterceptor.class);
  public void updateBid(Bid bid, Item item) { ... }
}