Hi,
I have the following requirement / problem.
I would like to implement a long running transaction that is in sync
with a conversation. I.e. I want to start a transaction when the
conversation starts and commit the transaction when the conversation ends.
So the transaction will be suspended and resumed in between requests.
So far I am able to observe the StartConversationEvent and start a
transaction. But I do not know how then to make sure that the
transaction will be available in the conversation context.
The code is as follows.
@RequestScoped
public class ConversationListener {
@ApplicationScopedDb
@Inject
NakedGraph db;
Transaction transaction;
@ConversationScoped
@Produces
public Transaction getTransaction() {
return this.transaction;
}
public void onStartConversation(@Observes StartConversationEvent
event) {
db.startTransaction();
transaction = db.getTransaction();
// Force producer to be called, to plonk the transaction in the
// conversation
// Like seam 2 outjection
Transaction t = getInstance(Transaction.class);
//This throws a NullPointerException
t.toString();
}
public void onCloseConversation(@Observes CloseConversationEvent
event) {
//The faces listener would have made sure the correct
transaction is associated with this thread
db.stopTransaction(Conclusion.SUCCESS);
}
public <T> T getInstance(Class<T> type, Annotation... qualifiers) {
BeanManager beanManager = getBeanManager();
Bean<T> bean = (Bean<T>)
beanManager.resolve(beanManager.getBeans(type, qualifiers));
CreationalContext<?> ctx =
beanManager.createCreationalContext(bean);
return (T) beanManager.getReference(bean, type, ctx);
}
private BeanManager getBeanManager() {
return BeanManagerProvider.getInstance().getBeanManager();
}
}
The above code does not work, it throws the following exception
Caused by: java.lang.NullPointerException
at
org.apache.myfaces.extensions.cdi.core.impl.scope.conversation.ConversationContextAdapter.get(ConversationContextAdapter.java:100)
at
org.apache.webbeans.context.CustomContextImpl.get(CustomContextImpl.java:48)
at
org.apache.webbeans.context.CustomPassivatingContextImpl.get(CustomPassivatingContextImpl.java:47)
at
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.getContextualInstance(NormalScopedBeanInterceptorHandler.java:127)
at
org.apache.webbeans.intercept.NormalScopedBeanInterceptorHandler.invoke(NormalScopedBeanInterceptorHandler.java:95)
at
org.javassist.tmp.java.lang.Object_$$_javassist_26.toString(Object_$$_javassist_26.java)
If this were to work the idea is then to suspend and resume the code in
faces listeners
@RequestScoped
public class FacesListener {
@ApplicationScopedDb
@Inject
NakedGraph db;
@Inject
Logger logger;
public void beforeFacesRequest(@Observes @BeforeFacesRequest
FacesContext ctx) {
logger.fine("beforeFacesRequest, setting db on thread");
GraphDb.setDb(db);
//Need to check here somehow if a conversation has been started
or not.
Transaction t =
CdiEnvironment.getInstance().getComponent(Transaction.class);
db.resume(t);
}
public void afterFacesRequest(@Observes @AfterFacesRequest
FacesContext ctx) {
logger.fine("afterFacesRequest, suspend transaction and
removing db from thread");
Transaction t = db.suspend();
//Do not need to anything with this transaction as it is
already in the conversation context
GraphDb.remove();
}
}
Hope it makes sense.
Is there a (better) way to do this?
Thanks
Pieter