Skip to main content
Version: 10.3.2

Predefined task types

There are some useful prepackaged task types not associated with any APIs. You can use them in the standard cross-process flow.

Tasks for Intake Business Process

InputProviderTask

You can use the task if, for some reason, you don't want to use Monitor to poll for input data continuously. It does the same as InputMonitor, but one time only—just as TransactionProvider from ODF 1.

Example
@BotTask
public class MyInputProviderTask implements InputProviderTask<Email> {

private final EmailRepository emailRepository;

public MyInputProviderTask(EmailRepository emailRepository) {
this.emailRepository = emailRepository;
}

@Override
public Collection<Email> queryInputEntities() {
final ArrayList<Email> emails = new ArrayList<>();
emails.add(new Email());
emails.add(new Email());

return emails;
}

@Override
public void saveInputEntity(Email input) {
emailRepository.create(input);
}
}

InputProcessorTask

If you need to write an operation that works on input entities, the task provides a convenient foundation for it.

Example
@BotTask
public class ChangeEmailsTask implements InputEntityProcessorTask<Email> {

private final EmailRepository emailRepository;

@Inject
public ChangeEmailsTask(EmailRepository emailRepository) {
this.emailRepository = emailRepository;
}

@Override
public Collection<Email> findInputEntities(UUID transactionId) {
return emailRepository.findAll(transactionId);
}

@Override
public void processInputEntities(Collection<Email> emails) {
emails.forEach(email -> email.setSubject("Changed"));
}

@Override
public void saveInputEntities(Collection<Email> emails) {
emails.forEach(emailRepository::update);
}
}

Monitors and Finalizers

You can organize the standard cross-process execution flow with the help of Monitor and Finalizer Tasks. See the procedure in Multi-process AI Agent design.

Tasks for Processing Business Process

InputConverterTask

Use the task to convert input entities to business entities.

Example
@BotTask
public class EmailToInvoiceConverterTask implements InputConverterTask<Email, Invoice> {

private final EmailRepository emailRepository;
private final InvoiceRepository invoiceRepository;

@Inject
public EmailToInvoiceConverterTask(EmailRepository emailRepository, InvoiceRepository invoiceRepository) {
this.emailRepository = emailRepository;
this.invoiceRepository = invoiceRepository;
}

@Override
public Collection<Email> findInputEntities(UUID transactionId) {
return emailRepository.findAll(transactionId);
}

@Override
public Collection<Invoice> processInputEntities(Collection<Email> emails) {
return emails.stream().map(EmailToInvoiceConverterTask::createInvoice).collect(Collectors.toList());
}

@Override
public void saveBusinessEntities(Collection<Invoice> invoices) {
invoiceRepository.createAll(invoices);
}

private static Invoice createInvoice(Email email) {
final int sum = email.getAttachments().stream().mapToInt(Attachment::getSize).sum();

Invoice invoice = new Invoice();
invoice.setAmount(sum);
return invoice;
}
}

BusinessEntityProcessorTask

Same as InputProcessorTask, this is an operation that works on business entities.

Example
@BotTask
public class InvoiceProcessorTask implements BusinessEntityProcessorTask<Invoice> {

private final InvoiceRepository invoiceRepository;

@Inject
public InvoiceProcessorTask(InvoiceRepository invoiceRepository) {
this.invoiceRepository = invoiceRepository;
}

@Override
public Collection<Invoice> findBusinessEntities(UUID transactionId) {
return invoiceRepository.findAll(transactionId);
}

@Override
public void processBusinessEntities(Collection<Invoice> invoices) {
invoices.forEach(invoice -> invoice.setType("CustomType"));
}

@Override
public void saveBusinessEntities(Collection<Invoice> invoices) {
invoices.forEach(invoiceRepository::update);
}
}

Tasks for Error Handling Business Process

ErrorHandlingTask

The task provides an error-handling operation.

Example
@BotTask
public class ExceptionProcessorTask implements ErrorHandlingTask {

private final TransactionOperation transactionOperation;

@Inject
public ExceptionProcessorTask(TransactionOperation transactionOperation) {
this.transactionOperation = transactionOperation;
}

@Override
public boolean isNeedManualErrorHandling(ErrorEntity errorEntity) {
// here we must decide if this error can be handled automatically by analyzing errorEntity
}

@Override
public void automationHandling(Transaction transaction) throws OdfException {
// here we must fix what's wrong with data
final Transaction newTransaction = transactionOperation.newTransaction();
transactionOperation.doAndUpdateTransaction(newTransaction, t -> {
// and put this data into new transaction to be processed again
});
}

@Override
public TransactionStatus updateTransactionStatus() {
// current transaction must be aborted
return TransactionStatus.ABORTED;
}
}

Other useful tasks

GenericTask

The task does absolutely nothing except what's written inside. Runner executes no under-the-hood code—no error handling, no filtering Transactions by status.

Example
@BotTask
public class GenericTaskExample implements GenericTask {

private final CurrentTransaction currentTransaction;
private final TaskOutput taskOutput;
private final Logger logger;

@Inject
public GenericTaskExample(CurrentTransaction currentTransaction, TaskOutput taskOutput, Logger logger) {
this.currentTransaction = currentTransaction;
this.taskOutput = taskOutput;
this.logger = logger;
}

@Override
public void run() {
if (currentTransaction.isPresent()) {
logger.info(String.format("Processing transaction %s%n", currentTransaction.get().getUuid()));
} else {
logger.info("No transaction");
}

taskOutput.setColumn("additional_field", "additional_field value");
taskOutput.setColumn("transaction_processed", String.valueOf(currentTransaction.isPresent()));
}
}

TransactionProcessorTask

The task operates on a Transaction instead of working with user-defined entities.

Example
@BotTask
public class FinalizeIntakeTask implements TransactionProcessorTask {

// this example is a real finalizer task form ODF2 core

@Override
public boolean shouldProcessTransaction(CurrentTransaction currentTransaction) {
// it will call doWithTransaction() if this method returns true
// and it means if Transaction status is INTAKE_IN_PROGRESS
return TransactionStatus.INTAKE_IN_PROGRESS.appliesTo(currentTransaction);
}

@Override
public void doWithTransaction(Transaction transaction) {
// when called, will change Transaction status to INTAKE_COMPLETED
TransactionStatus.INTAKE_COMPLETED.setTo(transaction);
}

}