cancel
Showing results for 
Search instead for 
Did you mean: 

HistoricFormProperty don't store the transformed value by the FormType

mikedias
Champ in-the-making
Champ in-the-making
Hi,

Sometimes we need to store big variables in a process instance. Knowing that
ACT_RU_VARIABLE.TEXT_
is a VARCHAR(4000), we create a BinaryFormType to store the big string as a byte array. But, when history level is AUDIT, the engine tries to insert the unprocessed big value at
ACT_HI_DETAIL.TEXT_
, causing a <b>Value too long for column "TEXT_ VARCHAR(4000)"</b>.

Here is a test case that demonstrate the issue:

BPMN 2.0 file:

<?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/processdef">
  <process id="binaryProcess" name="Binary Process" isExecutable="true">
    <startEvent id="sid-F9F0F672-8C03-4E1A-B5C0-C169B016E612">
      <extensionElements>
         <activiti:formProperty id="binaryProperty" name="binaryProperty" type="binary" />
      </extensionElements>
    </startEvent>
    <sequenceFlow id="sid-71C72183-6D1B-420B-96AB-476F10D7E905" sourceRef="sid-F9F0F672-8C03-4E1A-B5C0-C169B016E612" targetRef="sid-7CD47B08-8638-4A81-BC0C-89C2AC065684" />
    <userTask id="sid-7CD47B08-8638-4A81-BC0C-89C2AC065684" name="Binary Task">
      <extensionElements>
        <activiti:formProperty id="binaryProperty" name="binaryProperty" type="binary" />
      </extensionElements>
    </userTask>
    <sequenceFlow id="sid-56169958-5967-437D-8D1B-CFE42CDBDC5C" sourceRef="sid-7CD47B08-8638-4A81-BC0C-89C2AC065684" targetRef="sid-B3FF1567-3EC4-4053-BEF2-AC11883F0497" />
    <endEvent id="sid-B3FF1567-3EC4-4053-BEF2-AC11883F0497" />
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_binaryProcess">
    <bpmndi:BPMNPlane bpmnElement="binaryProcess" id="BPMNPlane_binaryProcess">
      <bpmndi:BPMNShape bpmnElement="sid-F9F0F672-8C03-4E1A-B5C0-C169B016E612" id="BPMNShape_sid-F9F0F672-8C03-4E1A-B5C0-C169B016E612">
        <omgdc:Bounds height="30.0" width="30.0" x="112.0" y="142.0" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-7CD47B08-8638-4A81-BC0C-89C2AC065684" id="BPMNShape_sid-7CD47B08-8638-4A81-BC0C-89C2AC065684">
        <omgdc:Bounds height="80.0" width="100.0" x="187.0" y="117.0" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="sid-B3FF1567-3EC4-4053-BEF2-AC11883F0497" id="BPMNShape_sid-B3FF1567-3EC4-4053-BEF2-AC11883F0497">
        <omgdc:Bounds height="28.0" width="28.0" x="332.0" y="143.0" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="sid-56169958-5967-437D-8D1B-CFE42CDBDC5C" id="BPMNEdge_sid-56169958-5967-437D-8D1B-CFE42CDBDC5C">
        <omgdi:waypoint x="287.0" y="157.0" />
        <omgdi:waypoint x="332.0" y="157.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="sid-71C72183-6D1B-420B-96AB-476F10D7E905" id="BPMNEdge_sid-71C72183-6D1B-420B-96AB-476F10D7E905">
        <omgdi:waypoint x="142.0" y="157.0" />
        <omgdi:waypoint x="187.0" y="157.0" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Test case:
[java]
package org.activiti.engine.test.history;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.form.AbstractFormType;
import org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Task;
import org.junit.Test;

public class HistoricFormPropertyTest {
 
  public static final String BPMN_FILE_PATH = "org/activiti/engine/test/history/HistoricFormPropertyTest.binaryProperty.bpmn20.xml";
 
  public class BinaryFormType extends AbstractFormType {

    public String getName() {
      return "binary";
    }

    public Object convertFormValueToModelValue(String propertyValue) {
      return propertyValue.getBytes();
    }

    public String convertModelValueToFormValue(Object modelValue) {
      return new String((byte[])modelValue);
    }
   
  }
 
  public ProcessEngine buildProcessEngine(String historyLevel) {
    List<AbstractFormType> customFormTypes = new ArrayList<AbstractFormType>();
    customFormTypes.add(new BinaryFormType());
   
    StandaloneInMemProcessEngineConfiguration pec = new StandaloneInMemProcessEngineConfiguration();
    pec.setCustomFormTypes(customFormTypes);
    pec.setHistory(historyLevel);
    return pec.buildProcessEngine();
  }
 
  @Test
  public void testBigStringFormData() {
    //ProcessEngine pe = buildProcessEngine(HistoryLevel.NONE.getKey()); // works
    ProcessEngine pe = buildProcessEngine(HistoryLevel.AUDIT.getKey()); // fail
   
    Deployment d = pe.getRepositoryService().createDeployment().addClasspathResource(BPMN_FILE_PATH).deploy();
    ProcessDefinition pd = pe.getRepositoryService().createProcessDefinitionQuery().deploymentId(d.getId()).singleResult();
   
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++) {
      sb.append("big String… ");
    }
   
    Map<String, String> properties = new HashMap<String, String>();
    properties.put("binaryProperty", sb.toString());
   
    pe.getFormService().submitStartFormData(pd.getId(), properties);
   
    Task t = pe.getTaskService().createTaskQuery().singleResult();
   
    pe.getFormService().submitTaskFormData(t.getId(), properties);
   
  }
 
}
[/java]

My suggestion to solve this is:
  • Change the
    HistoricFormProperty
    to receive a Object instead of String;
  •  
  • Change the
    FormPropertyHandler.submitFormProperty
    to return the transformed value;
  •  
  • Change the
    SubmitTaskFormCmd
    and
    SubmitStartFormCmd
    to report form properties after form handler transformation.
What do you think? Can I do this fix or there are a better solution?
2 REPLIES 2

pmsevestre
Champ in-the-making
Champ in-the-making
If you use a  recent version of MSSQL or MSDE, you can redefine those columns to a VARCHAR(MAX) type. For small sizes it will behave just like an ordinary varchar(), but large values will be handled as TEXT columns.

More information in the following link:

http://social.msdn.microsoft.com/Forums/sqlserver/en-US/4d9c6504-496e-45ba-a7a3-ed5bed731fcc/varchar...

I've used this approach with activiti 5.12.1 and could not find any side effects. Even search by variable value continues to work (SQL SERVER 2008 R2)

mikedias
Champ in-the-making
Champ in-the-making
Hi pmsevestre, thanks for the answer!

We are using the same approach to save attachments as process instance variable, so we really want to store the value as a byte array. Moreover, we want to use the HistoricFormProperty to keep a record of what was submitted in completed tasks.

But is good to know about this feature. Can be useful in another use case.