[JBoss Seam] - Help with MDB + Seam + jBPM - transaction issue?
by bsmithjj
Hello,
I have an MDB that invokes a SLSB method - the method does some persistence work and signals a jBPM ProcessInstance. I am consistently getting an exception related to transactions from jBPM. Here are the classes being used:
The MDB:
| @MessageDriven(activationConfig = {
| @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
| @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/SonicJMS/Queues/AccessControl/Receive"),
| @ActivationConfigProperty(propertyName = "providerAdapterJNDI", propertyValue = "java:/SonicJMSProvider"),
| @ActivationConfigProperty(propertyName = "useDLQ", propertyValue = "false")
| }
| )
| @Name("accessControlReceiveMDB")
| public class AccessControlReceiveMDB implements MessageListener {
|
| private Log log = LogFactory.getLog(AccessControlReceiveMDB.class);
|
| @EJB(beanName = "ProvisionSuccessBean")
| private ProvisionSuccess successfulResponse;
|
| @EJB(beanName = "ProvisionFailureBean")
| private ProvisionFailure failedResponse;
|
| @Resource
| MessageDrivenContext context;
|
| //(a)TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
| public void onMessage(javax.jms.Message message) {
| log.info("AccessControlReceiveMDB : onMessage()");
| log.info(message);
| try {
| // Grab Message Type from header.
| MessageTypes messageType = null;
| try {
| messageType = MessageTypes.valueOf(message
| .getStringProperty(MessageHeaderKeys.MessageType
| .toString()));
| } catch (Exception e) {
| messageType = MessageTypes.UnknownMessageType;
| }
|
| Long processId = null;
|
| switch (messageType) {
| case ProvisionSuccess:
| // Grab process id from header.
| try {
| processId = Long.valueOf(message.getStringProperty(MessageHeaderKeys.ProcessId.toString()));
| log.info("processId -> "+processId);
| Contexts.getEventContext().set("processId",processId);
| if (successfulResponse == null) {
| log.error("successResponse bean is null.");
| }
| successfulResponse.confirmProvisioning();
| } catch (Exception e) {
| log.error(e,e);
| log.error(
| "\nMissing Process ID in message header for message "
| + message.getJMSMessageID()
| +".\nMessage will be consumed but no processing will occur.\n"
| );
| }
| break;
|
| case ProvisionFailure:
| // Grab process id from header.
| try {
| processId = Long.valueOf(message.getStringProperty(MessageHeaderKeys.ProcessId.toString()));
| } catch (Exception e) {
| throw new Exception("Missing Process Id in Message Header. " + e);
| }
|
| failedResponse.confirmProvisioning(
| processId,
| message.getStringProperty(MessageHeaderKeys.ProvisionException.toString())
| );
| break;
|
| case ActiveUserList:
| break;
|
| case ActiveUserListCSV:
| break;
|
| case UnknownMessageType:
| log.info("Discarding message of type '"+messageType+"' - unknown message type.");
| break;
|
| }
| } catch (JMSException jmse) {
| log.error("Allowed MessageTypes -> " + Arrays.asList(MessageTypes.values()));
| log.error(jmse, jmse);
| context.setRollbackOnly();
| } catch (Exception e) {
| log.error(e, e);
| context.setRollbackOnly();
| }
| }
| }
|
The SLSB:
| @Stateless
| @Name("provisionSuccess")
| public class ProvisionSuccessBean implements ProvisionSuccess {
|
| //@Logger
| //protected Log log;
| private Log log = LogFactory.getLog(ProvisionSuccessBean.class);
|
| @PersistenceContext(unitName = "accessControlDatabase")
| protected EntityManager em;
|
| @In(create = true)
| private JbpmContext jbpmContext;
|
| public String confirmProvisioning(Long processId) {
| log.info("confirmProvisioning: " + processId);
|
| log.info("injected jbpmConext -> " + jbpmContext);
|
| ProcessInstance process = jbpmContext.getProcessInstance(processId);
| Long accessRequestId = (Long) process.getContextInstance().getVariable("accessRequestId");
|
| log.info("Access Request Id: " + accessRequestId);
| AccessRequest accessRequest = em.find(AccessRequest.class,accessRequestId.longValue());
| log.info("AccessRequest: " + accessRequest);
|
| .... A LOT OF BUSINESS LOGIC CUTOUT FROM HERE ....
| // Update the Access Request Decisions to include a complete decision.
| // Update the status of the Access Request to complete
| AccessRequestDecision decision = accessRequest.getDistributedSecurityAdminDecision();
| decision.setDecision(AccessRequestStatus.Complete);
| accessRequest.setRequestStatus(AccessRequestStatus.Complete);
| em.merge(decision);
| em.merge(accessRequest);
|
| // Signal to jBPM to move the workflow along
| log.info("Signaling workflow -> ProvisionSuccess");
|
| process.signal("ProvisionSuccess");
| jbpmContext.save(process);
|
| return "success";
| }
|
| }
|
|
The exception as seen in the JBoss console:
| 09:23:10,158 ERROR [StdServerSession] failed to commit/rollback
| org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=DEIBKST-6KZFT61/14, BranchQual=, localId=14] status=STATUS_NO_TRANSACTION; - nested throwable:
| (java.lang.NullPointerException)
| at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:372)
| at org.jboss.tm.TxManager.commit(TxManager.java:240)
| at org.jboss.jms.asf.StdServerSession.onMessage(StdServerSession.java:351)
| at progress.message.jimpl.Session.dU_(Unknown Source)
| at progress.message.jimpl.Session.run(Unknown Source)
| at org.jboss.jms.asf.StdServerSession.run(StdServerSession.java:196)
| at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:743)
| at java.lang.Thread.run(Thread.java:595)
| Caused by: java.lang.NullPointerException
| at org.jboss.seam.core.ManagedJbpmContext.beforeCompletion(ManagedJbpmContext.java:94)
| at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1491)
| at org.jboss.tm.TransactionImpl.beforePrepare(TransactionImpl.java:1110)
| at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:324)
| ... 7 more
|
|
I think the following log statements from server.log show jBPM actually getting a handle to the UserTransaction:
| 2007-02-08 09:23:10,111 DEBUG [org.jbpm.persistence.db.DbPersistenceServiceFactory] creating persistence service
| 2007-02-08 09:23:10,111 DEBUG [org.jbpm.persistence.db.DbPersistenceService] creating hibernate session
| 2007-02-08 09:23:10,111 DEBUG [org.hibernate.impl.SessionImpl] opened session at timestamp: 4796189041094656
| 2007-02-08 09:23:10,127 DEBUG [org.hibernate.transaction.JTATransaction] Looking for UserTransaction under: UserTransaction
| 2007-02-08 09:23:10,127 DEBUG [org.hibernate.transaction.JTATransaction] Obtained UserTransaction
| 2007-02-08 09:23:10,127 DEBUG [org.jboss.mx.loading.RepositoryClassLoader] setRepository, repository=org.jboss.mx.loading.HeirarchicalLoaderRepository3@40a1e1, cl=org.jboss.mx.loading.HeirarchicalLoaderRepository3$CacheClassLoader@d3e5cc{ url=null ,addedOrder=0}
| 2007-02-08 09:23:10,127 DEBUG [org.jboss.seam.interceptors.BijectionInterceptor] disinjecting dependencies of: provisionSuccess
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
|
and here we see Seam tearing down the jBPM Context and the transaction exception occuring from the server.log:
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.core.ManagedJbpmContext] destroying seam managed jBPM context
| 2007-02-08 09:23:10,142 DEBUG [org.jbpm.JbpmContext] closing JbpmContext
| 2007-02-08 09:23:10,142 DEBUG [org.jbpm.svc.Services] closing service 'persistence': org.jbpm.persistence.db.DbPersistenceService@1c4f6f6
| 2007-02-08 09:23:10,142 DEBUG [org.jbpm.persistence.db.DbPersistenceService] flushing hibernate session
| 2007-02-08 09:23:10,142 DEBUG [org.hibernate.jdbc.JDBCContext] successfully registered Synchronization
| 2007-02-08 09:23:10,142 DEBUG [org.jbpm.persistence.db.DbPersistenceService] closing hibernate session
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.core.ManagedJbpmContext] done destroying seam managed jBPM context
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] instantiating Seam component: org.jboss.seam.core.events
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] initializing new instance of: org.jboss.seam.core.events
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.Component] done initializing: org.jboss.seam.core.events
| 2007-02-08 09:23:10,142 DEBUG [org.jboss.seam.core.Events] Processing event:org.jboss.seam.postDestroyContext.EVENT
| 2007-02-08 09:23:10,158 DEBUG [org.jboss.seam.contexts.Lifecycle] <<< End call
| 2007-02-08 09:23:10,158 DEBUG [org.jboss.seam.core.ManagedJbpmContext] flushing seam managed jBPM context
| 2007-02-08 09:23:10,158 DEBUG [org.jboss.util.NestedThrowable] org.jboss.util.NestedThrowable.parentTraceEnabled=true
| 2007-02-08 09:23:10,158 DEBUG [org.jboss.util.NestedThrowable] org.jboss.util.NestedThrowable.nestedTraceEnabled=false
| 2007-02-08 09:23:10,158 DEBUG [org.jboss.util.NestedThrowable] org.jboss.util.NestedThrowable.detectDuplicateNesting=true
| 2007-02-08 09:23:10,158 ERROR [org.jboss.jms.asf.StdServerSession] failed to commit/rollback
| org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=DEIBKST-6KZFT61/14, BranchQual=, localId=14] status=STATUS_NO_TRANSACTION; - nested throwable: (java.lang.NullPointerException)
| at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:372)
| at org.jboss.tm.TxManager.commit(TxManager.java:240)
| at org.jboss.jms.asf.StdServerSession.onMessage(StdServerSession.java:351)
| at progress.message.jimpl.Session.dU_(Unknown Source)
| at progress.message.jimpl.Session.run(Unknown Source)
| at org.jboss.jms.asf.StdServerSession.run(StdServerSession.java:196)
| at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(PooledExecutor.java:743)
| at java.lang.Thread.run(Thread.java:595)
| Caused by: java.lang.NullPointerException
| at org.jboss.seam.core.ManagedJbpmContext.beforeCompletion(ManagedJbpmContext.java:94)
| at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1491)
| at org.jboss.tm.TransactionImpl.beforePrepare(TransactionImpl.java:1110)
| at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:324)
| ... 7 more
|
Any help on this is appreciated.
Thanks,
Brad Smith
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4013058#4013058
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4013058
19Â years, 2Â months
[EJB 3.0] - Re: Hook onto Transaction Manager
by dkalna
Hi Brett, if your beans can be Statefull Session Beans then you can implement SessionSynchronization interface:
package javax.ejb;
public interface javax.ejb.SessionSynchronization {
public abstract void afterBegin( ) throws RemoteException;
public abstract void beforeCompletion( ) throws RemoteException;
public abstract void afterCompletion(boolean committed)
throws RemoteException;
}
When a method of the SessionSynchronization bean is invoked outside of a transaction scope, the method executes in the Method-Ready state. However, when a method is invoked within a transaction scope (or creates a new transaction), the EJB moves into the Transactional Method-Ready state.
When a transactional method is invoked on a SessionSynchronization bean, the stateful bean becomes part of the transaction, causing the afterBegin( ) callback method defined in the SessionSynchronization interface to be invoked. This method should take care of reading any data from the database and storing the data in the bean's instance fields. The afterBegin( ) method is called before the EJB object delegates the business-method invocation to the EJB instance.
When the afterBegin( ) callback method completes, the business method originally invoked by the client is executed on the EJB instance. Any subsequent business methods invoked within the same transaction will be delegated directly to the EJB instance.
Once a stateful session bean is a part of a transactionwhether it implements SessionSynchronization or notit cannot be accessed by any other transactional context. This is true regardless of whether the client tries to access the EJB with a different context or the EJB's own method creates a new context. If, for example, a method with a transaction attribute of RequiresNew is invoked, the new transactional context causes an error to be thrown. Since the NotSupported and Never attributes specify a different transactional context (no context), invoking a method with these attributes also causes an error. A stateful session bean cannot be removed while it is involved in a transaction. This means that invoking an @Remove annotated method while the SessionSynchronization bean is in the middle of a transaction will cause an error to be thrown.
At some point, the transaction in which the SessionSynchronization bean has been enrolled will come to an end. If the transaction is committed, the SessionSynchronization bean will be notified through its beforeCompletion( ) method. At this time, the EJB should write its cached data to the database. If the transaction is rolled back, the beforeCompletion( ) method will not be invoked, avoiding the pointless effort of writing changes that won't be committed to the database.
The afterCompletion( ) method is always invoked, whether the transaction ended successfully with a commit or unsuccessfully with a rollback. If the transaction was a successwhich means that beforeCompletion( ) was invokedthe committed parameter of the afterCompletion( ) method will be true. If the transaction was unsuccessful, then the committed parameter will be false.
It may be desirable to reset the stateful session bean's instance variables to some initial state if the afterCompletion( ) method indicates that the transaction was rolled back.
Bye
Dalibor
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4013049#4013049
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4013049
19Â years, 2Â months