środa, 7 listopada 2012

EJB 3.1 [8]

Timer Service

A timer is associated with the bean that created it and it calls it's ejbTimeout(Timer timer)/@Timeout method when it goes off.
Since EJB 3.1 there is a ScheduleExpression class that allows to define when timer should be fired. There is also @Schedule annotation, that alows to achieve the same in a declarative manner.
EJB must implement TimedObject interface to use Timer Service.
TimerService can be accessed with sessionContext.getTimerService() method. You can create a timer with timerService.createXxxTimer() call (it can create SingleAction, Interval ands Calendar timers).
Alternatively, you can do it in declarative manner with @Schedule annotation:


Timers are persistent - they will be restored if the system crashes. It isn't clear what will happen with the interval timers that would go off several times while the system is down (they may catch up just after the startup).

Timers can be cancelled. To reschedule a timer you cancel it and create a new one. Timer created in the rolledback transaction scope will get uncreated.

Web Services

WIth JAX-RPC there is a lot to define (WSDL, JAX_RPC mapping file and webservices.xml). with JAX-WS all you need is @WebService and @WebMethod annotations.
When there is no @WebMethod annotation - all methods of bean annotated with @WebService are exposed.
@SOAPBinding annotation allows you to customize WS: style: DOCUMENT/RPC, use: LITERAL/ENCODED(do not use), parameterStyle: BARE/WRAPPED.
@WebParam can be placed on parameters (with name and mode: IN/OUT/INOUT attributes). @WebResult is the same for return value.
@OneWay annotation for methods that do not return response allows server to call it asynchronously (if it wishes to).
@WebService annotation has endpointInterface attribute, that allows to separate interface from implementation. We plece @WebService annotation on both the interface and the implementation then.

There is a @WebServiceRef that allows to inject a service class or an endpoint (the annotation would take the service class as an argument then).

piątek, 2 listopada 2012

EJB 3.1 [7]

Transactions

@TransactionAttribute(TransactionAttributeType.REQUIRED)
This annotation can be placen on a bean or on a method. It takes several values (though REQUIRED is the default one):
- NOT_SUPPORTED - Annotated method will alwes run outside transaction scope.
- SUPPORTS - If there is a transaction, it joins it. Otherwise it runs without one.
- REQUIRED - If there is a transaction, it joins. Otherwise it starts a new one.
- REQUIRES_NEW - It always starts a new transaction.
- MANDATORY - If there is no transaction, it throws an exception.
- NEVER - If there is a transaciton, it throws an exception.

MDBs can use only NOT_SUPPORTED (no transaction) and REQUIRED (new transaction). MDB method cannot be invoked within transaction context.
With MDB, the message is a part of the transaction only in case of CMT - this means JMS provider will redeliver it. For BMT the JMS provider will not know of the failure (unless it relies on acknowledgements).
EJB endpoints do not propagate transactions, therefore MANDATORY is forbidden in this case (it can change in the future).

Transactions and PersistenceContext

EM - EntityManager. PC - PersistentContext. SFSB - StateFullSessionBean
- TX-scoped EM called outside transaction will create PC for the method duration. Entities will then become detached.
- Tx-scoped EM called within transaction will create new PC (if there isn't one already) and associate it with transaciton. If PC exists, it will use it. (It applies to injected EMs.)
- If an EJB with tx-scoped PC calls SFSB with extended PC, an error is thrown.
- If SFSB with extended PC calls an EJB with tx-scoped one, extended context is propagated.
- SFSB with extended PC, calling non-injected SFSB with extended PC, will cause an error. For injected one - PC will be shared.

You can specify transaction isolation level using JDBC API (to do so lookup dataSource, then use getConnection method): connection.setTransacitonIsolation(Connection.TRANSACITON_SERIALIZABLE);
If there are many rsources in one transaciton, each can have different isolation level. But for one resource, this level must remain the same in any number of transacitons.

Locking

@Version annotation allows you to use OptimisticLocking. The annotation is placed on a dedicated field, that gets incremented with each update. If at the end of transaction version value is greater than at the beginning - it means that entity has bean changed by someone else - and OptimisticLockingException is thrown.

You can also lock entities manually - EntityManager has method lock (Object entity, LockModeType type), with LockModeTypes: READ and WRITE. It doesn't have to work on entities without @Version field.

UserTransaction

When managing transactins programatically, the most important interface is javax.transaction.UserTransaction. EJB server has to support UserTransaction, though it does not have to support the rest of the JTA. Main methods of UserTransaction:
- begin - throws IllegalStateException if there is already a transaction connected with the thread,
- commit - can throw HeuristicRollbackException or HeuristicMixedException if one of the resources has individually decided to rollback (/commit) transaction,
- getStatus - returns int,
- rollback - can throw SecurityException if the thread is not entitled to rollback transaction,
- setRollbackOnly,
- setTransactionTimeout(seconds) - can be called only after begin. If 0 is passed, the default value will be used.

With CMT you cannot use UserTransaction. All you need here is EjbContext.get/setRollbackOnly.
With BMT you should use UserTransaction.getStatus/rollback instead.

System and application exceptions

SystemExceptions are runtimes (including EjbException) and java.rmi.remoteException.
They can be turned into ApplicationExceptions via @ApplicationException annotation (it has rollback attribute that defaults to false).
SystemException thrown by an EJB always cause a rollback (both with standard and callback methods). The container will discard the EJB after that. If a SFSB is discarded, another call would end in NoSuchEJBException (runtime).

SFSB and SessionSynchronization

If a statefull bean implements SessionSynchronization interface, it has a new lifecycle state - Transactional Method-Ready (the bean knows it's in transaction). THere are new callbacks: afterBagin, beforeCompletion and afterCompletion(boolean comitted).

If a stateful is in transaction and someone calls method with requiresNew/notSupported/never attribure, an error will be thrown.
Calling a @Remove annotated method inside a transaction will also result in an error.
The @beforeCompletion method is not called before rollback. The afterCompletion method is called before both rollback and commit.

Interceptors
Create a class MyAuditor. Write a method taking a InvocationContext argument, returning Object result. Annotate it with @javax.interceptor.AroundInvoke. Then bind it to a bean (or to a method) with @Interceptors(MyAuditor) annotation.
Alternatively, use xml:



Method-params would be needed in case the method is overloaded. If you leave method-name and method-params tags out, the interceptor will be applied to all bean methods. if you use wildcard * as ejb-name, the interceptor will become global. Then, there are @ExcludeDEfaultInterceptors and @ExcludeClassInterceptors annotations.

InvocationContext argument has methods: getTarget (the bean), getMethod, get/setParameters, getContextData(used to pass information between chained interceptors), proceed(causes the target method to execute), getTImer.

You can use @Resource, @EJB and @PersistenceContext annotations in an interceptor, just like if it was a bean.
You can create callback interceptor by putting callback annotation on an interceptor method.
You can also declare @AroundInvoke method in the bean itself. It will be the most "inner" one, thus invoked as the last one.