# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ism-docs.xnarum.com/implementing-a-task.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
