cancel
Showing results for 
Search instead for 
Did you mean: 

Accessing Business-Data via JPA before and after Timer

bardioc
Champ in-the-making
Champ in-the-making
Hello,

I've setup a very simple example of a process model that involves two Service-Tasks and a single Timer Catching Event. The model is as follows:

[attachment=0]TestCaseA02.png[/attachment]

Our customer's development rules require to separate the persistence database from the business database. Both are Oracle Databases (Version 11gR2), hosted on different machines.

I've setup the activity configuration as follows, because we are using WebSphere and are required to use JTA for transaction management. As there are two database-connections involved in our processes, we use XA Datasources configured via WebSphere for both datasources.


<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
   
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">   
    <property name="transactionManager"  ref="transactionManager" />
</bean>

The rest of the configuration is done by code as follows:


final ProcessEngineConfiguration pec = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
pec.setJobExecutorActivate(true);
pec.setDataSource(dataSource);
pec.setHistory(ProcessEngineConfiguration.HISTORY_FULL);
pec.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

The specified <dataSource> is injected into this EJB via


@Resource(name = "jdbc/persistence-db")
private DataSource dataSource;

Additionally, there exists a JPA configuration for the business database as 'persistence.xml'. It defines JTA as transaction type as well as a jta-data-source and the corresponding entity classes.

Within the process, the first of the two service tasks accesses the business database within a JavaDelegate by JNDI lookup to a EJB that itself contains an injected EntityManager, e.g.


service = InitialContext.doLookup("ejblocal:" + DatabaseAccessService.class.getName());
final EntityManager em = service.getEntityManager();
em.persist(businessObject);
em.flush();

When we try to do this after the timer fired, e.g. after a couple of seconds, we receive an exception, that no transaction manager can be found for the EJB:


<openjpa-2.1.1-SNAPSHOT-r422266:1141200 fatal user error> org.apache.openjpa.persistence.InvalidStateException: Es konnte kein automatischer Lookup der javax.transaction.TransactionManager-Implementierung des EJB-Containers durchgeführt werden.Vergewissern Sie sich, dass die Anwendung in einem mit EJB 1.1 kompatiblen EJB-Container ausgeführt wird, und setzen Sie anschließend die Eigenschaft org.apache.openjpa.ManagedRuntime auf den entsprechenden Wert, um den TransactionManager abzurufen.
   at org.apache.openjpa.ee.AutomaticManagedRuntime.getTransactionManager(AutomaticManagedRuntime.java:253)
   at org.apache.openjpa.kernel.AbstractBrokerFactory.syncWithManagedTransaction(AbstractBrokerFactory.java:717)
   at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:389)
   at com.ibm.ws.persistence.kernel.WsJpaBrokerImpl.initialize(WsJpaBrokerImpl.java:306)
   at org.apache.openjpa.kernel.BrokerImpl.initialize(BrokerImpl.java:323)


Caused by: javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component.  This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request.  Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application.  Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name "comp/TransactionSynchronizationRegistry" not found in context "java:".]
   at com.ibm.ws.naming.java.javaURLContextImpl.throwExceptionIfDefaultJavaNS(javaURLContextImpl.java:522)
   at com.ibm.ws.naming.java.javaURLContextImpl.throwConfigurationExceptionWithDefaultJavaNS(javaURLContextImpl.java:552)
   at com.ibm.ws.naming.java.javaURLContextImpl.lookupExt(javaURLContextImpl.java:481)

It is understandable, that there is no longer an EJB context available as the timer process ended the initial transaction. However, after the timer fired, I've read activity creates a new transaction to continue within the process.

How am I able to participate in this transacition, so my JPA call will utilize it and work as expected?
For me right now, the only possible option is to disable JTA for the business data and use LOCAL_RESOURCE instead together with creating the entity managers directly and by myself. However I'd like to know if there is a better approach for this using activity.

Thank you very much.

Heiko
4 REPLIES 4

frederikherema1
Star Contributor
Star Contributor
The jobexecutor responsible for executing the timers uses a different thread than the calling thread. However, it uses the same way of starting a transaction than normal execution of the process would do. The exception states:
Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application.

Can't you locate your service in a different way?

bardioc
Champ in-the-making
Champ in-the-making
The jobexecutor responsible for executing the timers uses a different thread than the calling thread. However, it uses the same way of starting a transaction than normal execution of the process would do. The exception states:
Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application.

Can't you locate your service in a different way?

Hello, thanks for the fast response.

I'm not aware of any way doing this. WebSphere in special denies to do JNDI lookups in the "java:" context (where necessary things like java:comp/TransactionSynchronizationRegistry) are located from threads created outside of the J2EE applciation context. I would not even be able to lookup any datasource (e.g. java:comp/env/mydatasource) from threads outside the JEE context Smiley Sad

Is there a way to modify the jobexecutor to utilize "allowed" constructs to create new threads, such as using the commonJ Workmanager approach provided by WebSphere? I've not digged into Activiti enough to see if there is a pluggable API to change the JobExecutor's way of handling threads till now Smiley Sad. I'm willing to help in here.

I've actually played with the activiti-cdi version, but run into the same problem. After the jobexector ran, no bean context is available which is a dead end for us too Smiley Sad

Thanks,

Heiko

frederikherema1
Star Contributor
Star Contributor
The thread-pool used by activiti is afaik not pluggable. However, the jobexecutor uses a ThreadPoolExecutor. You can potentially subclass the JobExecutor and add it to your ProcessEngineCOnfiguration(Impl).

bardioc
Champ in-the-making
Champ in-the-making
The thread-pool used by activiti is afaik not pluggable. However, the jobexecutor uses a ThreadPoolExecutor. You can potentially subclass the JobExecutor and add it to your ProcessEngineCOnfiguration(Impl).

Hello again,

I've successfully implemented a commonJ-based POC for WebSphere that puts both, the job acquisition thread as well as the job execution within the JEE context by utilizing WorkItems/Work-Instances instead of direct threads in a threadPool. I currently do not use any of the pool features, as the work manager itself works as a queue based system.

My implemtation needs access to "private" API of the ProcessEngineConfiguration as I need to apply a different JobExecutor.

As the JobAquisitionThread implements Runnable, I've subclassed it and implemented the commonj.work.Work interface in this subclass. I'm not using the Runnable features at all, simply rely on the fact that the Work interface is affine to the Runnable interface. This is definitly not a good way, but I did not want to change too much here right now.

All in all the changes are:
  • replace the default JobExecutor with my own implementation

  • inside the JobExecutor replace the JobAcqusitionThread again with my own implementation
Using this constellation, I'm able to successfully optain an EntityManager (or any other JNDI resource) within the second service task (the one AFTER the timer). The transaction built by Activiti is used in this case.

As java is not an allowed attachment extention I cannot attach the modified versions of the WorkManager as well as the JobAcqusitionThread (Work). Keep in mind, this is a POC, e.g. the WorkManager JNDI name is currently hard-coded. If someone is interested in this, drop me a line.

Are there any plans to provide a customizable API for the JobExecutor? In JEE contexts it is generally forbidden to create own threads/threadgroups, etc. thus other application servers my suffer from this situation as well.

If there is any need/interest, I would be glad to help to open the API at this part and provide a pluggable version that is able to work with threads (for plain Java SE environments), commonJ (for WebSphere and others that support it) or any other implementation. I think its possible to generalize the problem here.

Drop me a line, if the team is interested. For now, I'll continue working with the POC to determine, if any other problems arise.

Best regards,

Heiko Kopp
Getting started

Tags


Find what you came for

We want to make your experience in Hyland Connect as valuable as possible, so we put together some helpful links.