Skip to content

Commit

Permalink
added FormAwareServiceTask for CMMN and BPMN
Browse files Browse the repository at this point in the history
  • Loading branch information
WelschChristopher committed Jan 9, 2025
1 parent 706e10f commit cd7aefe
Show file tree
Hide file tree
Showing 14 changed files with 297 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public interface BpmnXMLConstants {
public static final String ELEMENT_EVENT_LISTENER = "eventListener";
public static final String ELEMENT_TASK_LISTENER = "taskListener";
public static final String ELEMENT_SCRIPT = "script";
public static final String ELEMENT_FORM_REFERENCE = "formreference";

public static final String ATTRIBUTE_LISTENER_EVENT = "event";
public static final String ATTRIBUTE_LISTENER_EVENTS = "events";
public static final String ATTRIBUTE_LISTENER_ENTITY_TYPE = "entityType";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ public class BpmnXMLConverter implements BpmnXMLConstants {
addConverter(new ServiceTaskXMLConverter());
addConverter(new HttpServiceTaskXMLConverter());
addConverter(new CaseServiceTaskXMLConverter());
addConverter(new FormAwareServiceTaskXMLConverter());
addConverter(new SendEventServiceTaskXMLConverter());
addConverter(new ExternalWorkerServiceTaskXMLConverter());
addConverter(new SendTaskXMLConverter());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flowable.bpmn.converter;

import org.flowable.bpmn.model.BaseElement;
import org.flowable.bpmn.model.FormAwareServiceTask;

/**
* @author Christopher Welsch
*/
public class FormAwareServiceTaskXMLConverter extends ServiceTaskXMLConverter {

@Override
public Class<? extends BaseElement> getBpmnElementType() {
return FormAwareServiceTask.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.flowable.bpmn.model.ExtensionAttribute;
import org.flowable.bpmn.model.ExtensionElement;
import org.flowable.bpmn.model.ExternalWorkerServiceTask;
import org.flowable.bpmn.model.FormAwareServiceTask;
import org.flowable.bpmn.model.HttpServiceTask;
import org.flowable.bpmn.model.ImplementationType;
import org.flowable.bpmn.model.SendEventServiceTask;
Expand Down Expand Up @@ -130,7 +131,19 @@ protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model)
serviceTask = new ExternalWorkerServiceTask();

} else {
serviceTask = new ServiceTask();
String formKey = BpmnXMLUtil.getAttributeValue(ATTRIBUTE_FORM_FORMKEY, xtr);
if (StringUtils.isNotEmpty(formKey)) {
FormAwareServiceTask formAwareServiceTask = new FormAwareServiceTask();
formAwareServiceTask.setFormKey(formKey);

String formFieldValidation = BpmnXMLUtil.getAttributeValue(ATTRIBUTE_FORM_FIELD_VALIDATION, xtr);
if (StringUtils.isNotEmpty(formKey)) {
formAwareServiceTask.setValidateFormFields(formFieldValidation);
}
serviceTask = formAwareServiceTask;
} else {
serviceTask = new ServiceTask();
}
}

BpmnXMLUtil.addXMLLocation(serviceTask, xtr);
Expand Down Expand Up @@ -179,7 +192,6 @@ protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model)
} else {
parseChildElements(getXMLElementName(), serviceTask, model, xtr);
}

return serviceTask;
}

Expand All @@ -198,6 +210,9 @@ protected void writeAdditionalAttributes(BaseElement element, BpmnModel model, X
writeHttpServiceTaskAdditionalAttributes((HttpServiceTask) element, model, xtw);

} else {
if (element instanceof FormAwareServiceTask formAwareServiceTask) {
writeFormAwareServiceTaskAdditionalAttributes(formAwareServiceTask, xtw);
}
writeServiceTaskAdditionalAttributes((ServiceTask) element, xtw);
}
}
Expand Down Expand Up @@ -273,6 +288,16 @@ protected void writeHttpServiceTaskAdditionalAttributes(HttpServiceTask httpServ
writeServiceTaskAdditionalAttributes(httpServiceTask, xtw);
}

