> For the complete documentation index, see [llms.txt](https://ism-docs.xnarum.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ism-docs.xnarum.com/implementing-a-task.md).

# Implementing a Task

A task can be added on the fly during runtime. You implement a task class and put that class under Swordfish\_installed\_directory/custom directory. Then it will be automatically loaded when you open flow designer.

To implement a task, a task class must implement TaskHandler and define an TaskDefinition java annotation.

## TaskHandler interface

&#x20;

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>package com.ism.was.flow.entity;

import java.util.Map;
import java.util.Properties;

public interface TaskHandler {
public boolean initializeTask(Properties props);
public boolean execute(String flowId, String taskId, String transactionId, FlowTask \[] tasks, Map requestData);
public TaskResult getResult();
public String getName();
public boolean finalizeTask();
}

</code></pre></td></tr></tbody></table>

&#x20;

<table data-header-hidden><thead><tr><th width="176"></th><th></th></tr></thead><tbody><tr><td>Signature</td><td><pre><code>public boolean initializeTask(Properties props);

</code></pre></td></tr><tr><td>Description</td><td>Used when extra additional initialization is required for a task</td></tr><tr><td>Parameters</td><td>props - input attributes defined in flow.</td></tr><tr><td>Return</td><td><p>boolean value.</p><ul><li>True - initialization succeeded</li><li>False - initialization failed</li></ul></td></tr></tbody></table>

&#x20;

<table data-header-hidden><thead><tr><th width="177"></th><th></th></tr></thead><tbody><tr><td>Signature</td><td><pre><code>public boolean execute(String flowId, String taskId, String transactionId, FlowTask [] tasks, Map requestData);

</code></pre></td></tr><tr><td>Description</td><td>Main method of a task</td></tr><tr><td>Parameters</td><td><ul><li>flowId - flow id</li><li>taskId - task id</li><li>transactionId - transaction id</li><li>tasks - tasks executed previously</li><li>requestData - collection of output data from previous tasks</li></ul></td></tr><tr><td>Return</td><td><p>boolean value.</p><ul><li>True - succeeded</li><li>False - failed</li></ul></td></tr></tbody></table>

&#x20;

<table data-header-hidden><thead><tr><th width="176"></th><th></th></tr></thead><tbody><tr><td>Signature</td><td><pre><code>public TaskResult getResult();

</code></pre></td></tr><tr><td>Description</td><td>Returns the result of task execution. This result contains the input and output data of the task execution</td></tr><tr><td>Parameters</td><td> </td></tr><tr><td>Return</td><td>TaskResult may contain error information, if it failed.</td></tr></tbody></table>

&#x20;

<table data-header-hidden><thead><tr><th width="174"></th><th></th></tr></thead><tbody><tr><td>Signature</td><td><pre><code>public boolean finalizeTask();

</code></pre></td></tr><tr><td>Description</td><td>Used when an additional finalization is required of a task</td></tr><tr><td>Parameters</td><td> </td></tr><tr><td>Return</td><td><p>boolean value.</p><ul><li>True - succeeded</li><li>False - failed</li></ul></td></tr></tbody></table>

&#x20;

## TaskDefinition annotation

&#x20;

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>package com.ism.was.flow.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface TaskDefinition {
public String name();
public String description();
public int arguments();
public String html() default "";
public String type() default "java";
public String icon() default "";
public FieldDefinition \[] fields() default {};
public FieldDefinition \[] outs() default {};
public boolean test() default false;
public String testLink() default "";
public boolean custom() default false;
public String customPage() default "";
}

</code></pre></td></tr></tbody></table>

Attributes

<table><thead><tr><th width="215">Name</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>Task name displayed in flow designer</td></tr><tr><td>description</td><td>Task description</td></tr><tr><td>arguments</td><td>Number of input attribute. For display purpose only.</td></tr><tr><td>html</td><td>custom html page for input/output attributes</td></tr><tr><td>type</td><td>task type. For display purpose only</td></tr><tr><td>icon</td><td>path of task icon. ex) images/task.png</td></tr><tr><td>fields</td><td>input attribute list</td></tr><tr><td>outs</td><td>output attribute list</td></tr><tr><td>test</td><td>whether test page is provided</td></tr><tr><td>testLink</td><td>custom html page for testing</td></tr><tr><td>custom</td><td>True if custom html page is provided for input attibutes</td></tr><tr><td>customPage</td><td><p>The class path of the html page</p><p>ex) com/ism/was/flow/handler/html/ftptransfer-task.html</p></td></tr></tbody></table>

&#x20;

## FieldDefinition

&#x20;

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>package com.ism.was.flow.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface FieldDefinition {

```
public String name();
public String label() default "";
public String help() default "";
public int width() default 0;
public String type() default "text";
public int height() default 0;
public int rows() default 3;
public int cols() default 80;
public String selectFrom() default "";
public String [] options() default {};
public String [] labels() default {};
```

}

</code></pre></td></tr></tbody></table>

&#x20;

Attributes

