cancel
Showing results for 
Search instead for 
Did you mean: 

Activiti designer 5.14 removes custom form property information

k0k0pelli
Champ in-the-making
Champ in-the-making
Hi!
We implemented an extension for the activiti engine which allows us to use the form mechanism of activiti together with our own custom form property fields. We are using activiti:value inside a activiti:formProperty xml element to specify additional form information, such as column and row information, and so on. For processing this additional information, we extended the class org.activiti.engine.impl.form.FormTypes and implemented our own org.activiti.engine.form.FormProperty classes.

For creating the forms we have been using Activiti Designer which worked quite well so far. However, since we are using Activiti designer 5.14 instead of 5.12, our form information for our custom types is removed when switching to the form property editor and storing changes. With 5.12 it worked well.

To reproduce the problem, open the attached model in Activiti Designer 5.14. Open the properties of the usertask1 and change to the Form tab. After that, store the model.

The original example source code of the bpmn model looks like this:

<?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">
  <signal id="sigAbbruch" name="Abbruch"></signal>
  <process id="myProcess" name="My process" isExecutable="true"
     activiti:candidateStarterGroups="ICT@dummy.com">
    <documentation>${test}</documentation>
    <startEvent id="startevent1" name="Start" activiti:initiator="initiator"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <userTask id="usertask1" name="Computer Konto"
       activiti:candidateUsers="#{pojo.currUser().principal}"
       activiti:candidateGroups="ICT@dummy.com">
      <documentation>${serviceContext.getAttribute("test")}</documentation>
      <extensionElements>
        <activiti:formProperty id="lastName" name="lastName"
          type="com.dummy.xs.wfapps.forms.xs.XSTextField" required="true">
          <activiti:value id="col" name="0"></activiti:value>
          <activiti:value id="row" name="0"></activiti:value>
          <activiti:value id="width" name="1"></activiti:value>
          <activiti:value id="height" name="1"></activiti:value>
        </activiti:formProperty>
        ….
      </extensionElements>
    </userTask>
     ….
  </process>
   ….
</definitions>



After editing with the  form editor of Activiti Designer 5.14, it looks like this:

<?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">
  <signal id="sigAbbruch" name="Abbruch"></signal>
  <process id="myProcess" name="My process" isExecutable="true"
     activiti:candidateStarterGroups="ICT@dummy.com">
    <documentation>${test}</documentation>
    <startEvent id="startevent1" name="Start" activiti:initiator="initiator"></startEvent>
    <endEvent id="endevent1" name="End"></endEvent>
    <userTask id="usertask1" name="Computer Konto"
       activiti:candidateUsers="#{pojo.currUser().principal}"
       activiti:candidateGroups="ICT@dummy.com">
      <documentation>${serviceContext.getAttribute("test")}</documentation>
      <extensionElements>
        <activiti:formProperty id="lastName" name="lastName"
           type="com.dummy.xs.wfapps.forms.xs.XSTextField" required="true"></activiti:formProperty>
        ….
      </extensionElements>
    </userTask>
    ….
  </process>
  ….
</definitions>


My questions:
First, is it the right way to introduce custom form properties as described above or is there a better way to provide additional information for custom form properties? Is there something I have missed? Second, is Activiti Designer 5.14 meant to act like this or is it rather a bug?

5 REPLIES 5

frederikherema1
Star Contributor
Star Contributor
So the "activiti:value" elements are removed? I guess that can be considered as a bug, can you create a JIRA-issue for this?

k0k0pelli
Champ in-the-making
Champ in-the-making
Yes, the activiti:value elements are removed. I will create a JIRA issue.

frederikherema1
Star Contributor
Star Contributor
Thanks!

wojtek
Champ in-the-making
Champ in-the-making
Hi!
I have the same problem (it is quiet anoying). Could you inform me in case of solution (I do not have a JIRA account Smiley Sad ) ?
Regards
Wojtek

