Классы ProcessApplication
|
Этот раздел перенесён из документации Camunda 7 и в дальнейшем будет доработан с учётом особенностей OpenBPM Engine |
Вы можете делегировать бутстраппинг движка обработки процессов и деплоймент процессов в класс процессного приложения. Основная функциональность ProcessApplication предоставляется базовым классом io.openbpm.bpm.application.AbstractProcessApplication. На этом классе базируются многочисленные подклассы, зависящие от окружения и реализующие интеграцию в свое специфическое окружение:
-
ServletProcessApplication: для использования в процессных приложениях на сервлет-контейнерах, например,Apache Tomcat.
-
JakartaServletProcessApplication: для использования в процессных приложениях в контейнерах Jakarta Servlet 5.0+, например, WildFly.
-
EjbProcessApplication: для использования на серверах приложений на Java EE.
-
JakartaEjbProcessApplication: для использования на серверах приложений на Jakarta EE 9+, например, Wildfly.
-
EmbeddedProcessApplication: для использования, когда стандартное Java SE приложение получает встроенный движок управления процессами.
-
SpringProcessApplication: для использования при бутстраппинге процессного приложения из контекста приложения на Spring.
В следующем разделе мы пройдемся по различным реализациям и обсудим, где и как они должны использоваться.
ServletProcessApplication и JakartaServletProcessApplication
|
|
Поддерживается на: Apache Tomcat, Wildfly. Процессное приложение на Servlet поддерживается всеми контейнерами. Здесь вы можете прочитать заметки по процессным приложениям на Servlet и EJB/Java EE контейнерам
Форма представления пакета: WAR (или встроенный WAR внутри EAR)
Класс ServletProcessApplication является базовым классом для разработки процессных приложений на основании спецификации Servlet (Java веб приложения). Процессные приложения на сервлетах реализуют интерфейс javax.servlet.ServletContextListener на Java EE, что позволяет ему участвовать в жизненном цикле деплоймента вашего веб приложения.
Далее представлен пример процессного приложение на сервлетах:
package io.openbpm.bpm.example.loanapproval;
import io.openbpm.bpm.application.ProcessApplication;
import io.openbpm.bpm.application.impl.ServletProcessApplication;
@ProcessApplication("Loan Approval App")
public class LoanApprovalApplication extends ServletProcessApplication {
// empty implementation
}
Отметим аннотацию @ProcessApplication. Эта аннотация отвесает двум целям:
-
Предоставить имя ProcessApplication: вы можете предоставить кастомизированное имя для процессного приложения, используя аннотацию
@ProcessApplication("Loan Approval App"). Если имя не предоставлено, оно определяется автоматически. В случае процессного приложения на сервлетах используется имяServletContext. -
Вызвать автоматический деплоймент. В контейнере Servlet 3.0 для того, чтобы быть уверенными в том, что процессное приложение будет подхвачено контейнером и автоматически добавлено как ServletContextListener к деплойменту Servlet-контейнера, достаточно одной данной аннотации. Эта функциональность реализована в имплементации
javax.servlet.ServletContainerInitializer, называемойio.openbpm.bpm.application.impl.ServletProcessApplicationDeployer, которая расположена в модуле camunda-engine. Эта имплементация работает как для встроенного деплоймента camunda-engine.jar как библиотеки веб приложения в каталогеWEB-INF/libвашего файла WAR, так и для деплоймента camunda-engine.jar как разделяемой библиотеки внутри разделяемой библиотеки (например, глобальный каталогlib/в Apache Tomcat) в каталог или на сервер приложений. Спецификация Servlet 3.0 учитывает оба сценария деплоймента. В случае встроенного деплойментаServletProcessApplicationDeployerполучает одно уведомление, когда приложение задеплоено. В случае деплоймента в качестве разделяемой библиотекиServletProcessApplicationDeployerполучает нотификации для каждого файла WAR, содержащего аннотацию@ProcessApplication(как требует спецификация Servlet 3.0).
Это означает, что в случае, когда вы деплоите в контейнер, совместимый с Servlet 3.0 (например, Apache Tomcat), достапточно поставить аннотацию @ProcessApplication на ваш класс.
|
Существует шаблон проекта для Maven, называемый |
Использование процессных приложений на сервлетах внутри EJB/Jakarta EE/Java EE контейнера, например, Wildfly
Вы можете использовать ServletProcessApplication внутри EJB / Java EE контейнера, например, Wildfly 26 и ниже.
В Jakarta EE 9+ контейнерах, таких как WildFly, вам необходимо использовать JakartaServletProcessApplication.
Бутстраппинг и деплоймент процессного приложения будет работать таким же образом в Servlet-контейнере. оДнако, вы не сможете использовать все возможности Jakarta EE/Java EE в рантайм е. В отличие от
EjbProcessApplication (см. следующий раздел), ServletProcessApplication и JakartaServletProcessApplication не производят корректного переключения контекста межде приложениями на Jakarta EE/Java EE. Когда движок управления процессами вызывает Java Delegates из вашего приложения, только загрузчик класса контейста из текущего потока устанавливается как загрузчик классов вашего приложения. Это не позволяет движку управления процессами разрешать реализации Java Delegate из вашего приложения, но контейнер не будет выполнять EE-переключение контекста в ваше приложение. Следовательно, если вы используете процессное приложение на сервлетах внутри Jakarta EE/Java EE контейнера, вы не сможете использовать следующие возможности:
-
Использование CDI-бинов и EJB в качестве реализаций JavaDelegate в сочетании с Job Executor-ом.
-
Использование
@RequestScopedCDI-бинов с Job Executor-ом. -
Нахождение JNDI ресурсов в пространстве имен (naming scope) приложения.
Если ваше приложение не использует такие возможности, то нет никаких проблем с тем, чтобы использовать процессное приложение на сервлетах внутри EE-контейнера. В таком случае вы получаете только те гарантии, которые дает спецификация Servlet.
EjbProcessApplication и JakartaEjbProcessApplication
|
|
Поддерживается на: Wildfly. The EjbProcessApplication поддерживается контейнерами версий от Java EE 6 до Java EE 8. JakartaEjbProcessApplication поддерживается контейнерами Jakarta EE 9+, например, WildFly. Он не поддерживается в Servlet-контейнерах, подобных Apache Tomcat. Он может быть адаптирован для работы внутри Java EE 5 контейнеров.
Форма представления пакета: JAR, WAR, EAR
EjbProcessApplication и JakartaEjbProcessApplication являются базовыми классами для разработки процессных приложений на Jakarta EE/Java EE. Класс для процессного приложения на EJB должен сам деплоиться тоже как EJB.
Чтобы добавить процессное приложение на EJB к вашему Java-приложению, у вас есть две опции:
-
Добавить в бандл EJB-клиент для Camunda: мы предоставляем переиспользуемую generic-реализацию процессного EJB-приложения (под названием
io.openbpm.bpm.application.impl.ejb.DefaultEjbProcessApplication), включенную в Maven-артефакт. Вы можете добавить эту реализацию в ваше приложение как Maven-зависимость. Используйте артефактcamunda-ejb-clientдля приложений на Java EE или артефактcamunda-ejb-client-jakartaдля приложений на Jakarta EE 9+. -
Напишите кастомизированное процессное приложение на EJB: если вы хотите кастомизировать поведение
EjbProcessApplicationилиJakartaEjbProcessApplication, вы можете написать кастомизированный подкласс соответствующего класса и добавить его к своему приложению.
Обе опции подробно описаны ниже.
Добавление jar-файла Camunda EJB-клиента в бандл
Самая удобная опция для деплоймента процессного приложения в контейнер Java EE EJB — это добавить следующую Maven-зависимость к вашему Maven-проекту:
|
Импортируйте Camunda BOM, чтобы гарантировать правильные версии всех проектов Camunda. |
<dependency>
<groupId>io.openbpm.bpm.javaee</groupId>
<artifactId>camunda-ejb-client</artifactId>
</dependency>
Для контейнеров Jakarta EE 9+ EJB используйте следующую зависимость:
<dependency>
<groupId>io.openbpm.bpm.javaee</groupId>
<artifactId>camunda-ejb-client-jakarta</artifactId>
</dependency>
Camunda EJB Client содержит переиспользуемую реализацию для использования по умолчанию соответствующего процессного приложения EJB как Singleton Session Bean с автоматической активацией.
Эта опция деплоймента требует, чтобы ваш проект деплоился как композитный (то есть был WAR или EAR), поскольку вам придется добавлять JAR-файл библиотеки. Конечно, вы могли бы использовать плагин Maven Shade ил ичто-то подобное для добавления класса, содержащегося в атрефакте Camunda EJB Client к JAR-файлу, предназначенному для деплоймента.
|
Мы вспегда рекомендуем использовать Camunda EJB Client вместо того, чтобы деплоить кастомизированный класс Существует шаблон проекта для Maven, называемый |
Деплоймент кастомизированного класса EjbProcessApplication
Если вы хотите кастомизировать поведение класса EjbProcessApplication, у вас есть опция написать кастомизированный класс EjbProcessApplication. Далее приведен пример такой реализации:
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@ProcessApplication
@Local(ProcessApplicationInterface.class)
public class MyEjbProcessApplication extends EjbProcessApplication {
@PostConstruct
public void start() {
deploy();
}
@PreDestroy
public void stop() {
undeploy();
}
}
Открытие доступа к пути контекста сервлета, используя кастомизированное процессное EJB-приложение
Если ваше приложение является WAR (или WAR внутри EAR) и вы хотите использовать встроенные формы или внешние формы задач внутри приложения Tasklist, ваше кастомизированное процессное EJB-приложение должно открывать путь к контексту сервлета в вашем приложении, сделав его свойством. Это позволяет Tasklist разрешать путь к встроенныи или внешним формам задач.
Следовательно, ваше кастомизированное процессное EJB-приложение должно расширяться с помощью класса Map и getter-метода для эьтого Map следующим образом:
@Singleton
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@ProcessApplication
@Local(ProcessApplicationInterface.class)
public class MyEjbProcessApplication extends EjbProcessApplication {
protected Map<String, String> properties = new HashMap<String, String>();
@PostConstruct
public void start() {
deploy();
}
@PreDestroy
public void stop() {
undeploy();
}
public Map<String, String> getProperties() {
return properties;
}
}
Более того, чтобы предоставить путь к контексту сервлета, необходимо добавить к вашему приложению кастомизированный Java EE javax.servlet.ServletContextListener. Внутри кастомизированной реализации ServletContextListener вы должны:
-
Инжектировать ваше кастомизированное процессное EJB-приложение, используя аннотацию
@EJB -
Разрешить путь к контексту сервлета
-
Сделать доступным путь к контексту сервлета через свойство
ProcessApplicationInfo#PROP_SERVLET_CONTEXT_PATHвнутри вашего кастомизированного процессного EJB-приложения
Это можно сделать следующим образом:
public class ProcessArchiveServletContextListener implements ServletContextListener {
@EJB
private ProcessApplicationInterface processApplication;
public void contextInitialized(ServletContextEvent contextEvent) {
String contextPath = contextEvent.getServletContext().getContextPath();
Map<String, String> properties = processApplication.getProperties();
properties.put(ProcessApplicationInfo.PROP_SERVLET_CONTEXT_PATH, contextPath);
}
public void contextDestroyed(ServletContextEvent arg0) {
}
}
И, наконец, кастомизированный ProcessArchiveServletContextListener должен быть добавлен к файлу WEB-INF/web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<listener>
<listener-class>org.my.project.ProcessArchiveServletContextListener</listener-class>
</listener>
...
</web-app>
Вызов семантики процессного EJB-приложения
Тот факт, что процессное EJB-приложение представлено как Session Bean Component внутри EJB-контейнера, определяет следующее:
-
Семантику вызова кода из процессного приложения
-
Природу
ProcessApplicationReferenceв движке управления процессами
Когда движок управления процессами вызывает процессное EJB-приложение, он получает семантику вызова EJB. Например, если ваше процессное приложение предоставляет реализацию JavaDelegate, двидок вызовет метод execute(Callable) класса EjbProcessApplication и из этого метода вызовет JavaDelegate. Таким образом будет гарантировано, что:
-
Вызов будет перехвачен EJB-контейнером и "войдет" в процессное приложение легальным образом
-
JavaDelegateможет воспользоваться контекстом вызова процессного EJB-приложения и разрешить ресурсы из окружения компонента (например,java:comp/BeanManager).
Big pile of EJB interceptors
|
| +--------------------+
| |Process Application |
invoke v | |
ProcessEngine ----------------OOOOO--> Java Delegate |
| |
| |
+--------------------+
Процессное EJB-приложение позволяет встроить hook внутрь вызова, переопределив метод execute(Callable callable, InvocationContext invocationContext). Это дает контекст текущего вызова (например, выполнение) и может использоваться для выполнения кастомизированного кода, например, чтобы инициализировать контекст безопасности до того, как будет вызвана сервисная задача.
public class MyEjbProcessApplication extends EjbProcessApplication {
@Override
public <T> T execute(Callable<T> callable, InvocationContext invocationContext) {
if(invocationContext != null) {
// execute custom code (e.g. initialize the security context)
}
return execute(callable);
}
}
Когда процессное EJB-приложение регистрируется в движке управления процессами (см. ManagementService#registerProcessApplication(String, ProcessApplicationReference), процессное приложение передает в движок ссылку на само себя. Эта ссылка позволяет двидку управления процессами ссылаться на процессное приложение. Процессное EJB-приложение пользуется контекстом именования EJB-контейнеров и передает ссылку, содержащую уомпонент процессного приложения, в двидок. Каждый раз, когда движку необходимо обратиться к процессному приложению, отыскивается и вызывается экземпляр актуального компонента.
EmbeddedProcessApplication
Поддерживается в: JVM, Apache Tomcat, Wildfly
Форма представления пакета: JAR, WAR, EAR
Класс io.openbpm.bpm.application.impl.EmbeddedProcessApplication может использоваться только в комбинации с встроенным движком управления процессами. Использование в комбинации с разделенным движком не поддерживается, так как этот класс не производит переключения контекстов в процессном приложении в рантайме.
Встроенное процессное приложение также не предоставляет процедуры автоматического старта. Вам необходимо вручную вызвать метод #deploy вашего процессного приложения:
// instantiate the process application
MyProcessApplication processApplication = new MyProcessApplication();
// deploy the process application
processApplication.deploy();
// interact with the process engine
ProcessEngine processEngine = BpmPlatform.getDefaultProcessEngine();
processEngine.getRuntimeService().startProcessInstanceByKey(...);
// undeploy the process application
processApplication.undeploy();
Здесь класс MyProcessApplication может выглядеть вот так:
@ProcessApplication(
name="my-app",
deploymentDescriptors={"path/to/my/processes.xml"}
)
public class MyProcessApplication extends EmbeddedProcessApplication {
}
Помните, что заставить управляемое вручную EmbeddedProcessApplication работать, вам придется зарегистрировать ваш ProcessEngine в RuntimeContainer:
RuntimeContainerDelegate runtimeContainerDelegate = RuntimeContainerDelegate.INSTANCE.get();
runtimeContainerDelegate.registerProcessEngine(processEngine);
SpringProcessApplication
Поддерживается в: JVM, Apache Tomcat.
Форма представления пакета: JAR, WAR, EAR
Класс io.openbpm.bpm.engine.spring.application.SpringProcessApplication позволяет выполнять бутстраппинг процессного приложения через Spring Application Context. Вы можете либо сослаться на класс SpringProcessApplication из файла конфигурации контекста приложения в формате XML, либо использовать настройки, основанные на аннотациях.
Если ваше приложение является веб-приложением, вам следует использовать io.openbpm.bpm.engine.spring.application.SpringServletProcessApplication, поскольку он предоставляет поддержку для открытия пути сервлет-контекста через свойство ProcessApplicationInfo#PROP_SERVLET_CONTEXT_PATH.
Мы рпекомендуем всегда использовать SpringServletProcessApplication, за исключением тех случаев, когда деплоймент не является веб-приложением. Использование этого класса требует присутствие модуля .springframework:spring-web в classpath.
Конфигурирование Spring Process Application
Ниже приведен пример того, как производить бутстраппинг SpringProcessApplication внутри XML-файла контекста Spring-приложения:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="invoicePa" class="io.openbpm.bpm.engine.spring.application.SpringServletProcessApplication" />
</beans>
Не забудьте также добавить файл META-INF/processes.xml.
Если вы управляете вашим
processEngineвручную, вам придется зарегистрировать его вRuntimeContainerDelegate, как описано в секции EmbeddedProcessEngine.
Имя процессного приложения
SpringProcessApplication будет использовать имя бина (id="invoicePa" в вышеприведенном примере) как автоматически определяемое имя процессного приложения. Убкдитесь в том, что в этом месте в предоставляете уникальное имя для процессного приложения (уникальное среди всех процессных приложений, задеплоенных на одном инстансе сервера приложений). В качестве альтернативы вы можете предоставить кастомизированный подкласс для SpringProcessApplication (или SpringServletProcessApplication) и переопределить метод getName().
Конфигурирование управляемого движка управления процессами с использованием Spring
Если вы используете процессное приложение на Spring, вам может понадобиться сконфигурировать ваш движок управления процессами внутри XML файла контекста Spring-приложения (вместо файла processes.xml). В этом случае вам прдется использовать класс io.openbpm.bpm.engine.spring.container.ManagedProcessEngineFactoryBean для создания экземпляра объекта движка управления процессами. В дополнение к созданию объекта движка управления процессами, эта реализация регистрирует движок в инфраструктуре Camunda 7, чтобы движок возвращался ProcessEngineService. Далее приведен пример того, как сконфигурировать управляемый движок управления процессами с использованием Spring.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource">
<bean class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:mem:camunda;DB_CLOSE_DELAY=1000"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="processEngineConfiguration" class="io.openbpm.bpm.engine.spring.SpringProcessEngineConfiguration">
<property name="processEngineName" value="default" />
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="true"/>
<property name="jobExecutorActivate" value="false"/>
</bean>
<!-- using ManagedProcessEngineFactoryBean allows registering the ProcessEngine with the BpmPlatform -->
<bean id="processEngine" class="io.openbpm.bpm.engine.spring.container.ManagedProcessEngineFactoryBean">
<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"/>
</beans>
Лицензия и атрибуция
Эта документация была создана на базе материала "Camunda 7 Docs" от Camunda, находится под лицензией Creative Commons Attribution-ShareAlike 3.0 Unported License .
Оригинал документации: https://docs.camunda.org