1. Overview
Sometimes a Joget process must be ended from a custom action, for example when a request is withdrawn or cancelled. This article shows a BeanShell pattern for updating the related form record and aborting the active workflow process.
2. How It Works
- Read the selected row key from a datalist action.
- Load the matching form record.
- Update the approval status and modifier fields.
- Find the active workflow process ID from wf_process_link.
- Call workflowManager.processAbort(process_id) to abort the process.
3. Where to Use in Joget
- Datalist Builder: custom row action for withdraw/cancel buttons.
- Workflow Builder: administrative actions that terminate active requests.
- Userview: controlled self-service cancellation flows.
4. Full Code
import java.util.HashMap;
import org.joget.apps.form.dao.FormDataDao;
import org.joget.apps.form.model.FormRow;
import org.joget.apps.form.model.FormRowSet;
import org.joget.commons.util.LogUtil;
import org.joget.apps.app.service.AppUtil;
import org.joget.commons.util.UuidGenerator;
import org.joget.apps.datalist.model.DataListActionResult;
import org.joget.workflow.model.WorkflowProcessResult;
import org.joget.workflow.model.service.WorkflowManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.joget.apps.form.model.Element;
import java.io.*;
import java.io.IOException;
import java.util.Map;
String id="";
String active="";
if (rowKeys.length>0) {
id=rowKeys[0];
}
if(!id.isEmpty()){
//delete record
FormDataDao formDataDao = (FormDataDao) AppUtil.getApplicationContext().getBean("formDataDao");
FormRowSet form_rows = new FormRowSet();
form_rows.setMultiRow(true);
FormRow form_row=formDataDao.load("request_form","request_form",id);
form_row.setProperty("request_status","Withdrawn");
form_row.setProperty("modifiedBy","#currentUser.username#");
form_row.setProperty("modifiedByName","#currentUser.fullName#");
form_row.setDateModified(new Date());
form_rows.add(form_row);
formDataDao.saveOrUpdate("request_form","request_form",form_rows);
//formDataDao.delete("request_form","request_form",form_rows);
//terminate process
WorkflowManager workflowManager = (WorkflowManager) AppUtil.getApplicationContext().getBean("workflowManager");
try{
String process_id="";
DataSource ds = (DataSource)AppUtil.getApplicationContext().getBean("setupDataSource");
con = ds.getConnection();
if(!con.isClosed()) {
PreparedStatement stmt = con.prepareStatement("select * from wf_process_link where originProcessId=?");
stmt.setObject(1, id);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
process_id=rs.getString("processId");
}
con.close();
}
if(!process_id.isEmpty()){
LogUtil.info("Aborting Process for ProcessID: ", process_id);
workflowManager.processAbort(process_id);
}
}
catch (Exception e) {
con.close();
LogUtil.info("Catch Block","Exception Found "+e.toString());
}
}
5. Example Use Cases
- Withdraw asset registration requests.
- Cancel pending approval workflows.
- End duplicate or invalid requests.
- Build admin-only terminate actions from a datalist.
6. Customization Tips
- Replace form ID, table ID, and status value with your app's values.
- Restrict this action to authorized users only.
- Add a confirmation dialog before running the action.
- Log the reason for termination in a history table if auditability is required.
7. Key Benefits
- Updates business status and workflow status together.
- Gives users or admins a controlled cancellation action.
- Uses Joget's built-in WorkflowManager.
- Keeps termination logic close to the datalist action.
8. Security Note
Only allow trusted roles to abort processes. Terminating a workflow can bypass normal approval paths, so protect the datalist action with permission checks and audit logs.
9. Final Thoughts
This pattern is useful for controlled cancellation flows. Keep it permission-protected, record the reason for termination, and test with active and already-completed process instances.
Top comments (0)