All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbpm.mail.Mail Maven / Gradle / Ivy

The newest version!
package org.jbpm.mail;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jbpm.JbpmConfiguration.Configs;
import org.jbpm.JbpmException;
import org.jbpm.graph.def.ActionHandler;
import org.jbpm.graph.exe.ExecutionContext;
import org.jbpm.jpdl.el.ELException;
import org.jbpm.jpdl.el.VariableResolver;
import org.jbpm.jpdl.el.impl.JbpmExpressionEvaluator;
import org.jbpm.util.ClassLoaderUtil;
import org.jbpm.util.XmlUtil;
import org.w3c.dom.Element;

public class Mail implements ActionHandler {

  private String template;
  private String to;
  private String actors;
  private String cc;
  private String ccActors;
  private String bcc;
  private String bccActors;
  private String subject;
  private String text;

  private transient ExecutionContext executionContext;

  private static final long serialVersionUID = 2L;

  public Mail() {
  }

  public Mail(String template, String actors, String to, String subject, String text) {
    this.template = template;
    this.actors = actors;
    this.to = to;
    this.subject = subject;
    this.text = text;
  }

  public Mail(String template, String actors, String to, String bccActors, String bcc,
    String subject, String text) {
    this.template = template;
    this.actors = actors;
    this.to = to;
    this.bccActors = bccActors;
    this.bcc = bcc;
    this.subject = subject;
    this.text = text;
  }

  public void execute(ExecutionContext executionContext) {
    this.executionContext = executionContext;
    send();
  }

  public Collection getRecipients() {
    return collectRecipients(actors, to);
  }

  public Collection getCcRecipients() {
    return collectRecipients(ccActors, cc);
  }

  public Collection getBccRecipients() {
    Collection recipients = collectRecipients(bccActors, bcc);
    if (Configs.hasObject("jbpm.mail.bcc.address")) {
      if (!(recipients instanceof ArrayList)) recipients = new ArrayList(recipients);
      recipients.addAll(tokenize(Configs.getString("jbpm.mail.bcc.address")));
    }
    return recipients;
  }

  private Collection collectRecipients(String actors, String addresses) {
    if (actors != null) {
      if (addresses != null) {
        Collection recipients = new ArrayList(evaluateActors(actors));
        recipients.addAll(evaluateAddresses(addresses));
        return recipients;
      }
      return evaluateActors(actors);
    }
    else if (addresses != null) {
      return evaluateAddresses(addresses);
    }
    return null;
  }

  private Collection evaluateActors(String expression) {
    Object value = evaluate(expression, Object.class);
    Collection actorIds;
    if (value instanceof String) {
      actorIds = tokenize((String) value);
    }
    else if (value instanceof Collection) {
      actorIds = (Collection) value;
    }
    else if (value instanceof String[]) {
      actorIds = Arrays.asList((String[]) value);
    }
    else {
      throw new JbpmException(expression + " returned " + value
        + " instead of comma-separated string, string array or collection");
    }
    return resolveAddresses(actorIds);
  }

  protected Collection resolveAddresses(Collection actorIds) {
    AddressResolver addressResolver = (AddressResolver) Configs.getObject("jbpm.mail.address.resolver");

    Collection addresses = new ArrayList();
    for (Iterator iter = actorIds.iterator(); iter.hasNext();) {
      String actorId = (String) iter.next();
      Object result = addressResolver.resolveAddress(actorId);

      if (result instanceof String) {
        addresses.add(result);
      }
      else if (result instanceof Collection) {
        addresses.addAll((Collection) result);
      }
      else if (result instanceof String[]) {
        addresses.addAll(Arrays.asList((String[]) result));
      }
      else if (result == null) {
        // no such actor or actor has no address
      }
      else {
        throw new JbpmException(addressResolver + " returned " + result
          + " instead of single string, string array or collection");
      }
    }
    return addresses;
  }

  private Collection evaluateAddresses(String expression) {
    Object value = evaluate(expression, Object.class);
    if (value instanceof String) return tokenize((String) value);
    if (value instanceof Collection) return (Collection) value;
    if (value instanceof String[]) return Arrays.asList((String[]) value);
    // give up
    throw new JbpmException(expression + " returned " + value
      + " instead of comma-separated string, string array or collection");
  }

  protected List tokenize(String text) {
    return text != null ? Arrays.asList(text.split("[,;:]+")) : null;
  }

  private Object evaluate(String expression, Class expectedType) {
    VariableResolver variableResolver = new MailVariableResolver(getTemplateVariables(), JbpmExpressionEvaluator.getVariableResolver());
    return JbpmExpressionEvaluator.evaluate(expression, executionContext, expectedType, variableResolver, JbpmExpressionEvaluator.getFunctionMapper());
  }

  public String getSubject() {
    return subject != null ? (String) evaluate(subject, String.class) : null;
  }