protected void writeFormAwareServiceTaskAdditionalAttributes(FormAwareServiceTask formAwareServiceTask, XMLStreamWriter xtw) throws Exception {
if (StringUtils.isNotEmpty(formAwareServiceTask.getFormKey())) {
writeQualifiedAttribute(ATTRIBUTE_FORM_FORMKEY, formAwareServiceTask.getFormKey(), xtw);
}

if (StringUtils.isNotEmpty(formAwareServiceTask.getValidateFormFields())) {
writeQualifiedAttribute(ATTRIBUTE_FORM_FIELD_VALIDATION, formAwareServiceTask.getValidateFormFields(), xtw);
}
}

protected void writeServiceTaskAdditionalAttributes(ServiceTask element, XMLStreamWriter xtw) throws Exception {
ServiceTask serviceTask = element;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<attribute name="formKey" type="string">
<annotation>
<documentation>
Attribute used on a startEvent or a userTask.
Attribute used on a startEvent, userTask or serviceTask.
The value can be anything. The default form support in Flowable
assumes that this is a reference to a form html file used in the deployment
of the process definition. But this key can also be something completely different,
Expand All @@ -81,7 +81,7 @@
Allows to specify a custom class that will be called during the parsing
of the form information. This way, it is possible to use custom forms and form handling.
This class must implement the
org.activiti.engine.inpl.form.FormHamdler/StartFormHandler/taskFormHandler interface
org.activiti.engine.impl.form.FormHandler/StartFormHandler/taskFormHandler interface
(specific interface depending on the activity).
</documentation>
</annotation>
Expand All @@ -96,8 +96,8 @@
<element name="formProperty">
<annotation>
<documentation>
Subelement of the extensionsElement of activities that support forms.
Allows to specifies properties (!= process variables) for a form. See documentation chapter on
Sub element of the extensionsElement of activities that support forms.
Allows to specify properties (!= process variables) for a form. See documentation chapter on
form properties.
</documentation>
</annotation>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flowable.editor.language.xml;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FieldExtension;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.FormAwareServiceTask;
import org.flowable.editor.language.xml.util.BpmnXmlConverterTest;

class FormAwareServiceTaskConverterTest {

@BpmnXmlConverterTest("formAwareServiceTask.bpmn")
void validateModelWithFormReference(BpmnModel model) {
FlowElement flowElement = model.getMainProcess().getFlowElement("servicetask");
assertThat(flowElement)
.isInstanceOfSatisfying(FormAwareServiceTask.class, formAwareServiceTask -> {
assertThat(formAwareServiceTask.getId()).isEqualTo("servicetask");
assertThat(formAwareServiceTask.getName()).isEqualTo("FormAwareServiceTask");
assertThat(formAwareServiceTask.getImplementation())
.isEqualTo("${delegateExpression}");
assertThat(formAwareServiceTask.getImplementationType())
.isEqualTo("delegateExpression");
assertThat(formAwareServiceTask.getValidateFormFields())
.isEqualTo("true");
assertThat(formAwareServiceTask.getFormKey())
.isEqualTo("someFormKey");
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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" xmlns:design="http://flowable.org/design" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://flowable.org/test" design:palette="flowable-work-process-palette">

<process id="process" name="process1" isExecutable="true">
<endEvent id="end"></endEvent>
<sequenceFlow id="flow1" sourceRef="start" targetRef="servicetask"></sequenceFlow>
<serviceTask id="servicetask" name="FormAwareServiceTask" flowable:delegateExpression="${delegateExpression}" flowable:formKey="someFormKey" flowable:formFieldValidation="true">

</serviceTask>
<startEvent id="start"></startEvent>
<sequenceFlow id="flow2" sourceRef="servicetask" targetRef="end"></sequenceFlow>
</process>
</definitions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flowable.bpmn.model;

import java.util.List;

/**
* @author Christopher Welsch
*/
public class FormAwareServiceTask extends ServiceTask implements HasValidateFormFields {

protected String validateFormFields;
protected String formKey;

@Override
public String getValidateFormFields() {
return validateFormFields;
}

@Override
public void setValidateFormFields(String validateFormFields) {
this.validateFormFields = validateFormFields;
}

public String getFormKey() {
return formKey;
}

public void setFormKey(String formKey) {
this.formKey = formKey;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.flowable.cmmn.model.CasePageTask;
import org.flowable.cmmn.model.CmmnElement;
import org.flowable.cmmn.model.ExternalWorkerServiceTask;
import org.flowable.cmmn.model.FormAwareServiceTask;
import org.flowable.cmmn.model.HttpServiceTask;
import org.flowable.cmmn.model.ImplementationType;
import org.flowable.cmmn.model.ScriptServiceTask;
Expand Down Expand Up @@ -52,7 +53,21 @@ protected CmmnElement convert(XMLStreamReader xtr, ConversionHelper conversionHe
if (type != null) {

if (Objects.equals(type, ServiceTask.JAVA_TASK)) {
task = convertToJavaServiceTask(xtr, className);
String formKey = xtr.getAttributeValue(CmmnXmlConstants.FLOWABLE_EXTENSIONS_NAMESPACE, CmmnXmlConstants.ATTRIBUTE_FORM_KEY);
ServiceTask serviceTask;

if (StringUtils.isNotEmpty(formKey)) {
FormAwareServiceTask formAwareServiceTask = new FormAwareServiceTask();
formAwareServiceTask.setFormKey(formKey);
formAwareServiceTask.setValidateFormFields(
xtr.getAttributeValue(CmmnXmlConstants.FLOWABLE_EXTENSIONS_NAMESPACE, CmmnXmlConstants.ATTRIBUTE_FORM_FIELD_VALIDATION));
serviceTask = formAwareServiceTask;
} else {
serviceTask = new ServiceTask();
}

convertToJavaServiceTask(xtr, className, serviceTask);
task = serviceTask;

} else if (Objects.equals(type, HttpServiceTask.HTTP_TASK)) {
task = convertToHttpTask(xtr, className);
Expand Down Expand Up @@ -83,8 +98,7 @@ protected CmmnElement convert(XMLStreamReader xtr, ConversionHelper conversionHe
return task;
}

protected Task convertToJavaServiceTask(XMLStreamReader xtr, String className) {
ServiceTask serviceTask = new ServiceTask();
protected void convertToJavaServiceTask(XMLStreamReader xtr, String className, ServiceTask serviceTask) {
serviceTask.setType(ServiceTask.JAVA_TASK);

String expression = xtr.getAttributeValue(CmmnXmlConstants.FLOWABLE_EXTENSIONS_NAMESPACE, CmmnXmlConstants.ATTRIBUTE_EXPRESSION);
Expand All @@ -110,7 +124,6 @@ protected Task convertToJavaServiceTask(XMLStreamReader xtr, String className) {
serviceTask.setStoreResultVariableAsTransient(
Boolean.parseBoolean(xtr.getAttributeValue(CmmnXmlConstants.FLOWABLE_EXTENSIONS_NAMESPACE, CmmnXmlConstants.ATTRIBUTE_STORE_RESULT_AS_TRANSIENT)));

return serviceTask;
}

protected Task convertToHttpTask(XMLStreamReader xtr, String className) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.apache.commons.lang3.StringUtils;
import org.flowable.cmmn.converter.CmmnXmlConverterOptions;
import org.flowable.cmmn.model.CmmnModel;
import org.flowable.cmmn.model.FormAwareServiceTask;
import org.flowable.cmmn.model.HttpServiceTask;
import org.flowable.cmmn.model.ImplementationType;
import org.flowable.cmmn.model.ScriptServiceTask;
Expand Down Expand Up @@ -118,4 +119,26 @@ protected Class<? extends ServiceTask> getExportablePlanItemDefinitionClass() {
return ScriptServiceTask.class;
}
}

public static class FormAwareServiceTaskExport extends AbstractServiceTaskExport<FormAwareServiceTask> {

@Override
protected Class<? extends ServiceTask> getExportablePlanItemDefinitionClass() {
return FormAwareServiceTask.class;
}

@Override
public void writePlanItemDefinitionSpecificAttributes(ServiceTask serviceTask, XMLStreamWriter xtw) throws Exception {
super.writePlanItemDefinitionSpecificAttributes(serviceTask, xtw);
FormAwareServiceTask formAwareServiceTask = (FormAwareServiceTask) serviceTask;
if (StringUtils.isNotBlank(formAwareServiceTask.getFormKey())) {
xtw.writeAttribute(FLOWABLE_EXTENSIONS_PREFIX, FLOWABLE_EXTENSIONS_NAMESPACE, ATTRIBUTE_FORM_KEY, formAwareServiceTask.getFormKey());
}
if (StringUtils.isNotBlank(formAwareServiceTask.getValidateFormFields())) {
xtw.writeAttribute(FLOWABLE_EXTENSIONS_PREFIX, FLOWABLE_EXTENSIONS_NAMESPACE, ATTRIBUTE_FORM_FIELD_VALIDATION,
formAwareServiceTask.getValidateFormFields());
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class PlanItemDefinitionExport implements CmmnXmlConstants {
addPlanItemDefinitionExport(new AbstractServiceTaskExport.ServiceTaskExport());
addPlanItemDefinitionExport(new AbstractServiceTaskExport.HttpServiceTaskExport());
addPlanItemDefinitionExport(new AbstractServiceTaskExport.ScriptServiceTaskExport());
addPlanItemDefinitionExport(new AbstractServiceTaskExport.FormAwareServiceTaskExport());
addPlanItemDefinitionExport(new CasePageTaskExport());
addPlanItemDefinitionExport(new ExternalWorkerServiceTaskExport());
addPlanItemDefinitionExport(new MilestoneExport());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flowable.test.cmmn.converter;

import static org.assertj.core.api.Assertions.assertThat;

import org.flowable.cmmn.model.CmmnModel;
import org.flowable.cmmn.model.FormAwareServiceTask;
import org.flowable.cmmn.model.PlanItemDefinition;
import org.flowable.test.cmmn.converter.util.CmmnXmlConverterTest;

/**
* @author Christopher Welsch
*/
class FormAwareServiceTaskConverterTest {

@CmmnXmlConverterTest("org/flowable/test/cmmn/converter/formAwareServiceTask.cmmn")
public void validateModelWithCommaSeparatedStringExpressionCandidates(CmmnModel cmmnModel) {
assertThat(cmmnModel).isNotNull();

PlanItemDefinition itemDefinition = cmmnModel.findPlanItemDefinition("task1");
assertThat(itemDefinition)
.isInstanceOfSatisfying(FormAwareServiceTask.class, formAwareServiceTask -> {
assertThat(formAwareServiceTask.getId()).isEqualTo("task1");
assertThat(formAwareServiceTask.getName()).isEqualTo("FormAwareServiceTask");
assertThat(formAwareServiceTask.getImplementationType())
.isEqualTo("delegateExpression");
assertThat(formAwareServiceTask.getValidateFormFields())
.isEqualTo("true");
assertThat(formAwareServiceTask.getFormKey())
.isEqualTo("someFormKey");
});

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/CMMN/20151109/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/cmmn" xmlns:cmmndi="http://www.omg.org/spec/CMMN/20151109/CMMNDI" xmlns:dc="http://www.omg.org/spec/CMMN/20151109/DC" xmlns:di="http://www.omg.org/spec/CMMN/20151109/DI" xmlns:design="http://flowable.org/design" targetNamespace="http://flowable.org/cmmn" design:palette="flowable-work-case-palette">
<case id="myCase" name="My Case">
<casePlanModel id="mainPlanModel" name="Case plan model">
<planItem id="planItem1" name="Task 1" definitionRef="task1"/>
<task id="task1" name="FormAwareServiceTask" flowable:type="java" flowable:delegateExpression="${someDelegateExpression}" flowable:formKey="someFormKey" flowable:formFieldValidation="true">
</task>
</casePlanModel>
</case>
</definitions>
Loading

0 comments on commit cd7aefe

Please sign in to comment.