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);
}