  public String getText() {
    return text != null ? (String) evaluate(text, String.class) : null;
  }

  public String getFromAddress() {
    return Configs.hasObject("jbpm.mail.from.address") ?
      Configs.getString("jbpm.mail.from.address") : null;
  }

  public void send() {
    if (template != null) {
      Properties templateProperties = getTemplateProperties(template);

      if (actors == null) actors = templateProperties.getProperty("actors");
      if (to == null) to = templateProperties.getProperty("to");
      if (cc == null) cc = templateProperties.getProperty("cc");
      if (ccActors == null) ccActors = templateProperties.getProperty("cc-actors");
      if (bcc == null) bcc = templateProperties.getProperty("bcc");
      if (bccActors == null) bccActors = templateProperties.getProperty("bcc-actors");
      if (subject == null) subject = templateProperties.getProperty("subject");
      if (text == null) text = templateProperties.getProperty("text");
    }

    String sender = getFromAddress();
    Collection recipients = getRecipients();
    Collection ccRecipients = getCcRecipients();
    Collection bccRecipients = getBccRecipients();
    if (nullOrEmpty(recipients) && nullOrEmpty(ccRecipients) && nullOrEmpty(bccRecipients))
      return;

    String subject = getSubject();
    String text = getText();

    if (log.isDebugEnabled()) {
      StringBuffer detail = new StringBuffer("sending email");
      if (!nullOrEmpty(recipients)) detail.append(" to ").append(recipients);
      if (!nullOrEmpty(ccRecipients)) detail.append(" cc ").append(ccRecipients);
      if (!nullOrEmpty(bccRecipients)) detail.append(" bcc ").append(bccRecipients);
      if (subject != null) detail.append(" about '").append(subject).append('\'');
      log.debug(detail.toString());
    }

    Session session = Session.getInstance(getServerProperties());
    for (int retries = 4; retries >= 0; retries--) {
      try {
        sendInternal(session, sender, recipients, ccRecipients, bccRecipients, subject, text);
        break;
      }
      catch (MessagingException me) {
        if (retries == 0) throw new JbpmException("failed to send email", me);
        log.warn("failed to send email (" + retries + " retries left): " + me.getMessage());
      }
    }
  }

  public static void send(Properties serverProperties, String sender, Collection recipients,
    String subject, String text) {
    send(serverProperties, sender, recipients, null, subject, text);
  }

  public static void send(Properties serverProperties, String sender, Collection recipients,
    Collection bccRecipients, String subject, String text) {
    if (nullOrEmpty(recipients) && nullOrEmpty(bccRecipients)) return;

    if (log.isDebugEnabled()) {
      StringBuffer detail = new StringBuffer("sending email to ");
      detail.append(recipients);
      if (bccRecipients != null) detail.append(" bcc ").append(bccRecipients);
      if (subject != null) detail.append(" about '").append(subject).append('\'');
      log.debug(detail.toString());
    }

    Session session = Session.getInstance(serverProperties);
    for (int retries = 4; retries >= 0; retries--) {
      try {
        sendInternal(session, null, recipients, null, bccRecipients, subject, text);
        break;
      }
      catch (MessagingException me) {
        if (retries == 0) throw new JbpmException("failed to send email", me);
        log.warn("failed to send email (" + retries + " retries left): " + me.getMessage());
      }
    }
  }

  private static boolean nullOrEmpty(Collection col) {
    return col == null || col.isEmpty();
  }

  private static void sendInternal(Session session, String sender, Collection recipients,
    Collection ccRecipients, Collection bccRecipients, String subject, String text)
    throws MessagingException {
    MimeMessage message = new MimeMessage(session);
    // from
    if (sender != null) {
      message.setFrom(new InternetAddress(sender));
    }
    else {
      // read sender from session property "mail.from"
      message.setFrom();
    }
    // to
    if (recipients != null) {
      for (Iterator iter = recipients.iterator(); iter.hasNext();) {
        InternetAddress recipient = new InternetAddress((String) iter.next());
        message.addRecipient(Message.RecipientType.TO, recipient);
      }
    }
    // cc
    if (ccRecipients != null) {
      for (Iterator iter = ccRecipients.iterator(); iter.hasNext();) {
        InternetAddress recipient = new InternetAddress((String) iter.next());
        message.addRecipient(Message.RecipientType.CC, recipient);
      }
    }
    // bcc
    if (bccRecipients != null) {
      for (Iterator iter = bccRecipients.iterator(); iter.hasNext();) {
        InternetAddress recipient = new InternetAddress((String) iter.next());
        message.addRecipient(Message.RecipientType.BCC, recipient);
      }
    }
    // subject
    if (subject != null) message.setSubject(subject);
    // text
    if (text != null) message.setText(text);
    // send the message
    Transport.send(message);
  }

