Stateful EJB Lifecycle question - java

I have the following bean declaration:
#Stateful
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class InteruptBean implements Interrupt {
private boolean interrupt = false;
#Override
public boolean check() {
return interrupt;
}
#Override
public void interrupt() {
interrupt = true;
}
}
I'm trying to understand the Stateful EJB Lifecycle. Once the state of this EJB is permanently modified using the interrupt() method, and all references to this instance are set to null, is the bean instance put back in the eligible pool or is it discarded?
What makes me question my judgement is the TransactionAttributeType.NOT_SUPPORTED. I would hope the container spec says somewhere that a Stateful EJB is reset somehow how to it's initial state before being used again, not matter what the TransactionAttributeType is.
Thanks!

Read http://download.oracle.com/javaee/6/tutorial/doc/giplj.html#gipln.
At the end of the lifecycle, the client invokes a method annotated #Remove, and the EJB container calls the method annotated #PreDestroy, if any. The bean’s instance is then ready for garbage collection.
If nobody ever calls an #Remove method, the container will wait antil a timeout is reached and remove it.
The #TransactionAttribute annotation has nothing to do with the bean's lifecycle. It only tells the container if and when a transaction should be started when one of its business methods is invoked.

#cj91
I am not sure whether the SPEC specifically says what you are asking, i,e
I would hope the container spec says
somewhere that a Stateful EJB is reset
somehow how to it's initial state
before being used again, not matter
what the TransactionAttributeType is.
But I am pretty sure that the transaction attribute type has no impact on how a stateful EJB is (re)initialized.
NOT_SUPPORTED just means that the method cannot be invoked from within a transaction context. If it is invoked, it is silently ignored.
See
http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html

Related

Get caller class in Java CDI Interceptor

