Hi,
Here is the solution that with Gerhard's help is working well.
Firstly using the StartConversationEvent does not work as it creates a
logical cycle (observing a event it produces).
Create a conversation scoped transaction wrapper class which starts the
transaction on @PostConstruct and commits the transaction on @PreDestroy
Then in a listener class which observes @BeforeFacesRequest inject the
transaction wrapper class. This will start the transaction if a
conversation/transaction is not active.
I used a threadvar to tell if the conversation/transaction was created
in this thread, if so do nothing otherwise resume the transaction.
In a method that observes @AfterFacesRequest suspend the transaction.
I created a dedicated conversation group for the
conversation/transaction scoped wrapper class. On any action that
requires the transaction to be committed I then call
windowContext.closeConversationGroup(TransactionConversationGroup.class);
Thanks
Pieter
On 03/08/2011 10:46, Gerhard Petracek wrote:
hi pieter,
since it's quite different from the classical approach and it depends on the
concrete usage, i would suggest that we talk about it in our irc channel
(afterwards we post the solution).
regards,
gerhard
http://www.irian.at
Your JSF powerhouse -
JSF Consulting, Development and
Courses in English and German
Professional Support for Apache MyFaces
2011/8/3 Gerhard Petracek<[email protected]>
hi pieter,
ok - in this case that won't work (that's a logical cycle).
i thought more about a producer which creates a dependent scoped
transaction. however, as i see that won't help you in this special case.
imo something like a lazy transaction should work. i'll think about it and
create a demo.
regards,
gerhard
http://www.irian.at
Your JSF powerhouse -
JSF Consulting, Development and
Courses in English and German
Professional Support for Apache MyFaces
2011/8/3 Pieter Martin<[email protected]>
Hi,
The code below does have a producer for the transaction. But it threw an
exception.
I changed the code slightly now but am still getting the same exception.
public class ConversationListener {
@ApplicationScopedDb
@Inject
NakedGraph db;
@ConversationScoped
@Produces
public Transaction getTransaction() {
db.setTransactionMode(Mode.**MANUAL);
db.startTransaction();
return db.getTransaction();
}
public void onStartConversation(@Observes StartConversationEvent event,
Transaction t) {
System.out.println(t);
}
public void onCloseConversation(@Observes CloseConversationEvent event)
{
db.stopTransaction(Conclusion.**SUCCESS);
}
}
The StartConversationEvent is fired but the transaction parameter can not
be resolved. Getting 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.**NormalScopedBeanInterceptorHan**
dler.getContextualInstance(**NormalScopedBeanInterceptorHan**
dler.java:127)
at org.apache.webbeans.intercept.**NormalScopedBeanInterceptorHan**
dler.invoke(**NormalScopedBeanInterceptorHan**dler.java:95)
at org.javassist.tmp.java.lang.**Object_$$_javassist_26.**
toString(Object_$$_javassist_**26.java)
at java.lang.String.valueOf(**String.java:2838)
at java.io.PrintStream.println(**PrintStream.java:788)
at org.nakeduml.environment.**ConversationListener.**
onStartConversation(**ConversationListener.java:38)
Not sure why the producer method can not be called. Is the producer method
incorrect, does it need a qualifier?
Thanks
Pieter
On 02/08/2011 21:19, Gerhard Petracek wrote:
hi pieter,
the concept of outjection is deprecated.
you could create a producer method for the transaction.
if you need the transaction in an observer, you just have to add it as
additional parameter and the produced transaction will be injected into
the
observer method by cdi.
regards,
gerhard
http://www.irian.at
Your JSF powerhouse -
JSF Consulting, Development and
Courses in English and German
Professional Support for Apache MyFaces
2011/8/2 Pieter Martin<[email protected]**>
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.******
NormalScopedBeanInterceptorHan****
dler.getContextualInstance(****NormalScopedBeanInterceptorHan****
dler.java:127)
at org.apache.webbeans.intercept.******
NormalScopedBeanInterceptorHan****
dler.invoke(****NormalScopedBeanInterceptorHan****dler.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