ServerDeveloperGuide

Материал из RunaWFE

Перейти к: навигация, поиск

Сервер. Руководство разработчика

Версия 4.4.0

© 2015-2020, ООО "Процессные технологии", материалы этого документа распространяются свободно на условиях лицензии GNU FDL. RunaWFE Free является системой с открытым кодом и распространяется в соответствии с LGPL лицензией (http://www.gnu.org/licenses/lgpl.html).

Исходный код проекта был перенесён с https://sourceforge.net/p/runawfe на https://github.com/processtech.

Содержание

# Введение

# Основные компоненты и используемые технологии

Для WF–системы была выбрана следующая общая архитектура (в целом соответствует архитектуре, предлагаемой коалицией WfMC):

Компоненты системы:

  • Ядро системы
    • Содержит набор определений бизнес-процессов
    • Содержит набор выполняющихся экземпляров бизнес–процессов
  • Компонент, "назначающий" исполнителей для действий
  • Клиент
    • Список заданий (набор графических форм, содержит очереди поступивших работ, сортировки и фильтры)
    • Проигрыватель форм (отображает формы, разработанные в Среде разработки)
    • Административный интерфейс
      • Показывает состояния процессов, позволяет фильтровать и останавливать процессы
      • Позволяет загружать-выгружать процессы
      • Позволяет заводить-удалять пользователей
      • Позволяет задавать различные права
    • Редактор назначения заместителей
  • Среда разработки
  • Конструктор графических форм
  • Бот станции, содержащие ботов (Боты - приложения специального вида, которые также как и обычные пользователи могут выполнять задания)
  • Подсистема управления правами доступа (авторизация и аутентификация)

# Платформа программирования и используемые программные средства

В качестве платформы программирования используется J2EE.

Используемые программные средства:

  1. Сервер приложений - JBOSS (http://www.jboss.org).
  2. Среда разработки - любая, например Eclipse от IBM (http://www.eclipse.org).
  3. Система контроля версий - git
  4. Сборщик приложений – maven.
  5. Сервер баз данных – поддерживаются сервера БД:
  6. Операционная система — поддерживаются следующие ОС:
    • Windows (Server 2000-2008, XP, Vista, 7)
    • ALTLinux
    • Mandriva Linux
    • Fedora
    • Debian/Ubuntu

# Описание проектов

Название проекта Обязателен при сборке Обязателен при работе Зависимости Описание
wfe-alfresco нет нет runawfe-app Интеграция с Alfresco
wfe-app да да wfe-ear, wfe-cactus-it Проект для организации сборки maven
wfe-appserver нет нет  ? Не используется
wfe-bots да да wfe-service Подсистема ботов
wfe-cactus-it да нет wfe-service Интеграционные тесты
wfe-core да да - Основные компоненты системы
wfe-ear да да wfe-service, wfe-bots, wfe-office, wfe-web Проект для сборки runawfe.ear
wfe-office да нет wfe-core Обработчики для работы с Word, Excel
wfe-service да да wfe-core Сервисы (EJB + WebServices), представляющие собой публичное API приложения
wfe-web да да wfe-bots Визуальная часть приложения
wfe-webservice-client нет нет  ? Авто-генерации клиентской библиотеки на основе WSDL серверных сервисов. В нем же есть примеры использования веб-служб из Java клиента.

# Описание слоев архитектуры системы

Каждый компонент состоит из нескольких уровней (слоев).

Список слоев:

  • delegate
  • service
  • logic
  • DAO
  • hibernate

# Слой Delegate

Delegate-классы, реализующие сервисные интерфейсы представляют собой pattern проектирования BusinessDelegate, упрощающий доступ к серверному API системы. Клиентское приложение взаимодействует с системой только через Delegate-классы. Delegate-классы получаются посредством запроса фабрики Delegates, которая в зависимости от конфигурации возвращает нужную реализацию. Классы Delegate являются частью клиентского API.

Список основных Delegate-классов:

  • AuthenticationServiceDelegate – содержит методы для аутентификации пользователей в системе (с использованием логина/пароля, Kerberos и т.п.)
  • AuthorizationServiceDelegate — содержит методы для работы с полномочиями пользователей (назначение полномочий, проверка на допустимость операции для пользователя и т.п.)
  • BotServiceDelegate — содержит методы для работы с бот станциями и ботами
  • ExecutorServiceDelegate — содержит методы для работы с исполнителями. Позволяет создавать/удалять/изменять исполнителей а так же включать их в группы
  • ProfileServiceDelegate — содержит методы для работы с профайлам пользователей
  • SubstitutionServiceDelegate — содержит методы для управления правилами замещения
  • SystemServiceDelegate — содержит методы для входа/выхода пользователя в систему
  • DefinitionServiceDelegate — содержит методы для работы с определениями процессов
  • ExecutionServiceDelegate — содержит методы для работы с исполняемыми экземплярами процессов

Все существующие в данный момент Delegate-классы реализуют требуемую функциональность при помощи технологии EJB.

# Слой Service

Слой service – это серверное API доступа к системе. Реализации Delegate интерфейсов обращаются именно к этому слою. Каждый Delegate работает с одним соответствующим классом Service. В настоящее время все разработанные service классы и интерфейсы ориентированы на EJB-технологию, однако в будущем возможны и другие реализации. Реализации классов Service являются Stateless Session Bean EJB, которые декларативно поддерживают транзакционность вызовов и запрашивают соответствующие классы из слоя Logic.

Таким образом, классы Delegate – Service - Logic образуют как бы «транспорт» между клиентом и сервером.

# Слой Logic

Слой Logic – это реализация бизнес логики работы системы. Слой работает с классами слоя DAO для доступа к постоянному хранилищу.

# Слой DAO

Слой DAO – это интерфейсы и классы, обеспечивающие доступ к данным, находящимся в постоянном хранилище (базе данных). В настоящее время все DAO-классы системы реализованы при помощи ORM-средства Hibernate.

# Использование Hibernate

Hibernate – ORM (Object/Relational Mapping) средство. Отображает объектную архитектуру на реляционную структуру данных. Допускает настройку (не меняя разработанного кода) на большинство существующих серверов реляционных баз данных.

Поддерживает работу с распределенными транзакциями, автоматически создает таблицы для новых классов и т.д. Вся работа с данными внутри системы ведется только через Hibernate.

Все компоненты, предоставляющие клиентское API построены с использованием описанных выше слоев. В целях оптимизации в некоторых компонентах применяется кеширование, которое может встречаться на уровне logic или DAO. Основная функциональность по управлению кешами находится в классах CachingLogic, CacheInterceptor и классах соответствующих кешей. Изменения в кешируемых объектах перехватываются и сообщаются посредством CachingLogic всем подписавшимся на изменения классам кешей. Транзакция, изменяющая кеш, считается закрытой по окончанию обработки ejb вызова.

# Обновление базы данных

см. описание системы патчей.

# API

Система представляет API для интеграции с другими системами:

# Java API

Реализация (снизу вверх): БД - Hibernate3 - EJB3

Документацию можно смотреть в исходном коде (javadocs в *Service.java).

# WebServices API

Реализация (снизу вверх): БД - Hibernate3 - JAX-WS

Документация: WebServicesDeveloperGuide

# Scripting API

Реализация (снизу вверх): БД - Hibernate3 - XML Script

Документация: AdminScriptGuide

# Процесс сборки из исходного кода

Исходный код системы доступен в открытом репозитории на github.

Сервер можно собирать как средствами maven используя командную строку, так и используя среду Eclipse IDE.

В результате сборки будет сформирован runawfe.ear, который теоретически можно запустить на любом сервере приложений. Начиная с версии 4.3.0 введена поддержка JAVA версии 8, и отказ от JAVA 6. В дальнейшем планируется отказ от java7, поэтому рекомендуется использовать сервер приложений wildfly.

# Процесс сборки на примере Eclipse IDE

# Необходимое программное обеспечение для сборки

В отличие от Среды разработки для сборки сервера можно использовать Eclipse IDE любой версии и редакции.

  • установите плагин m2eclipse
  • используйте Apache Maven (>= 3.0.4), можно свободно загрузить по следующему адресу: http://maven.apache.org/
  • добавьте путь к Apache Maven директории bin в переменную окружения Path

# Импорт проектов

Импортируйте проекты с помощью Git-клиента из репозитория https://github.com/processtech/runawfe-server.

Eclipse srv proj.png

# Установка maven артефактов

Выполните

${wfe}/wfe-app/repository/add_dependencies.bat (Windows) 
${wfe}/wfe-app/repository/add_dependencies.sh (Linux) 

или другим способом установите артефакты в локальный репозиторий

# Сборка

Заведите конфигурацию запуска на основе maven как показано на рисунке

Maven.build.configuration.png

Запустите конфигурацию.

Сформированный runawfe.ear файл будет находиться в директории deployments проекта "wfe-ear", например "..\eclipse-workspace\runawfe-server\wfe-ear\${jboss.home.dir}\standalone\deployments"

# Сборка из командной строки

  • используйте Apache Maven (>= 3.0.4), можно свободно загрузить по следующему адресу http://maven.apache.org/
  • добавьте путь к Apache Maven директории bin в переменную окружения Path
  • импортируйте проекты с помощью Git-клиента из репозитория https://github.com/processtech/runawfe-server
  • выполните обновление зависимостей
${wfe}/wfe-app/repository/add_dependencies.bat (Windows) 
${wfe}/wfe-app/repository/add_dependencies.sh (Linux) 
  • откройте командную строку
  • перейдите в директорию ${wfe}/wfe-app/
  • выполните команду для сборки
mvn clean package -Dmaven.test.skip=true

Сформированный runawfe.ear файл будет находиться в директории deployments проекта "wfe-ear", например "..\runawfe-server\wfe-ear\${jboss.home.dir}\standalone\deployments"


Для установки артефактов в локальный репозиторий используйте команду

mvn clean install -Dmaven.test.skip=true

# Использование ear на сервере приложений

  • cкачайте текущую версию RunaWFE в виде файл-архива исполняемых java файлов с портала sourceforge runawfe-server-4.3.0.zip (на базе wildfly, java8)
  • распакуйте архив
  • обновите runawfe.ear на версию полученную в результате сборки

# Расширение функциональности

# Точки расширения системы

  • Обработчики позволяют исполнить код в процессах (элементы "Обработчик", "Задача сценария") и ботах
  • Форматы переменных определяют тип переменных и правила преобразования значений к текстовому представлению и обратно
  • Организационные функции используются при назначении ролей и в правилах замещения для определения заместителя
  • Критерии замещения используются в подсистеме замещения для определения заместителя при построении списка заданий
  • Валидаторы обеспечивают проверку переменных при выполнении задания (в т.ч. введенные значения форм)
  • Freemarker теги форм генерируют html код для отображения на форме
  • Ajax команды предоставляют доступ к функциональности сервера из JavaScript

# Процесс разработки расширений

Создайте новый java-проект и подключите необходимые зависимости (wfe-core, wfe-service).

Реализуйте в нем требуемые расширения и соберите его в виде jar-файла.

Замечание. Использование maven облегчит процесс управления зависимостями.

Разместить собранный jar на сервере вы можете:

  • положив его в runawfe.ear!/lib
  • положив его в директорию deploy (только для jboss4)
  • положив его в ${jboss.server.base.dir}/wfe.custom (только для jboss7)
  • положив его в ${jboss.server.base.dir}/${jboss.server.name}/wfe.custom (только для jboss4)

# Обработчики

Обработчик в процессе – компонент процесса (элементы "Обработчик", "Задача сценария"), использующийся для выполнения каких-либо действий при возникновении определенных событий (проход по определенному переходу в процессе, приход или уход управления из узла и т.п.).

Обработчик должен реализовывать интерфейс ru.runa.wfe.extension.ActionHandler. Создание экземпляра обработчика в системе происходит с использованием конструктора по умолчанию и передачей параметров обработчику вызовом метода setConfiguration(String). В классах-обработчиках возможно использование бинов Spring контекста (например с помощью аннотации @Autowired).

При написании нового обработчика рекомендуется наследовать его от абстрактного класса ru.runa.wfe.extension.handler.CommonHandler или ru.runa.wfe.extension.handler.CommonParamBasedHandler. В методе setConfiguration обработчик должен запомнить свои параметры (если обработчик их ожидает), а в методе execute происходит непосредственная обработка и выполнение требуемых действий.

В случае, если при выполнении обработчика произошла ошибка, произойдет откат транзакции и состояние процесса будет возвращено к заданию, исполнение которого повлекло вызов обработчика. В интерфейсе обработчика для бота ru.runa.wfe.extension.TaskHandler предусмотрен метод onRollback для работы с не-транзакционными ресурсами.

Эти обработчики удобно использовать для простых операций (например для отправки оповещений в виде SMS-сообщений если процесс попал в определенное состояние). Но у них есть несколько ограничений. Прежде всего у них нет соответствующего объекта контекста безопасности (security context). Это означает, что в них нельзя выполнять защищенные методы (запуск процессов, выполнение задач, создание пользователей и т.п.) Ошибочным решением в них будет блокирование выполнения процесса (например с Thread::Sleep(...)). Например, если в обработчике отправляется e-mail, а SMTP сервер недоступен, обработчику нельзя "задерживать" свое выполнение.

Связь между Средой разработки и сервером осуществляется по полному имени класса, поэтому регистрация не требуется.

# Специфика обработчиков для ботов

Бот - это сокращение от робот. В системе боты - это особый тип исполнителей. Система не отличает ботов от людей. У каждого бота есть свои права на вход в систему, он периодически просыпается, проверяет свой список задачи и выполняет обнаруженные там задачи.

Каждая задача бота обрабатывается при помощи соответствующего обработчика. Чтобы написать новый обработчик нужно реализовать интерфейс ru.runa.wfe.extension.TaskHandler.

Обратите внимание, что этот вид обработчиков выполняется в контексте безопасности (security context) пользователя-бота, и здесь может выполнятся любая операция (если у бота есть на это права).

Обработчики задач ботов могут блокировать выполнение процесса.

Например, обработчик задач, отправляющий e-mail может блокировать выполнение бизнес процесса до тех пор, пока обработчик не удостоверится, что SMTP сервер принял сообщение для последующей доставки.

Обработчики задач вызываются периодически, когда боты проверяют свои списки задач.

# Специфика обработчика для элемента ветвление

Обработчик для Decision является java-классом, реализующим интерфейс ru.runa.wfe.extension.DecisionHandler. Интерфейс содержит один метод decide(ExecutionContext executionContext), который возвращает имя выбранного перехода (одного из выходящих из данного ветвления). Создание экземпляра обработчика в системе происходит с использованием конструктора по умолчанию и передачей параметров обработчику вызовом метода setConfiguration(String). В классах-обработчиках возможно использование бинов контекста спринга (например с помощью аннотации @Autowired).

Обработчик принимает ExecutionContext в качестве входящего параметра и должен сделать выбор перехода исходя из значений переменных бизнес процесса и условий, указанных в конфигурации обработчика. Точно также как обработчики действия (action handler) обработчики выбора (decision handlers) не могут использовать защищенные (secured) методы, не могут обрабатывать ошибки и откладывать выбор перехода до лучших времен.

По умолчанию используется ru.runa.wfe.extension.decision.GroovyDecisionHandler.

# Использование ru.runa.wfe.extension.handler.CommonParamBasedHandler в качестве базового класса

Этот класс инкапсулирует в себе парсинг XML конфигурации определенного формата. Его удобно использовать если обработчик имеет фиксированное число параметров. Пример конфигурации:

<?xml version="1.0" encoding="UTF-8"?>
<config>
 <input>
   <param name="typeName" variable="тип отсутствия" />
   <param name="employee" variable="сотрудник" />
   <param name="requester" variable="подавший заявку" />
   <param name="from" variable="дата с" />
   <param name="to" variable="дата по" />
   <param name="cause" variable="причина" />
   <param name="comment" variable="комментарий" />
   <param name="confirmation" variable="дата подтверждения" />
   <param name="firmCode" value="111" />
   <param name="firmPositionCode" variable="код должности" />
   <param name="firmDepartmentCode" variable="код подразделения" />
 </input>
 <output>
   <param name="uuid" variable="идентификатор объекта" />
 </output>
</config>

Использование обработчика Groovy

См. соответствующий раздел в руководстве по работе с Groovy.

# Как написать функцию над организационной структурой

Функции над организационной структурой в системе применяются, например, при инициализации Ролей-Дорожек и в правилах замещения.

Класс, соответствующий функции над организационной структурой, должен реализовывать интерфейс ru.runa.wfe.extension.OrgFunction.

Интерфейс содержит один метод

List<? extends Executor> getExecutors(Object... parameters)

Этот метод должен возвращать список исполнителей.

В бизнес-процессе обработчик функции над оргструктурой используются при определении Ролей-Дорожек: указывается внутри тега swimlane, в теле тега <assignment>.В качестве параметра class тега <assignment> указывается класс-обработчик для инициализации swimlane: ru.runa.wfe.extension.AssignmentHandler. Внутри тега <assignment> содержится конфигурация для этого класса, которая представляет собой имя класса-наследника интерфейса OrgFunction и список параметров в скобках. В качестве параметра может выступать конкретное значение или имя переменной бизнес процесса в фигурных скобках, перед которым стоит значок $

Связь между Средой разработки и сервером осуществляется по полному имени класса, поэтому регистрация не требуется.

Если есть планы по использованию функции в подсистеме замещений - её можно зарегистрировать в substitutions.xml.

# Как написать критерий замещения

Критерии замещения в системе применяются в правилах замещения. Класс, соответствующий критерию замещения, должен наследоваться от ru.runa.wfe.ss.SubstitutionCriteria.

Для создания на основе него конечных критериев замещения с конфигурациями - его нужно зарегистрировать в substitution.criterias.xml.

Как реализовать класс-формат для переменных бизнес-процесса

См. соответствующий раздел в руководстве по работе с переменными.

# Как реализовать валидатор переменных

Классы, расширяющие абстрактный класс ru.runa.wfe.validation.FieldValidator, в системе применяются для проверки переменных при выполнении задания или старте процесса.

Пример:

public class OvertimeWorkRequestTimeCheck extends FieldValidator {
   @Override
   public void validate() {
       Date date = (Date) getFieldValue();
       if (date == null) {
           return;
       }
       boolean testMode = getVariableProvider().getValueNotNull(boolean.class, "тестовый режим");
       if (testMode) {
           return;
       }
       Calendar calendar = CalendarUtil.dateToCalendar(date);
       if (calendar.before(Calendar.getInstance())) {
           addError("Заявка не может быть оформлена задним числом");
           return;
       }
       CalendarUtil.setTimeFromCalendar(calendar, DemoProperties.getOvertimeWorkRequestMaximumStartTime());
       Utils.adjustCalendarForHolidaysInOvertimwWork(calendar);
       if (calendar.before(Calendar.getInstance())) {
           addError("Заявка на этот день не может быть подана, время подачи истекло " + CalendarUtil.formatDateTime(calendar));
       }
   }

}

Связь между Средой разработки и сервером осуществляется по имени валидатора, регистрация требуется на стороне сервера в файле validators.xml, а в среде разработки - в plugin.xml.

# Как реализовать FreeMarker тег для формы

FreemarkerForms#Components

# Как реализовать Ajax команду

Классы, расширяющие абстрактный класс ru.runa.wfe.commons.web.JsonAjaxCommand, (или реализующие ru.runa.wfe.commons.web.AjaxCommand) в системе применяются для доступа к функциональности сервера из JavaScript, например при отображении форм задания.

Регистрация команды происходит любым из двух способов:

  • в файле ajax.commands.xml, ей присваивается определенное имя
  • в контексте приложения, именем является id spring-бина

Затем по этому имени её можно выполнить используя JavaScript.

Пример команды

public class GetOrganizationNamesCommand extends JsonAjaxCommand {
   @Autowired
   private OrganizationDAO organizationDAO;
   @Override
   protected JSONAware execute(User user, HttpServletRequest request) throws Exception {
       String term = request.getParameter("term");
       if (term == null) {
           term = "";
       }
       List<Organization> organizations = organizationDAO.getAll();
       JSONArray array = new JSONArray();
       for (Organization organization : organizations) {
           if (organization.getName().startsWith(term)) {
               array.add(organization.getName());
           }
       }
       return array;
   }
}

Регистрация в wfe.custom.ajax.commands.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration xmlns="http://runa.ru/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://runa.ru/xml">
 <command name="getOrganizationNames" class="ru.runa.rkdemo.web.ajax.GetOrganizationNamesCommand" />
</configuration>

Её использование со скрипта формы (autocomplete input)

$(document).ready(function() {
 $('#editLinkedLists').on("onRowAdded", function(event, rowIndex) {
  $("input[name='названия организаций["+rowIndex+"]']").autocomplete( {
   delay: 300,
   minLength: 0,
   source: "/wfe/ajaxcmd?command=getOrganizationNames"
  });
  $("input[name='названия организаций["+rowIndex+"]']").focus(function() {
   $(this).autocomplete("search", $(this).val());
  });
 });
});
Личные инструменты