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
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
|
@TransactionAttribute | This tells the container how to handle the transaction, there are six choices, see below for more information
|
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, @ApplicationException(rollback=false) 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 |
BMT allows you to specify exactly where the transaction starts, ends, commits and rolls back, using the javax.transaction.UserTransaction interface.
BMT example | @Stateless |
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 { Note: |
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.
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) { ... } } |