Thanks for posting a solution m8 - but you forgot to tell us that any action related to the SchedulerThread/Service should be done when a valid JbpmContext is available e.g. :
Code:
/** remember - t1 WON'T be valid after you get out of the execute() method.... since the context is only valid for the duration you stay inside that method, any jbpm method you execute that requires the context (inside the domain of spring, OR even outside) will have access to it. */
JbpmContext t1 = (JbpmContext)getJbpmTemplate().execute(new JbpmCallback() {
public Object doInJbpm(JbpmContext context) {
// do something
ProcessInstance processInstance = context.getProcessInstance(instanceId);
log.debug("found process...");
processInstance.signal();
log.debug("signalled process...");
context.save(processInstance);
log.debug("saved process...");
return JbpmContext.getCurrentJbpmContext(); // statement not really needed - you can return null, or even monkey for all I care.
}
});
In contrast, if you had something like this:
Code:
// this caused me too much misery with a timer node.... will never work!
ProcessInstance processInstance = jbpmTemplate.findProcessInstance(instanceId);
log.debug("found process...");
processInstance.signal();
log.debug("signalled process...");
jbpmTemplate.saveProcessInstance(processInstance);
log.debug("saved process...");
It won't work as the context would be closed for some reason when the Scheduler code was reached.... and when that happened, I debugged the code and found out where it was failing and then printing a BIG FAT 'service "scheduler" not available OOHH Exception bla bla blady bla' :
Code:
// code from org.jbpm.svc.Services
public static Service getCurrentService(String name) {
return getCurrentService(name, true);
}
public static Service getCurrentService(String name, boolean isRequired) {
Service service = null;
// this was coming in as null !!!! No context means no service - mommyyyyy!!!
JbpmContext jbpmContext = JbpmContext.getCurrentJbpmContext();
if (jbpmContext!=null) {
service = jbpmContext.getServices().getService(name);
}
if (isRequired && (service==null)) {
throw new JbpmServiceException("service '"+name+"' unavailable");
}
return service;
}
So everything is working A-OK now. For people who want to integrate the scheduler service, I have attached the full code here:
Code:
// applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<!-- JBPM Datasource -->
<bean id="jbpmDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>
jdbc:mysql://localhost:3306/jbpmtest?useUnicode=true&characterEncoding=UTF-8
</value>
</property>
<property name="username">
<value>jbpm</value>
</property>
<property name="password">
<value>jbpm</value>
</property>
</bean>
<bean id="mysqlHibernateProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</prop>
<prop key="hibernate.default_batch_fetch_size">30</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
</props>
</property>
</bean>
<!-- JBPM Hibernate SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="jbpmDataSource" />
<property name="hibernateProperties"
ref="mysqlHibernateProperties" />
<property name="mappingLocations">
<value>classpath*:/org/jbpm/**/*.hbm.xml</value>
</property>
</bean>
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- helper for reading jBPM process definitions -->
<bean id="simpleWorkflow"
class="org.springmodules.workflow.jbpm31.definition.ProcessDefinitionFactoryBean">
<property name="definitionLocation"
value="classpath:com/arc/jbpmtest/sample/jpdl/simpleWorkflow/processdefinition.xml" />
</bean>
<!-- jBPM configuration -->
<!-- use this instead in production
<bean id="jbpmConfig" class="arc.jbpmtest.CustomLocalJbpmConfigurationFactoryBean">
-->
<bean id="jbpmConfiguration"
class="org.springmodules.workflow.jbpm31.LocalJbpmConfigurationFactoryBean">
<property name="sessionFactory" ref="sessionFactory" />
<property name="configuration"
value="classpath:jbpm.cfg.xml" />
<property name="createSchema" value="false" />
<property name="processDefinitions">
<list>
<ref local="simpleWorkflow" />
</list>
</property>
<!--
<property name="processDefinitionsResources">
<list>
<value>classpath:/org/springmodules/workflow/jbpm31/someOtherWorkflow.xml</value>
</list>
</property>
-->
</bean>
<!-- jBPM template -->
<bean id="jbpmTemplate"
class="org.springmodules.workflow.jbpm31.JbpmTemplate">
<constructor-arg index="0" ref="jbpmConfiguration" />
<constructor-arg index="1" ref="simpleWorkflow" />
</bean>
<bean id="workflowServiceTarget"
class="com.arc.jbpmtest.sample.base.workflow.WorkflowService"
autowire="byName">
<property name="jbpmTemplate" ref="jbpmTemplate" />
</bean>
<bean id="workflowService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager" />
<property name="target" ref="workflowServiceTarget" />
<property name="proxyTargetClass" value="true" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_NESTED</prop>
</props>
</property>
</bean>
<bean id="myMessageActionHandler"
class="com.arc.jbpmtest.sample.action.MessageActionHandler">
<property name="message"
value="This Message is Spring Injected!" />
</bean>
<bean id="workflowController"
class="com.arc.jbpmtest.beans.WorkflowController" scope="session">
<property name="workflowService" ref="workflowService" />
</bean>
<bean id="timerBean" class="com.arc.jbpmtest.servlets.JbpmThreadsServlet$TimerBean">
<property name="jbpmConfiguration" ref="jbpmConfiguration" />
<property name="jbpmTemplate" ref="jbpmTemplate" />
</bean>
</beans>