I am trying to create a Grails application that uses Activiti for its processing engine. To this end, I would like the main classes of the Activiti service (RuntimeService, TaskService, etc.) to be connected as Spring beans.
I believe that I have the wiring set correctly, but when I run a simple integration test that calls the runtime service, I get an error that Spring was unable to open a hibernation session (see Full stack trace , below).
Refresh . I can start the application with run-appand then call the controller action that calls my service, and it all works. As such, Activiti wiring works, it just conflicts with Grails Integration Testing.
I really want Activiti services to use the same data source connection as the Grails application. I guess the problem is that Activiti is trying to create its own instance of ConnectionHolder when Grails already has one setting for integration tests.
My specific (and possibly erroneous) question that I have is how to configure my Activiti ProcessEngine to use the same data source and hibernation connection as my Grails application?
A more general question is: how can I best use Activiti services for my Grails application? I looked at the Activiti plugin for grails and its source helped me get this far. However, I would prefer not to use this plugin; it does not use the latest activity, development on it is not very active, and this is not quite what I need in any case.
Full stack trace
| Failure: start approver request(com.package.MyServiceSpec)
| org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@7f2e1821] for key [org.springframework.jdbc.datasource.LazyConnectionDa
at grails.test.mixin.integration.IntegrationTestMixin.initIntegrationTest(IntegrationTestMixin.groovy:58)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
at org.spockframework.runtime.extension.builtin.JUnitFixtureMethodsExtension$FixtureType$FixtureMethodInterceptor.intercept(JUnitFixtureMethodsExtension.java:145)
at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:84)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@7f2e1821] for key [org.springframework.jdbc.datasource.LazyConn
... 7 more
Caused by: java.lang.IllegalStateException: Already value [org.springframework.jdbc.datasource.ConnectionHolder@7f2e1821] for key [org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy@1b7aeb] bound to thread [main]
... 7 more
| Completed 1 integration test, 1 failed in 0m 1s
resources.groovy
import org.activiti.engine.ProcessEngine
import org.activiti.spring.ProcessEngineFactoryBean
import org.activiti.explorer.form.*
import org.activiti.spring.SpringProcessEngineConfiguration
import grails.util.Environment
import org.springframework.jdbc.datasource.DataSourceTransactionManager
import org.springframework.jdbc.datasource.SimpleDriverDataSource
beans = {
processEngineConfig(SpringProcessEngineConfiguration) {
dataSource = ref('dataSource')
transactionManager = ref('transactionManager')
databaseType = 'oracle'
databaseSchema = 'OURSCHEMA'
databaseSchemaUpdate = false
jobExecutorActivate = true
}
processEngine(ProcessEngineFactoryBean) {
processEngineConfiguration = ref("processEngineConfig")
}
runtimeService(processEngine: "getRuntimeService")
repositoryService(processEngine: "getRepositoryService")
taskService(processEngine: "getTaskService")
managementService(processEngine: "getManagementService")
historyService(processEngine: "getHistoryService")
formService(processEngine: "getFormService")
}
Class of service
class MyService {
def foapAuthFoapService
def processEngine
def runtimeService
def repositoryService
def taskService
def managementService
def historyService
def formService
def startRequest(String requester, String subject, String designatedApprover) {
runtimeService.startProcessInstanceByKey('MyProcess', ["requester": requester, "subject": subject, "designatedApprover": designatedApprover])
}
}
Spock test
def "start request"() {
setup:
def approverRequest = service.startRequest(requester, subject, designatedApprover)
def variables = runtimeService.getVariables(approverRequest.id) //approverRequest.getProcessVariables()
expect:
approverRequest instanceof ProcessInstance
variables.entrySet().contailsAll(["designatedApprover": designatedApprover, "requester": requester, "subject": subject].entrySet())
where:
requester | subject | designatedApprover
"abc123" | "def456"| "hij789"
}