Blog‎ > ‎

Collection form type in Activiti

posted Sep 14, 2012, 12:40 PM by Luca Stancapiano   [ updated Sep 14, 2012, 12:42 PM ]
Here I post an example of collection form type in Activiti. I've seen actually only are supported the basic types in the form:

  • boolean
  • long
  • string
  • enum
  • date
  • user

A collection form type could be useful to work with lists and show a list of typed object in the form. Here the basic implementation of the collection form type:

package org.activiti.engine.impl.form;

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

import org.activiti.engine.impl.form.AbstractFormType;

public class CollectionFormType<T> extends AbstractFormType {

    private Map<String, T> values = new HashMap<String, T>();

    @Override
    public String getName() {
        return "collection";
    }

    @Override
    public Collection<T> convertFormValueToModelValue(String propertyValue) { // key1|key3
        String[] ids = propertyValue.split("\\|");
        Collection<T> ret = new ArrayList<T>();
        for (String id : ids) {
            T element = values.get(id);
            if (element != null) {
                ret.add(element);
            }
        }
        return ret;
    }

    @Override
    @SuppressWarnings("unchecked")
    public String convertModelValueToFormValue(Object modelValue) {
        Collection<T> modelValues = (Collection<T>) modelValue;
        values.clear();
        for (T value : modelValues)
            values.put(value.toString(), value);
        return modelValue.toString();
    }

    @Override
    public Object getInformation(String key) {
        if ("values".equals(key)) {
            return values;
        } else {
            return null;// TODO
        }
    }
}


With this implementation simply set in your activiti form property the type 'collection'. To view the rendered form property in the activiti explorer, a renderer must be implemented. Here a working sample:

package org.activiti.explorer.ui.form;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.activiti.engine.form.FormProperty;
import org.activiti.explorer.Messages;
import org.activiti.explorer.ui.form.AbstractFormPropertyRenderer;

import org.activiti.engine.impl.form.CollectionFormType;

import com.vaadin.event.ItemClickEvent;
import com.vaadin.ui.AbstractSelect.MultiSelectMode;
import com.vaadin.ui.Field;
import com.vaadin.ui.Table;

public class CollectionFormPropertyRenderer<T> extends
        AbstractFormPropertyRenderer {

    private Table table;
    private Map<String, T> values;

    public CollectionFormPropertyRenderer() {
        super(CollectionFormType.class);
    }

    @Override
    @SuppressWarnings("unchecked")
    public Field getPropertyField(FormProperty formProperty) {

        table = new Table();
        table.setCaption(getPropertyLabel(formProperty));
        table.setRequired(formProperty.isRequired());
        table.setRequiredError(getMessage(Messages.FORM_FIELD_REQUIRED,
                getPropertyLabel(formProperty)));
        table.setEnabled(formProperty.isReadable());
        table.setSelectable(formProperty.isWritable());
        table.setMultiSelect(true);
        table.setMultiSelectMode(MultiSelectMode.SIMPLE);

        table.addListener(new ItemClickEvent.ItemClickListener() {

            private static final long serialVersionUID = -6477528416002075564L;

            @Override
            public void itemClick(ItemClickEvent event) {
                //table.setCaption("CLICCCKATO!!!");
            }

        });

        values = (Map<String, T>) formProperty.getType().getInformation(
                "values");
        Class<T> genericClass = (Class<T>) values.values().iterator().next()
                .getClass();
        Method[] methods = genericClass.getMethods();
        java.lang.reflect.Field[] fields = genericClass.getDeclaredFields();
        for (java.lang.reflect.Field field : fields)
            if (hasMethod(methods, field))
                table.addContainerProperty(field.getName(), String.class, null);

        if (values != null) {
            for (Map.Entry<String, T> enumEntry : values.entrySet()) {

                String id = enumEntry.getKey();
                T value = enumEntry.getValue();
                table.addItem(getValues(fields, methods, value), id);

                if (enumEntry.getValue() != null) {
                    // table.setItemCaption(enumEntry.getKey(),
                    // enumEntry.getValue());
                }
            }
        }
        return table;
    }

    @Override
    public String getFieldValue(FormProperty formProperty, Field field) {

        assert field == table;

        @SuppressWarnings("unchecked")
        Collection<String> ids = (Collection<String>) field.getValue();
        String ret = "";

        for (String id : ids) {
            ret += id + "|";
        }
        return ret;
    }

    private boolean hasMethod(Method[] methods, java.lang.reflect.Field field) {
        for (Method method : methods) {
            String methodName = method.getName();
            if (methodName.startsWith("get")
                    && methodName.substring(3)
                            .equalsIgnoreCase(field.getName()))
                return true;
        }
        return false;
    }

    private Object[] getValues(java.lang.reflect.Field[] fields,
            Method[] methods, T type) {
        List<Object> result = new ArrayList<Object>();
        try {
            for (java.lang.reflect.Field field : fields)
                for (Method method : methods) {
                    String methodName = method.getName();
                    if (methodName.startsWith("get")
                            && methodName.substring(3).equalsIgnoreCase(
                                    field.getName()))
                        result.add(method.invoke(type));
                }
        } catch (UnsupportedOperationException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return result.toArray();
    }
}


This renderer uses the reflection to render all beans inside the list. Automatically it will show all getter methods of the bean. The patch can be found in the activiti codehaus page:

http://jira.codehaus.org/browse/ACT-1367
Comments