1. Activiti External Form Rendering
Reference: Activiti in Action
Reference: Activiti 5.10 User Guide. http://activiti.org/userguide/index.html#externalFormRendering
Reference: http://rongjih.blog.163.com/blog/static/33574461201263124922670/
We should be aware of the difference of StartForm and TaskForm.
Fact 1: FormService Interface should be implemented by myself
StartForm Methods | TaskForm Methods | Note |
getStartFormData | getTaskFormData | no template involved |
getRenderedStartForm | getRenderedTaskForm | template loaded, and script like juel in template evaluated |
submitStartFormData | submitTaskFormData |
Any reference implementation of FormService interface? YES! org.activiti.engine.impl.FormServiceImpl
public class FormServiceImpl extends ServiceImpl implements FormService {
//HERE COMMAND PATTERN APPLIED
public Object getRenderedStartForm(String processDefinitionId) {
return commandExecutor.execute(new GetRenderedStartFormCmd(processDefinitionId, null));
}
public Object getRenderedStartForm(String processDefinitionId, String engineName) {
return commandExecutor.execute(new GetRenderedStartFormCmd(processDefinitionId, engineName));
}
public Object getRenderedTaskForm(String taskId) {
return commandExecutor.execute(new GetRenderedTaskFormCmd(taskId, null));
}
public Object getRenderedTaskForm(String taskId, String engineName) {
return commandExecutor.execute(new GetRenderedTaskFormCmd(taskId, engineName));
}
public StartFormData getStartFormData(String processDefinitionId) {
return commandExecutor.execute(new GetStartFormCmd(processDefinitionId));
}
public TaskFormData getTaskFormData(String taskId) {
return commandExecutor.execute(new GetTaskFormCmd(taskId));
}
public ProcessInstance submitStartFormData(String processDefinitionId, Map<String, String> properties) {
return commandExecutor.execute(new SubmitStartFormCmd(processDefinitionId, null, properties));
}
public ProcessInstance submitStartFormData(String processDefinitionId, String businessKey, Map<String, String> properties) {
return commandExecutor.execute(new SubmitStartFormCmd(processDefinitionId, businessKey, properties));
}
public void submitTaskFormData(String taskId, Map<String, String> properties) {
commandExecutor.execute(new SubmitTaskFormCmd(taskId, properties));
}
public String getStartFormKey(String processDefinitionId) {
return commandExecutor.execute(new GetFormKeyCmd(processDefinitionId));
}
public String getTaskFormKey(String processDefinitionId, String taskDefinitionKey) {
return commandExecutor.execute(new GetFormKeyCmd(processDefinitionId, taskDefinitionKey));
}
}
public class GetRenderedStartFormCmd implements Command<Object>, Serializable {
private static final long serialVersionUID = 1L;
protected String processDefinitionId;
protected String formEngineName;
public GetRenderedStartFormCmd(String processDefinitionId, String formEngineName) {
this.processDefinitionId = processDefinitionId;
this.formEngineName = formEngineName;
}
public Object execute(CommandContext commandContext) {
ProcessDefinitionEntity processDefinition = Context
.getProcessEngineConfiguration()
.getDeploymentCache()
.findDeployedProcessDefinitionById(processDefinitionId);
if (processDefinition == null) {
throw new ActivitiException("Process Definition '" + processDefinitionId +"' not found");
}
StartFormHandler startFormHandler = processDefinition.getStartFormHandler();
if (startFormHandler == null) {
return null;
}
FormEngine formEngine = Context
.getProcessEngineConfiguration()
.getFormEngines()
.get(formEngineName);
if (formEngine==null) {
throw new ActivitiException("No formEngine '" + formEngineName +"' defined process engine configuration");
}
StartFormData startForm = startFormHandler.createStartFormData(processDefinition);
return formEngine.renderStartForm(startForm);
}
}
Noteworthy: business key
/**
* Start a new process instance with the user data that was entered as properties in a start form.
*
* A business key can be provided to associate the process instance with a
* certain identifier that has a clear business meaning. For example in an
* order process, the business key could be an order id. This business key can
* then be used to easily look up that process instance , see
* {@link ProcessInstanceQuery#processInstanceBusinessKey(String)}. Providing such a business
* key is definitely a best practice.
*
* Note that a business key MUST be unique for the given process definition.
* Process instance from different process definition are allowed to have the
* same business key.
*
* @param processDefinitionId the id of the process definition, cannot be null.
* @param businessKey a key that uniquely identifies the process instance in the context or the
* given process definition.
* @param properties the properties to pass, can be null.
*/
ProcessInstance submitStartFormData(String processDefinitionId, String businessKey, Map<String, String> properties);
public abstract class AbstractFormType implements FormType {
//What does this mean?
public abstract Object convertFormValueToModelValue(String propertyValue);
public abstract String convertModelValueToFormValue(Object modelValue);
public Object getInformation(String key) {
return null;
}
}
public abstract class FormDataImpl implements FormData, Serializable {
private static final long serialVersionUID = 1L;
//UNDERSTANDING
protected String formKey;
protected String deploymentId;
protected List<FormProperty> formProperties = new ArrayList<FormProperty>();
public interface FormHandler {
ThreadLocal<FormHandler> current = new ThreadLocal<FormHandler>();
void parseConfiguration(Element activityElement, DeploymentEntity deployment, ProcessDefinitionEntity processDefinition, BpmnParse bpmnParse);
void submitFormProperties(Map<String, String> properties, ExecutionEntity execution);
}