Activiti: пример создания workflow
На форуме прозвучала просьба написать пример воркфлоу на activiti с подробными объяснениями. Попытаюсь просьбу исполнить. Пишу в этом блоге впервые, прошу строго не судить.
Надо знать, что с введением в альфреску activiti общие принципы написания бизнесс-процессов кардинально не изменились. Изменился лишь язык описания процессов (всю документацию по activiti можно найти здесь) и некоторые мелочи в локализации. Поэтому прежде стоит прочитать предыдущие статьи здесь на форуме:
Пример создания workflow в ECM Alfresco
Создание workflow. Продолжение
Давайте имплементируем следующий сценарий:
1. Регистратор загружает документ-директиву и инициирует процесс, передавая документ начальнику некоего подразделения.
2. Начальник знакомится с содержанием документа-директивы, формирует поручение и отправляет поручение на исполнение, выбирая исполнителя.
3. Исполнитель выполняет поручение, добавляет к документам акт об исполнении и возвращает начальнику на рассмотрение.
4. Начальник утверждает исполнение, и процесс заканчивается. Иначе - начальник возвращает исполнителю поручение на доработку, и процесс возвращается к шагу 3.
Получится вот такой маршрут для документа:
Итак, создаем модель процесса DirectiveWorkflowModel.xml:
<?xml version="1.0" encoding="UTF-8"?> <!-- Описание модели бизнес-процесса --> <model name="dir:workflowmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0"> <!-- Импорт необходимых описаний --> <imports> <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" /> <import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm" /> <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/> </imports> <!-- Описываем пространство имен для нашего процесса --> <namespaces> <namespace uri="http://www.somecompany.ru/model/workflow/1.0" prefix="dir" /> </namespaces> <types> <!-- Подача директивы --> <type name="dir:start"> <!-- Наследуем от bpm:startTask --> <parent>bpm:startTask</parent> <!-- Указываем обязательные аспекты --> <mandatory-aspects> <!-- Начальник подразделения --> <aspect>bpm:assignee</aspect> </mandatory-aspects> </type> <!-- Ознакомление с директивой и передача на исполнение --> <type name="dir:inspection"> <!-- Наследуем от bpm:workflowTask --> <parent>bpm:workflowTask</parent> <!-- Доступ к документам пакета --> <overrides> <!-- Документ может быть добавлен --> <property name="bpm:packageActionGroup"> <default>add_package_item_actions</default> </property> <!-- Документ может быть отредактирован --> <property name="bpm:packageItemActionGroup"> <default>edit_package_item_actions</default> </property> </overrides> <!-- Указываем обязательные аспекты --> <mandatory-aspects> <!-- Исполнитель --> <aspect>dir:performer</aspect> </mandatory-aspects> </type> <!-- Исполнение поручения --> <type name="dir:perform"> <parent>bpm:workflowTask</parent> <!-- Доступ к документам пакета --> <overrides> <!-- Документ может быть добавлен --> <property name="bpm:packageActionGroup"> <default>add_package_item_actions</default> </property> <!-- Документ может быть отредактирован --> <property name="bpm:packageItemActionGroup"> <default>edit_package_item_actions</default> </property> </overrides> </type> <!-- Проверка исполнения --> <type name="dir:approve"> <!-- Наследуем от bpm:activitiOutcomeTask --> <!-- Новый объект, появился с введением activiti в альфреско --> <parent>bpm:activitiOutcomeTask</parent> <!-- Свойства --> <properties> <!-- Утвердить исполнение или же отправить на доработку --> <property name="dir:appOutcome"> <type>d:text</type> <default>reject</default> <constraints> <constraint name="dir:propAppOutcome" type="LIST"> <parameter name="allowedValues"> <list> <!-- Утвердить --> <value>approve</value> <!-- Отправить на доработку --> <value>reject</value> </list> </parameter> <parameter name="caseSensitive"> <value>true</value> </parameter> </constraint> </constraints> </property> </properties> <!-- Доступ к документам пакета --> <overrides> <!-- Документ может быть добавлен --> <property name="bpm:packageActionGroup"> <default>add_package_item_actions</default> </property> <!-- Документ может быть отредактирован --> <property name="bpm:packageItemActionGroup"> <default>edit_package_item_actions</default> </property> </overrides> </type> </types> <aspects> <aspect name="dir:performer"> <associations> <association name="dir:performer"> <source> <mandatory>true</mandatory> <many>false</many> </source> <target> <class>cm:person</class> <mandatory>true</mandatory> <many>false</many> </target> </association> </associations> </aspect> </aspects> </model>
Помещаем модель в ALFRESCO_HOME/tomcat/shared/classes/alfresco/extension/model/
Создаем процесс DirectiveProcess.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!-- Объявление необходимых пространств имен --> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <!-- Начало описания процесса --> <process id="PerformDirective" name="Исполнение внешних директив"> <!-- Начальный узел процесса --> <startEvent id="start" activiti:formKey="dir:start" /> <!-- Переход от старта к задаче ознакомления с директивой --> <sequenceFlow id='flow1' sourceRef='start' targetRef='inspection' /> <!-- Ознакомление с директивой и передача на исполнение --> <userTask id="inspection" name="Ознакомиться с документом и передать на исполнение." activiti:formKey="dir:inspection" > <extensionElements> <!-- Скрипт при создании задачи --> <!-- Устанавливаем срок исполнения и приоритет, если те не указаны --> <!-- Запоминаем начальника --> <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener"> <activiti:field name="script"> <activiti:string> if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority; execution.setVariable('manager', bpm_assignee.properties.userName); </activiti:string> </activiti:field> </activiti:taskListener> <!-- Скрипт при закрытии задачи --> <!-- Запоминаем исполнителя --> <activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener"> <activiti:field name="script"> <activiti:string> var performer = task.getVariable('dir_performer'); execution.setVariable('performer', performer.properties.userName); </activiti:string> </activiti:field> </activiti:taskListener> </extensionElements> <!-- Задача для начальника --> <humanPerformer> <resourceAssignmentExpression> <formalExpression>${bpm_assignee.properties.userName}</formalExpression> </resourceAssignmentExpression> </humanPerformer> </userTask> <!-- Переход от ознакомления с директивой к исполнениию --> <sequenceFlow id='flow2' sourceRef='inspection' targetRef='perform' /> <!--Исполнение поручения --> <!-- Второй способ обозначить владельца задачи - через activiti:assignee --> <!-- Задача для исполнителя --> <userTask id="perform" name="Исполнение поручения." activiti:formKey="dir:perform" activiti:assignee="${performer}" > <extensionElements> <!-- Скрипт при создании задачи --> <!-- Устанавливаем срок исполнения и приоритет, если те не указаны --> <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener"> <activiti:field name="script"> <activiti:string> if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority; </activiti:string> </activiti:field> </activiti:taskListener> </extensionElements> </userTask> <!-- Переход от исполнениия к проверке исполнения --> <sequenceFlow id='flow3' sourceRef='perform' targetRef='approve' /> <!-- Проверка исполнения --> <!-- Задача для начальника --> <userTask id="approve" name="Проверить исполнение поручения." activiti:formKey="dir:approve" activiti:assignee="${manager}" > <extensionElements> <!-- Скрипт при создании задачи --> <!-- Устанавливаем срок исполнения и приоритет, если те не указаны --> <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener"> <activiti:field name="script"> <activiti:string> if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority; </activiti:string> </activiti:field> </activiti:taskListener> <!-- Скрипт при закрытии задачи --> <!-- Устанавливаем результат --> <activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener"> <activiti:field name="script"> <activiti:string> execution.setVariable('dir_appOutcome', task.getVariable('dir_appOutcome')); </activiti:string> </activiti:field> </activiti:taskListener> </extensionElements> </userTask> <!-- Переход от проверки исполнения к развилке --> <sequenceFlow id='flow4' sourceRef='approve' targetRef='decision' /> <!-- Развилка: вернуться ли к исполнению или же окончить процесс --> <exclusiveGateway id="decision" name="Decision" /> <!-- Исполнение не утверждено: вернуться к задаче исполнения --> <sequenceFlow id='flow5' sourceRef='decision' targetRef='perform' > <conditionExpression xsi:type="tFormalExpression">${dir_appOutcome == 'reject'}</conditionExpression> </sequenceFlow> <!-- Исполнение утверждено: окончить процесс --> <sequenceFlow id='flow6' sourceRef='decision' targetRef='end' /> <!-- Конец процесса --> <endEvent id="end" /> </process> </definitions>
Помещаем процесс в ALFRESCO_HOME/tomcat/shared/classes/alfresco/extension/workflows/
Локализуем бизнес-процесс (dirWorkflow_ru_RU.properties):
PerformDirective.workflow.title=Обработка внешних директив PerformDirective.workflow.description=Ознакомиться с директивой и исполнить ее listconstraint.dir_propAppOutcome.approve=Утвердить исполнение listconstraint.dir_propAppOutcome.reject=Послать на доработку PerformDirective.node.inspection.transition.title=Направить на исполнение PerformDirective.node.inspection.transition.description=Направить на исполнение PerformDirective.node.perform.transition.title=Передать на утверждение PerformDirective.node.perform.transition.description=Передать на утверждение
Помещаем локализацию в ALFRESCO_HOME/tomcat/shared/classes/alfresco/extension/messages/
Настраиваем вэб-клиент (web-client-config-custom.xml):
<alfresco-config> <config evaluator="string-compare" condition="Languages"> <languages> <language locale="ru_RU">Russian</language> </languages> </config> <!-- Отображение бизнес процессов --> <!-- Подача директивы --> <config evaluator="node-type" condition="dir:start" replace="true"> <property-sheet> <!-- Разделитель --> <separator name="sep1" display-label-id="general" component-generator="HeaderSeparatorGenerator" /> <!-- Описание процесса --> <show-property name="bpm:workflowDescription" component-generator="TextAreaGenerator" /> <!-- Выбор начальника --> <show-association name="bpm:assignee" /> </property-sheet> </config> <!-- Ознакомление с директивой и передача на исполнение --> <config evaluator="node-type" condition="dir:inspection" replace="true"> <property-sheet> <!-- Разделитель --> <separator name="sep1" display-label-id="general" component-generator="HeaderSeparatorGenerator" /> <!-- Описание процесса --> <show-property name="bpm:workflowDescription" component-generator="TextAreaGenerator" /> <!-- Комментарий --> <show-property name="bpm:comment" component-generator="TextAreaGenerator" /> <!-- Выбор исполнителя --> <show-association name="dir:performer" /> </property-sheet> </config> <!-- Исполнение поручения --> <config evaluator="node-type" condition="dir:perform" replace="true"> <property-sheet> <!-- Разделитель --> <separator name="sep1" display-label-id="general" component-generator="HeaderSeparatorGenerator" /> <!-- Описание процесса --> <show-property name="bpm:workflowDescription" component-generator="TextAreaGenerator" /> <!-- Комментарий --> <show-property name="bpm:comment" component-generator="TextAreaGenerator" /> </property-sheet> </config> <!-- Проверка исполнения --> <config evaluator="node-type" condition="dir:approve" replace="true"> <property-sheet> <!-- Разделитель --> <separator name="sep1" display-label-id="general" component-generator="HeaderSeparatorGenerator" /> <!-- Описание процесса --> <show-property name="bpm:workflowDescription" component-generator="TextAreaGenerator" /> <!-- Комментарий --> <show-property name="bpm:comment" component-generator="TextAreaGenerator" /> <show-property name="dir:appOutcome" /> </property-sheet> </config> </alfresco-config>
Помещаем вэб-клиент в ALFRESCO_HOME/tomcat/shared/classes/alfresco/extension
Создаем загрузчик (dir-workflow-context.xml):
<?xml version='1.0' encoding='UTF-8'?> <!-- Описание моделей и процессов для загрузки --> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <beans> <!-- Регистрируем ресурсы --> <bean id="dir.workflowBootstrap" parent="workflowDeployer"> <property name="workflowDefinitions"> <list> <props> <!-- Тип процесса --> <prop key="engineId">activiti</prop> <!-- Путь --> <prop key="location">alfresco/extension/workflows/DirectiveProcess.xml</prop> <!-- MIME --> <prop key="mimetype">text/xml</prop> <!-- Загружать каждый раз --> <prop key="redeploy">true</prop> </props> </list> </property> <!-- Локализация --> <property name="labels"> <list> <value>alfresco.extension.messages.dirWorkflow</value> </list> </property> <!-- Список моделей для загрузки --> <property name="models"> <list> <value>alfresco/extension/model/DirectiveWorkflowModel.xml</value> </list> </property> </bean> </beans> <!-- Конец описания -->
И помещаем его в ALFRESCO_HOME/tomcat/shared/classes/alfresco/extension
Настраиваем пользовательский интерфейс для share (web-extension/share-config-custom.xml):
<!-- Настройки интерфейса --> <alfresco-config> <!-- Этим элементом можно включить режим отладки --> <config replace="true"> <flags> <client-debug>false</client-debug> <client-debug-autologging>false</client-debug-autologging> </flags> </config> <!-- Отображение информации при просмотре бизнес-процесса --> <config evaluator="string-compare" condition="activiti$PerformDirective"> <forms> <form> <!-- Список видимых полей --> <field-visibility> <show id="bpm:workflowDescription"/> <show id="bpm:assignee"/> <show id="packageItems" /> </field-visibility> <appearance> <!-- Блоки --> <set id="" appearance="title" label-id="workflow.set.general" /> <set id="assignee" appearance="title" label-id="dir_assignee" /> <set id="items" appearance="title" label-id="dir_items" /> <!-- Отображение полей --> <field id="bpm:workflowDescription" label-id="dir_description"> <control template="/org/alfresco/components/form/controls/textarea.ftl"> <control-param name="style">width: 95%</control-param> </control> </field> <field id="bpm:assignee" label-id="dir_assign_to" set="assignee" /> <field id="packageItems" set="items" label-id="dir_pitems" /> </appearance> </form> </forms> </config> <!-- Начальный узел процесса --> <config evaluator="task-type" condition="dir:start"> <forms> <form> <!-- Список видимых полей --> <field-visibility> <show id="bpm:workflowDescription"/> <show id="bpm:assignee"/> <show id="packageItems" /> </field-visibility> <appearance> <!-- Блоки --> <set id="" appearance="title" label-id="workflow.set.general" /> <set id="assignee" appearance="title" label-id="dir_assignee" /> <set id="items" appearance="title" label-id="dir_items" /> <!-- Отображение полей --> <field id="bpm:workflowDescription" label-id="dir_description"> <control template="/org/alfresco/components/form/controls/textarea.ftl"> <control-param name="style">width: 95%</control-param> </control> </field> <field id="bpm:assignee" label-id="dir_assign_to" set="assignee" /> <field id="packageItems" set="items" label-id="dir_pitems" /> </appearance> </form> </forms> </config> <!-- Ознакомление с директивой и передача на исполнение --> <config evaluator="task-type" condition="dir:inspection"> <forms> <form> <!-- Список видимых полей --> <field-visibility> <show id="bpm:workflowDescription"/> <show id="bpm:comment"/> <show id="dir:performer"/> <show id="transitions" /> <show id="packageItems" /> </field-visibility> <appearance> <!-- Блоки --> <set id="" appearance="title" label-id="workflow.set.general" /> <set id="assignee" appearance="title" label-id="dir_assignee" /> <set id="trans" appearance="" /> <set id="items" appearance="title" label-id="dir_items" /> <!-- Отображение полей --> <field id="bpm:workflowDescription" label-id="dir_description"> <control template="/org/alfresco/components/form/controls/textarea.ftl"> <control-param name="style">width: 95%</control-param> </control> </field> <field id="bpm:comment" label-id="dir_comment" /> <field id="dir:performer" label-id="dir_performer" set="assignee" /> <field id="transitions" set="trans" /> <field id="packageItems" set="items" label-id="dir_pitems" /> </appearance> </form> </forms> </config> <!--Исполнение поручения --> <config evaluator="task-type" condition="dir:perform"> <forms> <form> <!-- Список видимых полей --> <field-visibility> <show id="bpm:workflowDescription"/> <show id="bpm:comment"/> <show id="transitions" /> <show id="packageItems" /> </field-visibility> <appearance> <!-- Блоки --> <set id="" appearance="title" label-id="workflow.set.general" /> <set id="trans" appearance="" /> <set id="items" appearance="title" label-id="dir_items" /> <!-- Отображение полей --> <field id="bpm:workflowDescription" label-id="dir_description"> <control template="/org/alfresco/components/form/controls/textarea.ftl"> <control-param name="style">width: 95%</control-param> </control> </field> <field id="bpm:comment" label-id="dir_comment" /> <field id="transitions" set="trans" /> <field id="packageItems" set="items" label-id="dir_pitems" /> </appearance> </form> </forms> </config> <!--Проверка исполнения --> <config evaluator="task-type" condition="dir:approve"> <forms> <form> <!-- Список видимых полей --> <field-visibility> <show id="bpm:workflowDescription"/> <show id="bpm:comment"/> <show id="dir:appOutcome" /> <show id="packageItems" /> </field-visibility> <appearance> <!-- Блоки --> <set id="" appearance="title" label-id="workflow.set.general" /> <set id="items" appearance="title" label-id="dir_items" /> <!-- Отображение полей --> <field id="bpm:workflowDescription" label-id="dir_description"> <control template="/org/alfresco/components/form/controls/textarea.ftl"> <control-param name="style">width: 95%</control-param> </control> </field> <field id="bpm:comment" label-id="dir_comment" /> <field id="dir:appOutcome" label-id="workflow.field.outcome" > <control template="/org/alfresco/components/form/controls/workflow/activiti-transitions.ftl" /> </field> <field id="packageItems" set="items" label-id="dir_pitems" /> </appearance> </form> </forms> </config> </alfresco-config>
Помещаем вэб-клиент в ALFRESCO_HOME/tomcat/shared/classes/alfresco/web-extension
Локализуем метки интерфейса (dir_ru_RU.properties):
dir_assignee=Назначить ответственного dir_assign_to=Начальник подразделения dir_performer=Исполнитель dir_items=Документы dir_pitems=Директивы и пр. документы dir_description=Описание dir_comment=Комментарий
Помещаем локализацию в ALFRESCO_HOME/tomcat/shared/classes/alfresco/web-extension/messages/
Конфигурируем Spring bean для локализации интерфейса (custom-slingshot-application-context):
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'> <beans> <bean id="dir.resources" class="org.springframework.extensions.surf.util.ResourceBundleBootstrapComponent"> <property name="resourceBundles"> <list> <value>alfresco.web-extension.messages.dir</value> </list> </property> </bean> </beans>
Записываем его в ALFRESCO_HOME/tomcat/shared/classes/alfresco/web-extension
После рестарта альфрески заходим в localhost:8080/share, где в списке процессов мы видим наш процесс "Обработка внешних директив (Ознакомиться с директивой и исполнить ее)"
Updated
Вот так выглядит бизнес-процесс исполнения директив:
Прикрепленные файлы | Размер |
---|---|
workflows.zip | 10.63 кб |
start.png | 47.79 кб |
inspection.png | 52.53 кб |
perform.png | 53.14 кб |
approve.png | 54.17 кб |
diagram1.png | 10.99 кб |
Комментарии
24/10/2012 - 22:10
А где же в конце красивый скриншот открытой картинки модели процесса на странице деталей бизнес-процесса?;)
25/10/2012 - 10:39
Не подумала. :(
Добавила скрины каждого этапа-задачи в share.
25/10/2012 - 10:48
Здорово. Я имела в виду что-то типа http://www.alvexcore.com/img/ru/about/alvex-workflow-activiti.png, но можно и так :)
25/10/2012 - 12:21
Да, поняла, это будет полезно. Хорошо. Сделаю вечером обязательно.
З.Ы. Я вообще работаю в vi и jEdit, поэтому у меня со схемами напряженка. :) Вечерком у меня под рукой все инструменты будут
25/10/2012 - 12:34
Ок. Сама всегда все делаю в vi, хотя до activiti вообще еще не добралась, и не знаю, как там что рисовать.
30/10/2012 - 14:14
Здравствуйте! У меня, пожалуй, обратная проблема - не могу удалить процесс на activiti. Alfresco-4.0.d. Создала свой процесс в /shared/extention, не могла сначала ничего изменить в нём (после перезагрузки ничего не менялось), потом решила совсем удалить, но не получается! Не могли бы подсказать, как это правильно сделать?
30/10/2012 - 14:42
Для того, чтобы при обновлении файла процесса в share/extension обновлялся сам воркфлоу, надо обратить внимание на конфигурацию воркфлоу. Проверьте внимательно в файле *-workflow-context часть, описывающую файл процесса. У меня вот эта часть:
Обратите внимание на значение ключа redeploy
Что означает перезагрузку при обновлении файла. Может быть у Вас это описано так
Измените false на true, и тогда при каждом рестарте альфрески процесс будет перезагружаться
Кроме того, может быть, Вы просто копируете файл процесса. Но просто перезаписать файл процесса в шаре не перезагружает вокрфлоу. Если Вы деплоете воркфлоу таким образом, то после обновления файла Вы должны рестартовать сам сервер. Чтобы обновлять воркфлоу без перезагрузки сервера, Вы должны пользоваться интерфейсом самого альфрески для деплоймента процесса и модели.
Теперь что касается удаления воркфлоу. Дело в том, что при прохождении процесса его история записывается в альфреске. Т е чтобы начисто удалить воркфлоу, надо отключить все активные процессы, очистить всю историю пройденных процессов, если они были, и после этого удалить все его файлы (процесс, модель и пр.), иначе альфреска так и будет ругаться.
Но Вы можете пойти другим путем: Вы можете не удалять файлы, а вернуть их на место и спрятать сам воркфлоу вот таким образом Если Вы используете activity, то префикс jbpm в <workflow name="jbpm$doc:testAppRej"/> меняется на activity, а doc:testAppRej на имя Вашего процесса. Пример:
<workflow name="activiti$activitiReview"/>
30/10/2012 - 14:53
Если Вы все же хотите совсем убрать процесс из системы, то, как я и сказала, недостаточно лишь удалить его файлы. Надо зайти в администраторскую консоль (http://localhost:8080/alfresco/faces/jsp/admin/workflow-console.jsp). В ней Вы можете увидеть все воркфлоу, набрав:
show definitions all
А чтобы "раздеплоить" воркфлоу, наберите:
undeploy definition <workflow definition name>
01/11/2012 - 13:41
Огромное спасибо за обстоятельный ответ! Буду пробовать.
01/11/2012 - 14:59
Не за что! Надеюсь, получится.
Кстати, здесь на портале у Фуфлера есть коммент на ту же тему. Посмотрите здесь, в последних комментариях.
10/06/2013 - 11:09
10/06/2013 - 11:18
Но, вообще, я бы посоветовала при таком раскладе, когда уже непонятно, из-за чего там перекосилось, переставить альфреску, отработать Ваш новый воркфлоу (без деплоя моего) и потом уже, когда все заработает, ставить альвексю А то сейчас уже замылена картина
10/06/2013 - 11:23
10/06/2013 - 14:44
org.alfresco.error.AlfrescoRuntimeException: 05100162 Exception in Transaction
Caused by: org.dom4j.DocumentException: Error on line 178 of document : The element type "alfresco-config" must be terminated by the matching end-tag "". Nested exception: The element type "alfresco-config" must be terminated by the matching end-tag "". at org.dom4j.io.SAXReader.read(SAXReader.java:482) at org.dom4j.io.SAXReader.read(SAXReader.java:343) at org.springframework.extensions.config.xml.XMLConfigService.parse(XMLConfigService.java:212)
10/06/2013 - 14:54
Как Вы уже увидели, практически все файлы процесса - модели, описания процессов, описание интерфейсов и клиентов - это XML-ки. Соответственно, все элементы и атрибуты должны писаться правильно и закрываться в правильном месте.
Я Вам посоветую следующее: править файлы процесса в редакторах, которые имеют встроенные парсеры. К примеру, я использую jEdit с установленным на него XML-плаггином. В нем очень легко олавливать ошибки xml-ого синтаксиса
10/06/2013 - 16:29
2013-06-10 18:59:04,821 ERROR [extensions.config.BaseConfigService] [localhost-startStop-1] Input stream invalid - skipped for source: classpath:alfresco/extension/web-client-config-custom.xml' org.springframework.extensions.config.ConfigException: 05100001 Failed to parse config stream at org.springframework.extensions.config.xml.XMLConfigService.parse(XMLConfigService.java:224) at org.springframework.extensions.config.BaseConfigService.appendConfig(BaseConfigService.java:268) at org.springframework.extensions.config.BaseConfigService.parse(BaseConfigService.java:298) at org.springframework.extensions.config.xml.XMLConfigService.initConfig(XMLConfigService.java:132) at org.alfresco.repo.config.xml.RepoXMLConfigService.access$001(RepoXMLConfigService.java:53) at org.alfresco.repo.config.xml.RepoXMLConfigService$1.execute(RepoXMLConfigService.java:133) at org.alfresco.repo.config.xml.RepoXMLConfigService$1.execute(RepoXMLConfigService.java:127) at org.alfresco.repo.transaction.RetryingTransactionHelper.doInTransaction(RetryingTransactionHelper.java:433) at org.alfresco.repo.transaction.RetryingTransactionHelper.doInTransaction(RetryingTransactionHelper.java:323) at org.alfresco.repo.config.xml.RepoXMLConfigService.initRepoConfig(RepoXMLConfigService.java:125) at org.alfresco.repo.config.xml.RepoXMLConfigService.resetRepoConfig(RepoXMLConfigService.java:195) at org.alfresco.repo.config.xml.RepoXMLConfigService.initConfig(RepoXMLConfigService.java:109) at org.alfresco.repo.config.xml.RepoXMLConfigService$2.doWork(RepoXMLConfigService.java:241) at org.alfresco.repo.security.authentication.AuthenticationUtil.runAs(AuthenticationUtil.java:529) at org.alfresco.repo.config.xml.RepoXMLConfigService.onBootstrap(RepoXMLConfigService.java:237) at org.springframework.extensions.surf.util.AbstractLifecycleBean.onApplicationEvent(AbstractLifecycleBean.java:56) at org.alfresco.repo.management.SafeApplicationEventMulticaster.multicastEventInternal(SafeApplicationEventMulticaster.java:209) at org.alfresco.repo.management.SafeApplicationEventMulticaster.multicastEvent(SafeApplicationEventMulticaster.java:180) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:303) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:911) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:428) at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47) at org.alfresco.web.app.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:63) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:618) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:963) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1600) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) at java.util.concurrent.FutureTask.run(FutureTask.java:166) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) at java.lang.Thread.run(Thread.java:722) Caused by: org.dom4j.DocumentException: Error on line 10 of document : Invalid byte 2 of 2-byte UTF-8 sequence. Nested exception: Invalid byte 2 of 2-byte UTF-8 sequence. at org.dom4j.io.SAXReader.read(SAXReader.java:482) at org.dom4j.io.SAXReader.read(SAXReader.java:343) at org.springframework.extensions.config.xml.XMLConfigService.parse(XMLConfigService.java:212) ... 38 more 2013-06-10 18:59:27,288 INFO [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl 2013-06-10 18:59:27,425 INFO [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js 2013-06-10 18:59:27,426 INFO [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl 2013-06-10 18:59:27,431 INFO [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js 2013-06-10 18:59:32,479 INFO [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 342 Web Scripts (+0 failed), 355 URLs 2013-06-10 18:59:32,479 INFO [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 8 Package Description Documents (+0 failed) 2013-06-10 18:59:32,479 INFO [extensions.webscripts.DeclarativeRegistry] [localhost-startStop-1] Registered 0 Schema Description Documents (+0 failed) 2013-06-10 18:59:32,710 INFO [extensions.webscripts.AbstractRuntimeContainer] [localhost-startStop-1] Initialised Spring Surf Container Web Script Container (in 5270.954ms) 2013-06-10 18:59:32,718 INFO [extensions.webscripts.TemplateProcessorRegistry] [localhost-startStop-1] Registered template processor freemarker for extension ftl 2013-06-10 18:59:32,725 INFO [extensions.webscripts.ScriptProcessorRegistry] [localhost-startStop-1] Registered script processor javascript for extension js 2013-06-10 18:59:34,602 INFO [web.site.EditionInterceptor] [http-apr-8080-exec-9] Successfully retrieved license information from Alfresco. 2013-06-10 18:59:47,464 INFO [web.scripts.ImapServerStatus] [http-apr-8080-exec-6] Successfully retrieved IMAP server status from Alfresco: disabled
10/06/2013 - 16:30
11/06/2013 - 08:33
11/06/2013 - 10:57
12/06/2013 - 12:43
12/06/2013 - 13:32
12/06/2013 - 17:54
12/06/2013 - 18:02
Зарегистрированным пользователям доступен обмен прямыми сообщениями. После регистрации в профиле других пользователей (например, Angelina) Вам будет видна вторая вкладка "Отправить сообщение".
13/06/2013 - 16:02
03/12/2012 - 13:34
03/12/2012 - 14:43
03/12/2012 - 15:33
03/12/2012 - 16:30
03/12/2012 - 16:33
03/12/2012 - 16:36
30/05/2013 - 16:05
30/05/2013 - 16:38
31/05/2013 - 08:44
31/05/2013 - 11:58
1. Вы знаете, что процесс всегда поднимается, к примеру, на Иванова. Тогда в модели на старте Вы не указываете в аспектах bpm:assignee, а в процессе в соответствующем атрибуте прямо прописываете userid Иванова:
2. У Вас в модели остается bpm:assignee, но процесс Вы поднимаете автоматически, из-вне неким скриптом и владельца задачи Вы прописываете прямо в скрипте. Например:
3. Вы добавляете в процесс процедуру старта (start event). В процедуре старта Вы создаете переменную процесса, к примеру, assignee, и инициализируете, присваивая значение "ivanov". При этом bpm:assignee также отсутствует в аспектах старта в модели:
31/05/2013 - 13:55
31/05/2013 - 14:25
Надо четко понимать, какие изменения и как Вы производите.
Вы без проблем можете производить изменения в описании процесса, как в части скриптов, так и части добавления процедур и развилок, единственное условие - это соответствие задач описанию оных в модели процесса. Т е просто убирать userTask или добавить Вы не можете, они всегда соответствуют модели. Единственно, помните, что уже поднятые процессы будут идти по старому сценарию.
Если же Вы меняете модель процесса, тот тут есть свои законы. Смотрите, есть правило: все изменения на уже установленной модели в альфреско должны происходить в порядке возрастания. Т е Вы можете в модели добавить к каждому шагу аспекты, но убирать уже существующие не можете. Вы можете добавлять в модели типы, но убирать существующие - не можете. И т д . Вы даже не можете, к примеру, поменять свойство аспекта с mandatory=true на mandatory=false. Это тоже считается правкой с убыванием.
Если же Вы все же хотите убрать что-то из существующей, уже задеплоенной в альфреске модели, Вы или должны убрать существующую (а это головная боль, поскольку надо ее удалять из базы и прочее), или же можете пойти более легким путем: создайте новую модель с новым описанием. При этом надо помнить, что Ваши неймспейсы (а отсюда и префиксы), которые Вы объявляете в новой модели и название этой модели должны быть новыми и уникальными.
У меня такое ощущение, что Вы пытаетесь изменить процесс, который уже существует и работает на Вашей альфреске. И изменения эти не в порядке увеличения. Судя по всему, Вы пытаетесь удалить аспект bpm:assignee в модели. Если это так, то лучше все же создать новый процесс. Еще более простой вариант, если Вы просто пока "играетесь" процессами локально - это переставить альфреску :)
Или же, если все дело в этом bpm:assignee, оставьте этот аспект, не рисуйте его в клиенте и интерфейса, но проставьте его значение через стартовую процедуру, поскольку он обязательный - это аспект. Если же дело не в аспекте, то проверьте правки модели и описания на то, о чем я говорила выше.
Кроме того, надо помнить, что процесс - это не только модель и описание. Это еще вэб-клиент и интерфейс. Т е там тоже надо вносить соответствующие правки.
Вы знаете, мне кажется, что Вы пока не совсем себе представляете работу процессов на альфреске. Знаете, я Вам посоветую хорошую книжку: "Professional Alfresco® Practical Solutions for Enterprise Content Management
Alfresco", написанное в соавторстве с David Caruana, John Newton, Michael Farman, Michael G. Uzquiano, Kevin Roast. Описание процессов там дано на JBPM, но все остальное в альфреске не изменилось. Особенно там подробно описаны создание моделей. Важно понимать. как модель связана/определяет процесс.
31/05/2013 - 14:38
31/05/2013 - 14:42
31/05/2013 - 14:50
31/05/2013 - 14:44
31/05/2013 - 14:48
31/05/2013 - 15:02
Кстати, поля описываются также в модели через свойства и аспекты. В них Вы можете устанавливать тип поля - будет ли это список, целое число, дата и прочее, а также будет ли поле обязательным, множественным и прочее. А на форме процесса, при загрузке в share, вид поля Вы можете описать сами. Формы, а также элементы управления в Альфреско рисуются с помощью FreeMarker-а и JavaScript-а. Также в самой альфреске есть некоторые готовые шаблоны эти элементов, такие, как дата, простые списки (в альфреско они представлены элементов select), ассоциации... Все это также описано в той книжке. Вообще, полезная книженция :)
31/05/2013 - 15:04
31/05/2013 - 14:43
03/06/2013 - 10:42
03/06/2013 - 11:05
Также можно самому создать ссылку на данный процесс. Выглядит ссылка примерно вот так:
где 206006 - уникальный номер процесса
У каждого процесса свой идентификационный номер, генерируемый самой альфреской. В скрипте внутри описания процессов напишите:
где procID и есть тот самый идентификационный номер.
03/06/2013 - 11:22
03/06/2013 - 11:33
03/06/2013 - 11:53
03/06/2013 - 12:13
У меня никогда такой ситуации не возникало, разве что Вы сами прописываете ссылку, в которой указываете идентификационный номер несуществующего процесса.
03/06/2013 - 12:18
03/06/2013 - 12:27
Судя по всему, баг определенной версии альфрески. Прямо сейчас у меня 4.0.с Там такого не происходит.
05/06/2013 - 12:33
05/06/2013 - 13:22
03/06/2013 - 12:27
03/06/2013 - 12:39
03/06/2013 - 12:40
07/06/2013 - 10:36
07/06/2013 - 15:18
07/06/2013 - 15:39
10/06/2013 - 07:10
27/06/2013 - 09:31
27/06/2013 - 11:44
dir:appOutcome
значениями которого могут быть approve или rejectЧтобы послать уведомление о решении начальника, мы должны извлечь значение решения и, в зависимости от этого значения, скомпановать письмо. Шаг проверки исполнения будет выглядеть следующим образом:
27/06/2013 - 12:46
27/06/2013 - 13:28
Все, что находится на рабочем столе - есть дашлеты. Задачи, которые поднимаются у людей, собираются и показываются в дашлете "Мои задачи" Т е Вам нужно или же написать дашлет, отслеживающий состояние, или же генерить параллельную задачу инициатору, в которой будет описана вся информация текущая.
Также, если Вы выберите в верху рабочего стола Еще - Запущенные мной деловые процессы, Вы увидите список процессов, инициированных данным юзером. И там, нажав на линк соответствующего процесса, увидите все его состояния.
27/06/2013 - 13:34
27/06/2013 - 13:53
Первый способ - это написать простенький процесс, состоящий из одного таска "для ознакомления" и содержащий все необходимые поля. Тогда в скрипте процесса исполнения директивы в процедурах поднимать java script-ом поднимать эти задачи. Код скрипта бывает примерно такой:
Второй способ для генерации параллельных задач - это использовать структуру multiInstanceLoopCharacteristics. Пример ее использования находится в самой Альфреско в ALFRESCO_HOME/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/workflow/parallel-review.bpmn20.xml
28/06/2013 - 09:26
28/06/2013 - 11:19
Можно. Для этого Вы добавляете соответствующие свойства в модель, а в описании процесса в нужном месте ставите развилку.
"Если есть bpm:startTask обязателен ли bpm:workflowTask ?"
На самом деле вопрос включает два подвопроса. Если Вы имеете в виду, можно ли в модели описать только один стартТаск, то ответ - да, можно. Если же вопрос касается того, можно ли в описании процесса описать только один стартТаск, то здесь ответ - нет. Поскольку в описании процессов на активити в каждом процессе, кроме начальной и конечной процедуры необходимо описать хотя бы один userTask. Хотя и эту проблему можно решить. Если Ваш процесс обязательно должен состоять из стартовой процедуры и конечной (т е воркфлоу в Альфреске используется, например, как форма заполнения чего-то), то можно ввести timer event и переходить со старта на таймер, ждать пару секунд, а затем завершить процесс.
03/07/2013 - 14:08
Пытаюсь сделать простенький процесс на основе примера.
Возникла проблема: при описании модели для startTask не указал аспект bpm:assignee. Обнаружилось это, когда при попытке запуска процесса нет возможности указать исполнителя. Добавил в модель аспект, добавлять ведь можно, на сколько я понимаю? Однако ничего не меняется. В какую сторону копать?
Спасибо.