I'm trying to implement a cache that holds results from a specific business method call and then refreshes itself every 30 minutes.
I was able to accomplish that by using a singleton EJB using a scheduled method; however, every class that calls that business method now has to instead call the method from the singleton that exposes the cached results.
I want to avoid this behaviour and keep the code from these classes as is, so I thought of using an interceptor that would intercept every call to that particular business method and return instead the results from the cache singleton.
However, this solution has the application stalling since the singleton calls the intercepted business method itself to cache its results, so the interceptor intercepts the call (pardon the repetition) and tries to return the result of the singleton method that exposes the cached values, while the singleton is still waiting for the call to the business method to proceed.
The most obvious solution would be to get the method caller from the interceptor, and check if its
class corresponds to the singleton's; if so, proceed with the call, otherwise return the cached results from the singleton. However, it appears that the InvocationContext object used by the interceptor doesn't expose any methods to access information about the intercepted method's caller. Is there any other way to access the caller's class, or any workaround to this issue?
Here's my singleton class:
#Singleton
#Startup
public class TopAlbumsHolder {
private List<Album> topAlbums;
#Inject
private DataAgent dataAgent;
#PostConstruct
#Schedule(hour = "*", minute = "*/30", persistent = false)
private void populateCache() {
this.topAlbums = this.dataAgent.getTopAlbums();
}
#Lock(LockType.READ)
public List<Album> getTopAlbums() {
return this.topAlbums;
}
}
And here's my interceptor:
#Interceptor
#Cacheable(type = "topAlbums")
public class TopAlbumsInterceptor {
#Inject
private TopAlbumsHolder topAlbumsHolder;
#AroundInvoke
public Object interceptTopAlbumsCall(InvocationContext invocationContext) throws Exception {
// if the caller's class equals that of the cache singleton, then return invocationContext.proceed();
// otherwise:
return this.topAlbumsHolder.getTopAlbums();
}
}
Note that the #Cacheable annotation is a custom interceptor binding, not javax.persistence.Cacheable.
EDIT: I modified the interceptor method that way:
#AroundInvoke
public Object interceptTopAlbumsCall(InvocationContext invocationContext) throws Exception {
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace())
if (TopAlbumsHolder.class.getName().equals(stackTraceElement.getClassName()))
return invocationContext.proceed();
return this.topAlbumsHolder.getTopAlbums();
}
But I doubt that's the cleanest solution, and I don't know if it's portable.
EDIT 2: In case it is not clear enough, I need to access information about the invoker class of the intercepted method, not the invoked class that has its method intercepted; that's why I'm iterating over the stack trace to access the invoker's class, but I reckon this is not an elegant solution, even though it works.
For what you need to do, I'd say use either interceptor or decorator.
Your interceptor is however wrong. Firtly you are missing the basic part, which is a call to InvocationContext.proceed() that forwards the call to next-in-line interceptor (if there is any) or the method call itself. Secondly, the injection point you placed there is very specific and would only help you if you intercept this very type of bean. Typically, an around invoke interceptor method looks like this:
#AroundInvoke
Object intercept(InvocationContext ctx) throws Exception {
// do something before the invocation of the intercepted method
return ctx.proceed(); // this invoked next interceptor and ultimately the intercepted method
// do something after the invocation of the intercepted method
}
Furthermore, if you want metadata information about what bean was intercepted, every interceptor can inject a special built-in bean just for that. From the metadata, you can gather information on what bean you're currently intercepting. Here is how you get that metadata:
#Inject
#Intercepted
private Bean<?> bean;
Note that interceptors are unaware of what type they intercept, it can be anything and hence you usually need to operate on plain Object.
Should you need something more specific, CDI offers a Decorator pattern which in basically a type-aware interceptor. It has a special injection point (a delegate) that gives you direct access to the decorated bean. It might possibly fit your scenario even better, take a look at this part of CDI specification explaining Decorators.
There is a misunderstanding.
You don't inject the Object which gets intercepted into the interceptor, but use the invocationContext.
You just need to call invocationContext.proceed() then there is no recursion.
The result of proceed() you can cache.
Iterate over the stack trace to check on TopAlbumsHolder exists isn't a good way.
To escape invoking the interceptor during calling the getTopAlbums() from DataAgent class you can specify the scheduler direct in the DataAgent which gathers the data and push it into TopAlbumsHolder. You can do it another way, but your main point direct invoking the getTopAlbums() within the DataAgent bean without participating proxy (in this case, the interceptor won't apply).
P.S. Pay attention that cached data should be immutable (both the collection and its objects).

Can I call a method with TransactionAttributeType.REQUIRED from another method with TransactionAttributeType.NOT_SUPPORTED in same EJB

I have a following code structure, I need guidence on how to start a local transaction cascaded from a NOT_SUPPORTED transaction type method in same EJB.
#Stateless
#TransactionManagement(value = TransactionManagementType.CONTAINER)
public class SessionBean implements SessionBeanInterface{
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void methodA() {
methodB();
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void methodB() {
}
}
Currently when I try this i get below exception.
No active transaction for PuId=App#EJB.jar#Persistence
The way you have called "methodB" would not give a chance to the EJB Container to start a transactional context for you. To do that you have to invoke that method through either Remote or Local views/interface.
It is the container who supplies you these additional features and hence it is necessary to route your calls through interface than. (On a side note this is Proxy Design Pattern).
If you directly call "methodB" as you have done in above code snippet, it is just another method call without container intervention.

start transaction AFTER not BEFORE start of synchronized method in singleton bean

I have a war file deployed in glassfish. We have a Singleton bean and we have 1 synchronized method in it.
#TransactionAttribute (TransactionAttributeType.REQUIRED)
public synchronized void do()
{
...
}
However, I am noticing that transaction is started before the method is called. How do I start a transaction after the caller obtains the lock on the bean class' monitor?
Thank you.
Update: We are just trying to have a bean method that can only be called by one thread at a time. We do not want any other thread to call this method until the previous thread is completely done with it. I had created another thread where I got the idea of using a singleton bean: synchronized method in stateless session bean not working as expected in glassfish
Update: After doing some reading, it seems I can create my own transactions UserTransaction. Will that be supported? Never mind. I got this error message:
Only session beans with bean-managed transactions can obtain UserTransaction
I think one way would be to move the synchronization out of the bean by wrapping the call to the method inside another bean (YourBean would be the interface of your bean class):
public class WrapperBeanImpl implements WrapperBean {
private YourBean yb;
private final Object lock;
#Resource
private SessionContext ctx;
#PostConstruct
public void init() {
yb = ctx.getBusinessObject(YourBean.class);
}
#TransactionAttribute(TransactionAttributeType.NEVER)
public void synchronizedDo() {
synchronized(lock) {
yb.do();
}
}
}
(Example slightly modified from http://www.javahelp.info/2009/11/01/using-transactionattribute-in-submethods-on-same-ejb3-beans/ )
Of course, this does not really stop anyone from calling the do() method directly bypassing this extra synchronization, although that may not be a problem. You also have the option of leaving the synchronization in your bean as an extra safeguard.
Just use #ConcurrencyManagementType(CONTAINER) on a class level and container will maintain synchronization. And use methond without synchronized directive.

Spring #Transactional multiple threads

I have a method A running in the transactional scope which:
Modifies an entity A to switch from state A to state B
Passes a task to a executor service that expects an Entity to be in state B when executed
The problem is when this task is run (that thing I have no control of) before the method A commits, it doesn't see the required state changed because it does not block until the method A level transaction ends.
Task is run using a spring bean and #Transactional-annotated method like this:
#Service
public class TransactionalProcessingAdapter implements ProcessingAdapter {
#Override
#Transactional
public void execute(ProcessingAdaptedMethod processingAdapter) {
processingAdapter.execute();
}
}
What am I doing wrong? Thanks!
The thing is that Spring transactions are thread bounded - eg a transaction is visible inside its initial threads only. ThreadLocal is used to implement that property.
You might want to implement your own TransactionSynchronizationManager in Spring and inject it. Use something like InheritableThreadLocal instead of ThreadLocal.

Container-managed transaction in JAX-WS, weblogic

I'm trying to use Container-Managed Transactions inside webservice, but transaction isn't created. I have something like that:
#WebService(...)
#Stateless
#TransactionManagment(TransactionManagmentType.CONTAINER)
public class ExampleService {
// EntityManager and other fields
#TransactionAttribure(TransactionAttributeType.REQUIRED)
public void test(String s){
// persist something with EntityManager
}
}
When I call this method, I get javax.persistence.TransactionRequiredException: The method public abstract void javax.persistence.EntityManager.persist(java.lang.Object) must be called in the context of a transaction.
What am I doing wrong?
Thanks!
From what I recall 'TransactionAttributeType.REQUIRED' means that method should be only called when transaction is already in progress for current thread (in other words 'called in context of transaction'). It's not clear who if anybody starts transaction in your case. If nobody then the exception you're getting makes perfect sense.
Now I'm not sure how or is it even currently possible to propagate transaction across Web services call. I don't think this is particularly good idea to do so even if possible.
Perhaps you what you need TransactionAttributeType.REQURES_NEW in your case so Container would start the transaction before passing control to your annotated method?

Categories

Resources