chearius
Champ in-the-making
Champ in-the-making
<p>
Hi,
</p><p>
the problem is in the class org.activiti.engine.impl.form.FormTypes. In case of enum or date, new instance of a subclass of org.activiti.engine.form.AbstractFormType is created and only for this instance the value of datePattern or activiti:value elements respectively is passed to the newly created instance. All other form types (including custom ones) won't get any of these values!
</p><p>
As a workaround you can create a subclass of org.activiti.engine.impl.form.FormTypes and set the values in your custom form type. Here is an example:
</p>
<p><strong>activiti-standalone-context.xml</strong></p>
<code>
    <bean id="activitiFormTypes" class="ActivitiFormTypes">
        <property name="activitiFormTypes">
            <list>
                <bean class="org.activiti.engine.impl.form.BooleanFormType" />
                <bean class="org.activiti.engine.impl.form.DateFormType">
                    <constructor-arg index="0" value="dd/MM/yyyy" />
                </bean>
                <bean class="org.activiti.engine.impl.form.DoubleFormType" />
                <bean class="org.activiti.engine.impl.form.LongFormType" />
                <bean class="org.activiti.engine.impl.form.StringFormType" />

                <bean class="CustomCheckboxFormPropertyType" />
                <bean class="CustomTextboxFormPropertyType" />
            </list>
        </property>
    </bean>
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource" />
        <property name="transactionManager" ref="transactionManager" />
        <property name="databaseSchemaUpdate" value="true" />
        <property name="jobExecutorActivate" value="true" />
        <property name="enableDatabaseEventLogging" value="true" />
        <property name="formTypes" ref="activitiFormTypes" />
    </bean>
</code>
<p><strong>ActivitiFormTypes.java</strong></p>
<java>
public class ActivitiFormTypes extends FormTypes implements InitializingBean {

    private List<AbstractFormType> activitiFormTypes;

    @Override
    public void addFormType(AbstractFormType formType) {
        super.addFormType(formType);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        for (AbstractFormType type : activitiFormTypes) {
            super.addFormType(type);
        }
    }

    public List<AbstractFormType> getActivitiFormTypes() {
        return activitiFormTypes;
    }

    @Override
    public AbstractFormType parseFormPropertyType(FormProperty formProperty) {
        if (formTypes.containsKey(formProperty.getType()) && formTypes.get(formProperty.getType()) instanceof AbstractActivitiFormType) {
            AbstractActivitiFormType abstractFormType = (AbstractActivitiFormType) formTypes.get(formProperty.getType());
            AbstractActivitiFormType clone = abstractFormType.cloneFormType();
            clone.setFormProperty(formProperty);

            return clone;

        } else {
            return super.parseFormPropertyType(formProperty);
        }
    }

    public void setActivitiFormTypes(List<AbstractFormType> activitiFormTypes) {
        this.activitiFormTypes = activitiFormTypes;
    }
}
</java>
<p><strong>AbstractActivitiFormType.java</strong></p>
<java>
public abstract class AbstractActivitiFormType extends AbstractFormType {

    protected FormProperty formProperty;

    protected Map<String, FormValue> formValues;

    public abstract AbstractActivitiFormType cloneFormType();

    public FormProperty getFormProperty() {
        return formProperty;
    }

    public FormValue getValue(String id) {
        return formValues.get(id);
    }

    public Collection<FormValue> getValues() {
        return formValues.values();
    }

    public void setFormProperty(FormProperty formProperty) {
        this.formProperty = formProperty;
        setValues(formProperty.getFormValues());
    }

    protected void setValues(Collection<FormValue> values){
        formValues = new LinkedHashMap<>();

        for (FormValue value : values) {
            formValues.put(value.getId(), value);
        }
    }
}
</java>
<p>
Your custom form types (like CustomTextboxFormPropertyType or CustomCheckboxFormPropertyType) will be subclasses of the new abstract class AbstractActivitiFormType. The cloneFormType method should just create a new instance of the custom form type.
</p>
<p>
Please note, that you have to register standard Activiti Form Types yourself if you want to user them. They wont get registered by the org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl bean (or its subclasses).
</p>
<p>
This solution is not as clean as it could be but it works. I'd suggest that a new element (like activiti:fieldProperty) should be defined for form properties in order to make custom form property types configurable from within the process definition. If I find some time and ifthere is an interest in this feature, I'll create a patch.
</p>
<p>
Best Regards,<br>
chearius
</p>