cancel
Showing results for 
Search instead for 
Did you mean: 

New Spring applicationContext started by activiti-rest

engywook
Champ in-the-making
Champ in-the-making
Hi,
I have a Spring (3.2.2) managed web application using Activiti 5.12.  I'm not having any issues with this configuration and Activiti performs as expected.  The process engine is managed by Spring and has access to all the beans it needs.  We have not been using activiti-explorer or activiti-rest with this configuration.

Now I'm trying to incorporate the activiti-rest jar into the existing webapp.  I have the servlet mapping configured and am able to process certain requests that don't use other spring beans.  It looks like activiti-rest uses Activiti's ProcessEngines class to load an entirely new applicationContext based on activiti-context.xml, which results in a new process engine.  In my application, the activiti-context.xml file is one of many context files imported by the main application context XML file.  So this new application context does not have access to all of the beans nor to the camel context that some of the tasks delegate to. 

I figure I could restructure the context files so the rest context has the same beans, but I'd prefer to have one context and especially one camel context.  I've considered the possibility of just letting ProcessEngines start the application context and disabling the org.springframework.web.context.ContextLoaderListener but I have not tried that. 

I'm mainly looking for advice here.  What's the best way to include the activiti-rest jar in an existing spring application?  Is there a way to inject the process engine into activiti-rest's relelvant classes or to initialize ProcessEngines with Spring process engine rather than ProcessEngines creating its own application context and process engine? 

Thanks!

I'm not sure if this is useful but here's my web.xml.

<web-app>
   <display-name>webapp name</display-name>
   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/applicationContext.xml</param-value>
   </context-param>
   <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class>
   </listener>
   <!– activiti-rest –>
   <servlet>
      <servlet-name>ActivitiRestServlet</servlet-name>
      <servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
      <init-param>
         <!– Application name –>
         <param-name>org.restlet.application</param-name>
         <param-value>activitiRest</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>ActivitiRestServlet</servlet-name>
      <url-pattern>/process/*</url-pattern>
   </servlet-mapping>
       <session-config>
      <session-timeout>30</session-timeout>
   </session-config>
   <welcome-file-list>
      <welcome-file>index.html</welcome-file>
   </welcome-file-list>
</web-app>

I altered my activiti-context.xml  to include all the datasource and transaction management beans so that ProcessEngines can start that new context, but I'm not importing everything here so some beans are still missing, particularly camel.

<beans>
   <context:component-scan base-package="com.example.security.ldap"/>
   <import resource="properties-context.xml" />
   <import resource="data-source-context.xml" />
   <import resource="persistence-context.xml" />
   <import resource="activiti-processEngine-context.xml" />
</beans>

activiti-processEngine-context.xml is a new file what the main application context xml file imports now on application start.

<beans>
   <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration" depends-on="entityManagerFactory">
      <property name="databaseType" value="${activiti.processEngineConfiguration.databaseType}" />
      <property name="dataSource" ref="dataSource" />
      <property name="transactionManager" ref="transactionManager" />
      <property name="databaseSchemaUpdate" value="${activiti.processEngineConfiguration.databasechemaUpdate}" />
      <property name="deploymentResources" value="classpath*:processes/*.bpmn" />
      <property name="history" value="audit" />
      <property name="jobExecutorActivate" value="true" />
      <property name="customSessionFactories">
         <list>
            <ref bean="ldapUserManagerFactory"/>
            <ref bean="ldapGroupManagerFactory"/>
         </list>
      </property>
   </bean>

   <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
      <property name="processEngineConfiguration" ref="processEngineConfiguration" />
   </bean>

   <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
   <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
   <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
   <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
   <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
   <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService" />
   
   <bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule">
      <property name="processEngine" ref="processEngine" />
   </bean>
   <bean id="activitiRest" class="org.activiti.rest.application.ActivitiRestServicesApplication"/>
</beans>
1 REPLY 1

engywook
Champ in-the-making
Champ in-the-making
Here's what I ended up doing in case this helps somebody.

I added a ProcessEnginesInitializer class that extends org.activiti.engine.ProcessEngines.  The bean's @PostConstruct method registers the Spring-managed process engine with ProcessEngines, sets ProcessEngines.isInitialized to true, and performs some other initializations that ProcessEngines normally does.  Next, the org.activiti.rest.application.ActivitiRestServicesApplication bean's declaration needs to depend on the processEnginesInitializer (to ensure that the REST service is initialized after ProcessEngines has been initialized).  This results in the REST API using the Spring-managed process engine and avoids the extra application context I mentioned before.


@Component("processEnginesInitializer")
public class ProcessEngineInitializer extends org.activiti.engine.ProcessEngines {

protected static final Logger log = LoggerFactory.getLogger(ProcessEngineInitializer.class);

@Inject
private ProcessEngine processEngine;

@PostConstruct
public void contextInitialized() {
  String processEngineName = processEngine.getName();
  String resourceUrl = "applicationContext.xml"; // I'm not sure that this text matters so you may be able to set this to anything.
  ProcessEngineInfo processEngineInfo = new ProcessEngineInfoImpl(processEngineName, resourceUrl, null);
  processEngineInfosByName.put(processEngineName, processEngineInfo);
  processEngineInfosByResourceUrl.put(resourceUrl, processEngineInfo);
  registerProcessEngine(processEngine);
  isInitialized = true;
  ProcessEngine processEngine = ProcessEngineInitializer.getDefaultProcessEngine();
  if (processEngine == null) {
   log.error("Could not initialize Activiti");
  }
}

@PreDestroy
public void contextDestroyed() {
  ProcessEngineInitializer.destroy();
}
}


<bean id="activitiRest" class="org.activiti.rest.application.ActivitiRestServicesApplication" depends-on="processEnginesInitializer"/>