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



Reply via email to