All Jetspeed components that use the database are transactional. This guide helps you learn about how Jetspeed components are wired together in the context of Spring transactions. When deploying Jetspeed, you may need to modify some of the componnents that are transactional. This guide will help you understand how to configure transactional beans (services) in Jetspeed.
Transactions allow you to group several operations into a single unit of work that either fully happens or fully doesn't happen. Jetspeed leverages the Spring Framework to make its components transactional. The Spring Framework provides the transaction management required to execute transactions across two or more Jetspeed components. Jetspeed transactions are configured as declarative transactions. Jetspeed currently does not make use of programmatic transactions. The Spring Framework provides the declarative transaction management through Spring's AOP framework. Spring provides three ways to declare transactional boundaries in the spring configuration.
Lets take one example of a transaction Jetspeed service: the Permission Manager service. This service is configured in the security-managers.xml
file.
The first bean is actually named with a Impl
suffix. This is because this is the implementation bean:
the bean name org.apache.jetspeed.security.impl.PermissionManagerImpl
is the same name as the class. Class attributes
represent the class name of the implementing class.
The second bean is named by interface: org.apache.jetspeed.security.PermissionManager
. This bean is not the actual
Permission implementation. The bean definition is a transactional proxy: it is an bean wrapper or interceptor. When wiring the
Permission Manager to another Jetspeed service, make sure to use the proxy object, not the actual implementation. This ensures
that declarative transaction support in Spring can intercept calls to the Permission Manager.
Notice that the parent bean is baseTransactionProxy
. This is how we get the transactional support: through Spring AOP
inheriting the base functionality for proxying transactions declaratively.
<!-- Security: Permission Manager --> <bean id="org.apache.jetspeed.security.impl.PermissionManagerImpl" class="org.apache.jetspeed.security.impl.PermissionManagerImpl" /> <bean id="org.apache.jetspeed.security.PermissionManager" parent="baseTransactionProxy" name="permissionManager" > <property name="proxyInterfaces"> <value>org.apache.jetspeed.security.PermissionManager</value> </property> <property name="target"> <ref bean="org.apache.jetspeed.security.impl.PermissionManagerImpl"/> </property> <property name="transactionAttributes"> <props> <prop key="remove*">PROPAGATION_REQUIRED</prop> <prop key="grant*">PROPAGATION_REQUIRED</prop> <prop key="revoke*">PROPAGATION_REQUIRED</prop> <prop key="grant*">PROPAGATION_REQUIRED</prop> <prop key="add*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="*">PROPAGATION_SUPPORTS</prop> </props> </property> </bean>
There are several transactional attributes that control the behavior of transactions on the wrappered bean
add*
. Then the body of the tag can contain
either PROPAGATION_REQUIRED or PROPAGATION_SUPPORTS keywords, as well as exception handling behavior described below.
Transaction Propagation Required - If propagation is required, then the method is required to be a part of a transaction. If, when the method is called, there is not an active transaction, a transaction will be immediately started by the proxy (interceptor). Methods that store to a persistent database are usually marked as propagation required.
Transaction Propagation Supported - If propagation is only supported, then the method is NOT required to be a part of a transaction. If, when the method is called, there is not an active transaction, a transaction will be NOT be started by the proxy (interceptor). If there is a transaction active, the method will join the transaction. Methods not marked with either required or supported properties will not participate in transactions.
Exception Handling and Rollback -
Transactions can also be committed or rolled back based on one or more Exception classes. In the example below
we use -
, the minus sign, to denote that any RegistrationExceptions
that occur on any methods that start with register*
will cause the transaction to rollback. On the contrary, using a +
, a plus sign, will cause the transaction
to commit for the given method and exception.
<property name="transactionAttributes"> <props> <prop key="register*">PROPAGATION_REQUIRED,-org.apache.jetspeed.administration.RegistrationException</prop> </props> </property>
Transactions can be nested when one service calls another service. Take for example, the User Registration portlet which uses
the Jetspeed Administration service method named registerUser
. User registration requires transactional calls to
both the Permission Manager and the User Manager. The transaction begins on the Jetspeed Administration service, calls into the
Permission Manager to the grantPermission method, and then the User Manager's storeUser method. If any of these methods fails,
the entire transaction is rolled back. If all methods succeed, the transaction is committed as shown below.