Extending jBPM mail

When adding jbpm to a project I didn't want to have to configure mail settings in two places and learn a second templating language just to send reminder mails from a business process. The following is how I integrated the Seam mail system into jbpm to get around those issues. The following is sufficient for my purposes but should probably be extended to be more generic/flexible.

 * Copyright Software Factory - 2009
package nz.co.softwarefactory.risingstars.jbpm;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import nz.co.softwarefactory.risingstars.util.EmailEventListener;

import org.jboss.seam.core.Events;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.taskmgmt.exe.PooledActor;
import org.jbpm.taskmgmt.exe.TaskInstance;

 * Overrides the jBPM mail service to use the seam mail system instead.
 * @author craig
public class Mail extends org.jbpm.mail.Mail {

    private static final String TEMPLATE_PATH = "/WEB-INF/pages/occurrence/";
    private static final String EMAIL_TASK_ASSIGNMENT = "taskAssignmentEmailWrapper.xhtml";
    private static final String EMAIL_TASK_CREATE = "taskCreateEmailWrapper.xhtml";
    private static final String EMAIL_TASK_REMINDER = "taskReminderEmailWrapper.xhtml";

    private static final String TEMPLATE_TASK_ASSIGNMENT = "task-assign";
    private static final String TEMPLATE_TASK_CREATE = "task-create";
    private static final String TEMPLATE_TASK_REMINDER = "task-reminder";

    public String template = null;

    public String actors = null;

    private ExecutionContext executionContext;

     * @see org.jbpm.mail.Mail#execute(org.jbpm.graph.exe.ExecutionContext)
    public void execute(final ExecutionContext executionContext) {
        this.executionContext = executionContext;

    public void send() {
        final TaskInstance task = executionContext.getTaskInstance();
        final Map<String, Object> parameters = new HashMap<String, Object>();


        parameters.put("task", task);
        // TODO this probably isn't as flexible as it could be as does not all
        // use of "to" field and will not evaluate
        // expressions before attempting to resolve addresses. Was using
        // getRecipients but am not able get it to use
        // the actor Ids I wanted it to as actors is private and cannot be set.
        parameters.put("addresses", resolveAddresses(tokenize(actors)));

        if (Mail.TEMPLATE_TASK_ASSIGNMENT.equals(template)) {
                    Mail.TEMPLATE_PATH + Mail.EMAIL_TASK_ASSIGNMENT, parameters);
        else if (Mail.TEMPLATE_TASK_REMINDER.equals(template)) {
                    Mail.TEMPLATE_PATH + Mail.EMAIL_TASK_REMINDER, parameters);
        else if (Mail.TEMPLATE_TASK_CREATE.equals(template)) {
                    Mail.TEMPLATE_PATH + Mail.EMAIL_TASK_CREATE, parameters);

    private void setActors(final TaskInstance task) {
        if (actors == null || actors.isEmpty()) {
            final String actorId = task.getActorId();
            if (actorId != null && !actorId.isEmpty()) {
                actors = actorId;
            else {
                final Set<PooledActor> pooledActors = task.getPooledActors();
                final StringBuilder sb = new StringBuilder();
                for (final PooledActor pooledActor : pooledActors) {
                    if (sb.length() > 0) {
                actors = sb.toString();


<string name='mail.class.name' value='nz.co.softwarefactory.risingstars.jbpm.Mail' />