<table><thead><tr><th width="205">Name</th><th>Description</th></tr></thead><tbody><tr><td>name</td><td>Attribute name displayed in property editor</td></tr><tr><td>label</td><td>Label of attribute</td></tr><tr><td>help</td><td>Help message</td></tr><tr><td>width</td><td>Not used. For display purpose only. HTML text box</td></tr><tr><td>height</td><td>Not used. For display purpose only. HTML text box</td></tr><tr><td>rows</td><td>For display purpose only. HTML textarea</td></tr><tr><td>cols</td><td>For display purpose only. HTML textarea</td></tr><tr><td>selectFrom</td><td>Used only when option list of HTML select is from a class invocation</td></tr><tr><td>options</td><td>Available values of the attribute. HTML select</td></tr><tr><td>labels</td><td>For display purpose only. HTML select</td></tr></tbody></table>

&#x20;

## Example implementation - Wait Task

&#x20;

<table data-header-hidden><thead><tr><th></th></tr></thead><tbody><tr><td><pre><code>package com.ism.was.flow.handler;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

import com.ism.common.Common;
import com.ism.common.logger.DefaultLogger;
import com.ism.was.flow\.annotation.FieldDefinition;
import com.ism.was.flow\.annotation.TaskDefinition;
import com.ism.was.flow\.config.FlowConstants;
import com.ism.was.flow\.entity.FlowTask;
import com.ism.was.flow\.entity.SubFlowExecution;
import com.ism.was.flow\.entity.TaskHandler;
import com.ism.was.flow\.entity.TaskResult;
import com.ism.was.flow\.log.SubFlowExecutionLog;
import com.ism.was.flow\.log.SubflowLogManager;
import com.ism.was.flow\.util.FlowUtil;

@TaskDefinition(
name="Wait", description="Wait sub flow completion", arguments=-1,
custom=false,type="function",
icon="images/wait.png",
fields = {
@FieldDefinition(name="SubFlowId", width=100, height=30, rows=10, cols=80, type="select", selectFrom="com.ism.projects.jpa.web.flow\.FlowProcessor" ),
@FieldDefinition(name="ExecutionCount", width=100, height=30, rows=10, cols=80, type="text" ),
@FieldDefinition(name="Timeout", width=100, height=30, rows=10, cols=80, type="text" ),
},
outs = {

```
	}
)
```

public class WaitSubTask implements TaskHandler {

```
protected Properties props;
protected TaskResult result;

protected Properties outprops;

private String resultValueName = null;

public boolean initializeTask(Properties props) {
	// TODO Auto-generated method stub
	this.props = props;
	return true;
}

public boolean execute(String flowId, String taskId, String gidSeq, FlowTask[] tasks, Map imap) {
	// TODO Auto-generated method stub
	
	result = new TaskResult(gidSeq);
	result.setStartTime();
	
	Vector imaps = new Vector();
	HashMap omap = new HashMap();
	omap.putAll(imap);
	
	result.setSuccess(true);
	
String gid = (String)imap.get("GID");
	
String subFlowId = (String)props.get("SubFlowId");
String executionCount = (String)props.get("ExecutionCount");
String timeout = (String)props.get("Timeout");
	
resultValueName = (String)props.get("out-ResultValue");
if ( resultValueName == null || resultValueName.trim().length() &#x3C; 1 ) {
	resultValueName = "ResultValue";
}
	
Object rtn = null;

int completedCount = 0;
	try {
		executionCount = (String)FlowUtil.getValue(imap, props, executionCount);
		if ( executionCount == null ) {
			throw new Exception("ExecutionCount cannot be null or empty");
		}
		int executionCountInt = -1;
		try {
			executionCountInt = Integer.parseInt(executionCount.trim());	
		}catch( Exception e ) {
			throw new Exception("ExecutionCount value is invalid[" + executionCount + "]");
		}
		long start = System.currentTimeMillis();
		long timeoutLong = Long.parseLong(timeout) * 1000; //30 sec
		boolean succeeded = false;
		int interval = 0;
		while ( true ) {
		String fkey = String.format("%s-%s-%s", flowId, subFlowId, gid);
    			int count = SubflowLogManager.countComplete(fkey);
    		if ( ++interval % 10 == 0 ) {
    				DefaultLogger.logN("Expected count = {}, logged count = {}, {}, {}, {} ", executionCountInt, count, flowId, subFlowId, gid);
			}else {
    				DefaultLogger.logV("Expected count = {}, logged count = {}, {}, {}, {} ", executionCountInt, count, flowId, subFlowId, gid);
			}
        		if ( count != executionCountInt ) {
    				Thread.sleep(2000);
    			}else {
        			succeeded = true;
        			SubflowLogManager.removeSubflows(fkey);
    				break;
        		}
    			if ( Common.shutdown ) {
    				break;
        		}
    			long now = System.currentTimeMillis();
        		if ( now > (start + timeoutLong) ) {
    				break;
    			}
		}
	omap.put(resultValueName, rtn);
		result.setSuccess(succeeded);
	}catch( Exception e ) {
		DefaultLogger.logE(e, "Failed to executing function");
    		result.setErrorMessage(e.getMessage());
    		result.setException(e);
		result.setSuccess(false);
	}
result.setData(omap);
	result.setEndTime();
	
	return result.isSuccess();
}

public TaskResult getResult() {
	// TODO Auto-generated method stub
	return result;
}

public String getName() {
	// TODO Auto-generated method stub
	return null;
}

public boolean finalizeTask() {
	// TODO Auto-generated method stub
	return false;
}
```

}

</code></pre></td></tr></tbody></table>

<br>
