/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jbpm.pvm.internal.email.impl; import java.io.File; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.Address; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Message.RecipientType; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import org.jbpm.api.Execution; import org.jbpm.api.JbpmException; import org.jbpm.api.identity.Group; import org.jbpm.api.identity.User; import org.jbpm.pvm.internal.email.spi.AddressResolver; import org.jbpm.pvm.internal.email.spi.MailProducer; import org.jbpm.pvm.internal.env.EnvironmentImpl; import org.jbpm.pvm.internal.identity.spi.IdentitySession; import org.jbpm.pvm.internal.script.ScriptManager; /** * Default mail producer. * * @author Alejandro Guizar */ public class MailProducerImpl implements MailProducer, Serializable { private static final long serialVersionUID = 1L; private MailTemplate template; public MailTemplate getTemplate() { return template; } public void setTemplate(MailTemplate template) { this.template = template; } public Collection produce(Execution execution) { Message email = instantiateEmail(); fillFrom(execution, email); fillRecipients(execution, email); fillSubject(execution, email); fillContent(execution, email); return Collections.singleton(email); } protected Message instantiateEmail() { return new MimeMessage((Session) null); } /** * Fills the from attribute of the given email. The sender addresses are an optional * element in the mail template. If absent, each mail server supplies the current user's email * address. * * @see {@link InternetAddress#getLocalAddress(Session)} */ protected void fillFrom(Execution execution, Message email) { AddressTemplate fromTemplate = template.getFrom(); // "from" attribute is optional if (fromTemplate == null) return; // resolve and parse addresses String addresses = fromTemplate.getAddresses(); if (addresses != null) { addresses = evaluateExpression(addresses, execution); try { email.addFrom(InternetAddress.parse(addresses)); } catch (MessagingException e) { throw new JbpmException("failed to add " + addresses + " to senders", e); } } EnvironmentImpl environment = EnvironmentImpl.getCurrent(); IdentitySession identitySession = environment.get(IdentitySession.class); AddressResolver addressResolver = environment.get(AddressResolver.class); // resolve and tokenize users String userList = fromTemplate.getUsers(); if (userList != null) { String[] userIds = tokenizeActors(userList, execution); List users = identitySession.findUsersById(userIds); addSenders(resolveAddresses(users, addressResolver), email); } // resolve and tokenize groups String groupList = fromTemplate.getGroups(); if (groupList != null) { for (String groupId : tokenizeActors(groupList, execution)) { Group group = identitySession.findGroupById(groupId); addSenders(addressResolver.resolveAddresses(group), email); } } } private String evaluateExpression(String expression, Execution execution) { ScriptManager scriptManager = EnvironmentImpl.getFromCurrent(ScriptManager.class); Object value = scriptManager.evaluateExpression(expression, template.getLanguage()); if (!(value instanceof String)) { throw new JbpmException("expected expression '" + expression + "' to return string, but was: " + value); } return (String) value; } private String[] tokenizeActors(String recipients, Execution execution) { String[] actors = evaluateExpression(recipients, execution).split("[,;|\\s]+"); if (actors.length == 0) throw new JbpmException("recipient list is empty: " + recipients); return actors; } /** construct recipient addresses from user entities */ private Address[] resolveAddresses(List users, AddressResolver addressResolver) { int userCount = users.size(); Address[] addresses = new Address[userCount]; for (int i = 0; i < userCount; i++) { addresses[i] = addressResolver.resolveAddress(users.get(i)); } return addresses; } /** add senders to message */ private void addSenders(Address[] addresses, Message email) { try { email.addFrom(addresses); } catch (MessagingException e) { throw new JbpmException("failed to add " + Arrays.toString(addresses) + " to senders", e); } } protected void fillRecipients(Execution execution, Message email) { // to AddressTemplate to = template.getTo(); if (to != null) fillRecipients(to, execution, email, RecipientType.TO); // cc AddressTemplate cc = template.getCc(); if (cc != null) fillRecipients(cc, execution, email, RecipientType.CC); // bcc AddressTemplate bcc = template.getBcc(); if (bcc != null) fillRecipients(bcc, execution, email, RecipientType.BCC); } private void fillRecipients(AddressTemplate addressTemplate, Execution execution, Message email, RecipientType recipientType) { // resolve and parse addresses String addresses = addressTemplate.getAddresses(); if (addresses != null) { addresses = evaluateExpression(addresses, execution); try { email.addRecipients(recipientType, InternetAddress.parse(addresses)); } catch (MessagingException e) { throw new JbpmException("failed to add " + addresses + " to recipients of type " + recipientType, e); } } EnvironmentImpl environment = EnvironmentImpl.getCurrent(); IdentitySession identitySession = environment.get(IdentitySession.class); AddressResolver addressResolver = environment.get(AddressResolver.class); // resolve and tokenize users String userList = addressTemplate.getUsers(); if (userList != null) { String[] userIds = tokenizeActors(userList, execution); List users = identitySession.findUsersById(userIds); addRecipients(resolveAddresses(users, addressResolver), email, recipientType); } // resolve and tokenize groups String groupList = addressTemplate.getGroups(); if (groupList != null) { for (String groupId : tokenizeActors(groupList, execution)) { Group group = identitySession.findGroupById(groupId); addRecipients(addressResolver.resolveAddresses(group), email, recipientType); } } } /** add recipient addresses to message */ private void addRecipients(Address[] addresses, Message email, RecipientType recipientType) { try { email.addRecipients(recipientType, addresses); } catch (MessagingException e) { throw new JbpmException("failed to add " + Arrays.toString(addresses) + " to recipients of type " + recipientType, e); } } protected void fillSubject(Execution execution, Message email) { String subject = template.getSubject(); if (subject != null) { subject = evaluateExpression(subject, execution); try { email.setSubject(subject); } catch (MessagingException e) { throw new JbpmException("failed to set subject to " + subject, e); } } } protected void fillContent(Execution execution, Message email) { String text = template.getText(); String html = template.getHtml(); List attachmentTemplates = template.getAttachmentTemplates(); if (html != null || !attachmentTemplates.isEmpty()) { // multipart Multipart multipart = new MimeMultipart("related"); // text if (text != null) { BodyPart textPart = new MimeBodyPart(); text = evaluateExpression(text, execution); try { textPart.setText(text); multipart.addBodyPart(textPart); } catch (MessagingException e) { throw new JbpmException("failed to add text content: " + text, e); } } // html if (html != null) { BodyPart htmlPart = new MimeBodyPart(); html = evaluateExpression(html, execution); try { htmlPart.setContent(html, "text/html"); multipart.addBodyPart(htmlPart); } catch (MessagingException e) { throw new JbpmException("failed to add html content: " + html, e); } } // attachments if (!attachmentTemplates.isEmpty()) { addAttachments(execution, multipart); } try { email.setContent(multipart); } catch (MessagingException e) { throw new JbpmException("failed to set multipart content: " + multipart, e); } } else if (text != null) { // unipart text = evaluateExpression(text, execution); try { email.setText(text); } catch (MessagingException e) { throw new JbpmException("failed to add text content: " + text, e); } } } protected void addAttachments(Execution execution, Multipart multipart) { for (AttachmentTemplate attachmentTemplate : template.getAttachmentTemplates()) { BodyPart attachmentPart = new MimeBodyPart(); // resolve and set description String description = attachmentTemplate.getDescription(); if (description != null) { description = evaluateExpression(description, execution); try { attachmentPart.setDescription(description); } catch (MessagingException e) { throw new JbpmException("failed to set attachment description: " + description, e); } } // resolve name; if absent, it will be taken from file or url String name = attachmentTemplate.getName(); if (name != null) { name = evaluateExpression(name, execution); } // resolve and read file String file = attachmentTemplate.getFile(); if (file != null) { File targetFile = new File(evaluateExpression(file, execution)); if (!targetFile.isFile()) { throw new JbpmException("could not read attachment content, file not found: " + targetFile); } // set content from target file try { attachmentPart.setDataHandler(new DataHandler(new FileDataSource(targetFile))); // extract attachment name from file if (name == null) { name = targetFile.getName(); } } catch (MessagingException e) { throw new JbpmException("failed to add attachment content: " + targetFile, e); } } else { URL targetUrl; // resolve and read external url String url = attachmentTemplate.getUrl(); if (url != null) { try { url = evaluateExpression(url, execution); targetUrl = new URL(url); } catch (MalformedURLException e) { throw new JbpmException("could not read attachment content, malformed url: " + url, e); } } // resolve and read classpath resource else { String resource = evaluateExpression(attachmentTemplate.getResource(), execution); targetUrl = EnvironmentImpl.getCurrent().getClassLoader().getResource(resource); if (targetUrl == null) { throw new JbpmException("could not read attachment content, resource not found: " + resource); } } // set content from url try { attachmentPart.setDataHandler(new DataHandler(targetUrl)); // extract attachment name from target url if (name == null) { name = extractResourceName(targetUrl); } } catch (MessagingException e) { throw new JbpmException("failed to add attachment content: " + targetUrl, e); } } // set name, must be resolved at this point try { attachmentPart.setFileName(name); } catch (MessagingException e) { throw new JbpmException("failed to set attachment name: " + name, e); } try { multipart.addBodyPart(attachmentPart); } catch (MessagingException e) { throw new JbpmException("failed to add attachment part: " + attachmentPart, e); } } } private static String extractResourceName(URL url) { String path = url.getPath(); if (path == null || path.length() == 0) return null; int sepIndex = path.lastIndexOf('/'); return sepIndex != -1 ? path.substring(sepIndex) : null; } }