-
1. Drools, Spring integration and JTA in container
salaboy21 Jan 24, 2011 8:54 AM (in response to urdo2)It should work, because it works with JTA Bitronix, can you create an isolated test case using spring JTA, I will be glad to see the error and fixit in the repository.
-
2. Re: Drools, Spring integration and JTA in container
urdo2 Jan 24, 2011 9:58 AM (in response to salaboy21)Maybe the problem is in my configuration:
.....
<drools:ksession id="jpaSingleSessionCommandService" type="stateful" kbase="knowledgeBase">
<drools:configuration>
<drools:work-item-handlers>
<!-- .... -->
</drools:work-item-handlers>
<drools:jpa-persistence>
<drools:transaction-manager ref="transactionManager"/>
<drools:entity-manager-factory ref="entityManagerFactory"/>
</drools:jpa-persistence>
</drools:configuration>
</drools:ksession>
.....
<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/org.drools.persistence.jpa.local"/>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TransactionManager"/>
<property name="userTransactionName" value="UserTransaction"/>
</bean>
.....
During deployment, application throws NullpointerException in class: SingleSessionCommandService
because when invoked initTransactionManager(Environment env) method:
Object tm = env.get( EnvironmentName.TRANSACTION_MANAGER );
....
if ( tm.getClass().getName().toLowerCase().contains( "jpa" ) ) {
// configure spring for JPA and local transactions
cls = Class.forName( "org.drools.container.spring.beans.persistence.DroolsSpringJpaManager" );
con = cls.getConstructors()[0];
this.jpm = ( JpaManager) con.newInstance( new Object[] { this.env } );
} else {
// configure spring for JPA and distributed transactions
}
jpm is null,
because tm.getClass().getName().toLowerCase().contains( "jpa" ) is not true, in my case (org.springframework.transaction.jta.JtaTransactionManager)
-
3. Drools, Spring integration and JTA in container
salaboy21 Jan 24, 2011 9:58 AM (in response to urdo2)Did you set the transaction manager in the Environment?
-
4. Re: Drools, Spring integration and JTA in container
urdo2 Jan 24, 2011 10:16 AM (in response to salaboy21)Yes, because env.get( EnvironmentName.TRANSACTION_MANAGER ) return instance of JtaTransactionManager
-
5. Re: Drools, Spring integration and JTA in container
salaboy21 Jan 24, 2011 10:19 AM (in response to urdo2)Can you isolate a failing test? I will take a look at the problem if you want.
Greetings.
-
6. Re: Drools, Spring integration and JTA in container
urdo2 Jan 25, 2011 7:00 AM (in response to salaboy21)I isolate test case in war.
-
webapp-workflow.zip 7.2 KB
-
-
7. Re: Drools, Spring integration and JTA in container
salaboy21 Jan 25, 2011 7:05 AM (in response to urdo2)Perfect let me have a look on that..
Greetings
-
8. Drools, Spring integration and JTA in container
urdo2 Jan 27, 2011 1:13 PM (in response to salaboy21)I think it works with JTA Bitronix, but without Spring.
-
9. Re: Drools, Spring integration and JTA in container
pbezek Mar 28, 2011 8:13 AM (in response to urdo2)I have same problem. As "bodi bajk" correctly addressed, my problem is also about the line tm.getClass().getName().toLowerCase().contains( "jpa" ) Is there any recent development/fix on this subject?
-
10. Re: Drools, Spring integration and JTA in container
alexmanly Apr 8, 2011 7:55 AM (in response to urdo2)I have this same problem.
In the spring config I create the Transaction manager as follows:
{code:xml}
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/rd-domain-pu" />
<tx:jta-transaction-manager />
{code:xml}
This creates a transaction manager with the type:
org.springframework.transaction.jta.JtaTransactionManager
My drools spring config is this:
{code:xml}
<drools:kbase id="kbase1">
<drools:resources>
<drools:resource id="cloneFlow" type="DRF" source="classpath:Clone.rf"/>
<drools:resource id="approvalFlow" type="DRF" source="classpath:Approval.rf"/>
</drools:resources>
<drools:configuration>
<drools:mbeans enabled="true" />
<drools:event-processing-mode mode="STREAM" />
</drools:configuration>
</drools:kbase>
<drools:ksession id="jpaSingleSessionCommandService" type="stateful" kbase="kbase1" name="stateful-session">
<drools:configuration>
<drools:jpa-persistence>
<drools:transaction-manager ref="transactionManager" />
<drools:entity-manager-factory ref="entityManagerFactory" />
<drools:variable-persisters>
<drools:persister for-class="javax.persistence.Entity" implementation="org.drools.persistence.processinstance.persisters.JPAVariablePersister"/>
<drools:persister for-class="java.io.Serializable" implementation="org.drools.persistence.processinstance.persisters.SerializableVariablePersister"/>
</drools:variable-persisters>
</drools:jpa-persistence>
<drools:work-item-handlers>
<drools:work-item-handler name="Human Task" ref="humanTaskHandler"/>
</drools:work-item-handlers>
<drools:keep-reference enabled="true" />
<drools:clock-type type="REALTIME" />
</drools:configuration>
<drools:script>
<drools:start-process process-id="1"/>
<drools:fire-all-rules/>
</drools:script>
</drools:ksession>
{code:xml}
No when the spring context is loaded I get the same error and the problem is the initTransactionManager method in SingleSessionComand:
The problem is the class does start with "org.springframework" (in the first if statement. But the class does not contain "jpa" in the second if statement. Which means the line comment: //configure spring for JPA and distributed transactions
{code}
public void initTransactionManager(Environment env) {
Object tm = env.get( EnvironmentName.TRANSACTION_MANAGER );
if ( tm != null && tm.getClass().getName().startsWith( "org.springframework" ) ) {
try {
Class<?> cls = Class.forName( "org.drools.container.spring.beans.persistence.DroolsSpringTransactionManager" );
Constructor<?> con = cls.getConstructors()[0];
this.txm = (TransactionManager) con.newInstance( tm );
logger.debug( "Instantiating DroolsSpringTransactionManager" );
if ( tm.getClass().getName().toLowerCase().contains( "jpa" ) ) {
// configure spring for JPA and local transactions
cls = Class.forName( "org.drools.container.spring.beans.persistence.DroolsSpringJpaManager" );
con = cls.getConstructors()[0];
this.jpm = ( JpaManager) con.newInstance( new Object[] { this.env } );
} else {
// configure spring for JPA and distributed transactions
}
} catch ( Exception e ) {
logger.warn( "Could not instatiate DroolsSpringTransactionManager" );
throw new RuntimeException( "Could not instatiate org.drools.container.spring.beans.persistence.DroolsSpringTransactionManager", e );
}
} else {
logger.debug( "Instantiating JtaTransactionManager" );
this.txm = new JtaTransactionManager( env.get( EnvironmentName.TRANSACTION ),
env.get( EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY ),
tm );
this.jpm = new DefaultJpaManager(this.env);
}
}
{code}
Does anyone from Drools development know when the code will support a "org.springframework.transaction.jta.JtaTransactionManager" class?
Thanks in advance
-
11. Re: Drools, Spring integration and JTA in container
fabiowg Apr 8, 2011 3:09 PM (in response to alexmanly)Hi there,
After some time struggling to make this "Spring + JTA + Drools" integration, I could make it work, but I'm still unsure if it's the right way. As everyone pointed out, the SingleSessionComand#initTransactionManager ignores the case where a org.springframework.transaction.jta.JtaTransactionManager is used. So I had to manually create an Environment like this:
Environment environment = EnvironmentFactory.newEnvironment();
environment.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
DroolsSpringTransactionManager jtaTransactionManager = new DroolsSpringTransactionManager(ptm);
this.environment.set(EnvironmentName.TRANSACTION_MANAGER, jtaTransactionManager);
DroolsSpringJpaManager pcm = new DroolsSpringJpaManager(environment);
environment.set(EnvironmentName.PERSISTENCE_CONTEXT_MANAGER, pcm);
And, after that, I create my ksession (unfortunately, without the <drools:ksession/> shortcut):
ksession = JPAKnowledgeService.newStatefulKnowledgeSession(this.kbase, null, environment);
Hope this helps.
Fábio
-
12. Re: Drools, Spring integration and JTA in container
alexmanly Apr 11, 2011 3:54 AM (in response to fabiowg)Hi Fabio
Thanks for taking the time to respond.
Can you please tell me what the object type is for your attribute: "ptm".
I assume it is this object type:
{code}
org.springframework.transaction.jta.JtaTransactionManager
{code}
Also, I am using Drools version 5.1 and the Class EnvironmentName does not have a static field named:
{code}
EnvironmentName.PERSISTENCE_CONTEXT_MANAGER
{code}
What should I use instead of that field?
Kind regards
Alex
-
13. Re: Drools, Spring integration and JTA in container
fabiowg Apr 11, 2011 7:33 AM (in response to alexmanly)Hi,
I've just noticed that the code of initTransactionManager you sent was a bit different from the one I was analyzing. I'm using Drools version 5.2.0.M1.
In fact, there doesn't seem to be a way to pass a PersistenceContextManager through the environment in version 5.1.x. So I think the easiest way to make it work would be to subclass the SingleSessionCommandService, override the initTransactionManager, where you would lookup the transactionManager in the environment using any key you like), and then manually instantiate a CommandBasedStatefulKnowledgeSession.
I just came up with this idea, so I don't know if it works at all.
(By the way, ptm is supposed to be the spring PlatformTransactionManager, so yes, it could be a JtaTransactionManager).
What a mess, huh?
-
14. Re: Drools, Spring integration and JTA in container
alexmanly Apr 11, 2011 8:34 AM (in response to fabiowg)Hi,
I have managed to get the spring context to load by overriding the SingleSessionCommandService as you mentioned. Here is my code:
{code}
public void initTransactionManager(Environment env) {
Object tm = env.get( EnvironmentName.TRANSACTION_MANAGER );
if ( tm != null && tm.getClass().getName().equals( "org.springframework.transaction.jta.JtaTransactionManager" ) ) {
logger.debug( "Instantiating Spring JtaTransactionManager" );
this.txm = new JtaTransactionManager(((org.springframework.transaction.jta.JtaTransactionManager)tm).getUserTransaction(),
env.get( EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY ),
((org.springframework.transaction.jta.JtaTransactionManager)tm).getTransactionManager() );
this.jpm = new DefaultJpaManager(this.env);
} else {
// continue as normal
}
{code}
I agree.....very messy. Thanks for your help.