  private static final Map serverPropertiesByResource = new HashMap();

  private Properties getServerProperties() {
    Properties serverProperties;

    if (Configs.hasObject("resource.mail.properties")) {
      String resource = Configs.getString("resource.mail.properties");
      synchronized (serverPropertiesByResource) {
        // look in server properties cache
        serverProperties = (Properties) serverPropertiesByResource.get(resource);
        if (serverProperties == null) {
          // load server properties and put them in the cache
          serverProperties = ClassLoaderUtil.getProperties(resource);
          serverPropertiesByResource.put(resource, serverProperties);
        }
      }
    }
    else {
      serverProperties = new Properties();
      // host
      if (Configs.hasObject("jbpm.mail.smtp.host")) {
        String smtpHost = Configs.getString("jbpm.mail.smtp.host");
        serverProperties.setProperty("mail.smtp.host", smtpHost);
      }
      // port
      if (Configs.hasObject("jbpm.mail.smtp.port")) {
        int port = Configs.getInt("jbpm.mail.smtp.port");
        serverProperties.setProperty("mail.smtp.port", Integer.toString(port));
      }
    }
    return serverProperties;
  }

  private static final Map templatePropertiesByResource = new HashMap();
  private static final Map templateVariablesByResource = new HashMap();

  private static Properties getTemplateProperties(String templateName) {
    String resource = Configs.getString("resource.mail.templates");
    synchronized (templatePropertiesByResource) {
      Map templateProperties = (Map) templatePropertiesByResource.get(resource);
      if (templateProperties == null) {
        loadTemplates(resource);
        templateProperties = (Map) templatePropertiesByResource.get(resource);
      }
      return (Properties) templateProperties.get(templateName);
    }
  }

  private static Map getTemplateVariables() {
    String resource = Configs.getString("resource.mail.templates");
    synchronized (templateVariablesByResource) {
      Map templateVariables = (Map) templateVariablesByResource.get(resource);
      if (templateVariables == null) {
        loadTemplates(resource);
        templateVariables = (Map) templateVariablesByResource.get(resource);
      }
      return templateVariables;
    }
  }

  private static void loadTemplates(String resource) {
    Element templatesElement = XmlUtil.parseXmlResource(resource, true).getDocumentElement();

    Map templatePropertiesMap = new HashMap();
    for (Iterator iter = XmlUtil.elementIterator(templatesElement, "mail-template"); iter.hasNext();) {
      Element templateElement = (Element) iter.next();

      Properties templateProperties = new Properties();
      addTemplateProperty(templateElement, "to", templateProperties);
      addTemplateProperty(templateElement, "actors", templateProperties);
      addTemplateProperty(templateElement, "subject", templateProperties);
      addTemplateProperty(templateElement, "text", templateProperties);
      addTemplateProperty(templateElement, "cc", templateProperties);
      addTemplateProperty(templateElement, "cc-actors", templateProperties);
      addTemplateProperty(templateElement, "bcc", templateProperties);
      // preserve backwards compatibility with bccActors element
      Element bccActorsElement = XmlUtil.element(templateElement, "bccActors");
      if (bccActorsElement != null) {
        templateProperties.setProperty("bcc-actors", XmlUtil.getContentText(bccActorsElement));
      }
      else {
        addTemplateProperty(templateElement, "bcc-actors", templateProperties);
      }

      templatePropertiesMap.put(templateElement.getAttribute("name"), templateProperties);
    }
    templatePropertiesByResource.put(resource, templatePropertiesMap);

    Map templateVariables = new HashMap();
    for (Iterator iter = XmlUtil.elementIterator(templatesElement, "variable"); iter.hasNext();) {
      Element variableElement = (Element) iter.next();
      templateVariables.put(variableElement.getAttribute("name"), variableElement.getAttribute("value"));
    }
    templateVariablesByResource.put(resource, templateVariables);
  }

  private static void addTemplateProperty(Element templateElement, String property,
    Properties templateProperties) {
    Element element = XmlUtil.element(templateElement, property);
    if (element != null) {
      templateProperties.setProperty(property, XmlUtil.getContentText(element));
    }
  }

  static class MailVariableResolver implements VariableResolver, Serializable {

    private Map templateVariables;
    private VariableResolver variableResolver;

    private static final long serialVersionUID = 1L;

    MailVariableResolver(Map templateVariables, VariableResolver variableResolver) {
      this.templateVariables = templateVariables;
      this.variableResolver = variableResolver;
    }

    public Object resolveVariable(String pName) throws ELException {
      if (templateVariables != null && templateVariables.containsKey(pName)) {
        return templateVariables.get(pName);
      }
      return variableResolver != null ? variableResolver.resolveVariable(pName) : null;
    }
  }

  private static final Log log = LogFactory.getLog(Mail.class);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy