/* =============================================================================== * * Part of the InfoGlue Content Management Platform (www.infoglue.org) * * =============================================================================== * * Copyright (C) * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2, as published by the * Free Software Foundation. See the file LICENSE.html for more information. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple * Place, Suite 330 / Boston, MA 02111-1307 / USA. * * =============================================================================== */ package org.infoglue.cms.applications.workflowtool.function.email; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import javax.activation.DataHandler; import javax.mail.Address; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.SendFailedException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import org.apache.log4j.Logger; import org.infoglue.cms.applications.workflowtool.function.InfoglueFunction; import org.infoglue.cms.exception.SystemException; import org.infoglue.cms.util.mail.ByteDataSource; import org.infoglue.cms.util.mail.MailService; import org.infoglue.cms.util.mail.MailServiceFactory; import org.infoglue.cms.util.mail.StringDataSource; import com.opensymphony.workflow.WorkflowException; /** * */ public class EmailFunction extends InfoglueFunction { private final static Logger logger = Logger.getLogger(EmailFunction.class.getName()); /** * */ private static final String ADDRESS_DELIMITER = ","; /** * */ private static final String EMAIL_PARAMETER_PREFIX = "email_"; /** * */ public static final String ILLEGAL_ADDRESSES_PARAMETER = EMAIL_PARAMETER_PREFIX + "IllegalAddresses"; /** * */ public static final String ILLEGAL_ADDRESSES_PROPERTYSET_KEY = "email_IllegalAddresses"; /** * */ public static final String TO_PARAMETER = EMAIL_PARAMETER_PREFIX + "to"; /** * */ public static final String FROM_PARAMETER = EMAIL_PARAMETER_PREFIX + "from"; /** * */ public static final String ATTACHMENTS_PARAMETER = "attachments"; /** * */ private static final String TO_ARGUMENT = "to"; /** * */ private static final String FROM_ARGUMENT = "from"; /** * */ private static final String SUBJECT_ARGUMENT = "subject"; /** * */ private static final String BODY_ARGUMENT = "body"; /** * */ private static final String BODY_TYPE_ARGUMENT = "type"; /** * */ private static final String SILENT_MODE_ARGUMENT = "silent"; /** * */ private static final String STATUS_OK = "status.email.ok"; /** * */ private static final String STATUS_NOK = "status.email.nok"; /** * */ private MailService service; /** * */ private MimeMessage message; /** * */ private MimeMultipart multipart; /** * */ private Collection attachments = new ArrayList(); /** * The illegal addresses. */ private Collection illegalAddresses; // type: <String> /** * Indicates if a failure should be ignored. */ private boolean silentMode; /** * */ public EmailFunction() { super(); } /** * */ protected void execute() throws WorkflowException { setFunctionStatus(silentMode ? STATUS_OK : STATUS_NOK); try { process(); } catch(Exception e) { if(!silentMode) { throwException(e); } logger.warn("[silent mode]", e); } processIllegalAddresses(); } /** * */ private void processIllegalAddresses() { if(illegalAddresses.isEmpty()) { removeFromPropertySet(ILLEGAL_ADDRESSES_PROPERTYSET_KEY); } else { final StringBuffer sb = new StringBuffer(); for(final Iterator i = illegalAddresses.iterator(); i.hasNext(); ) { final String address = i.next().toString(); sb.append((sb.length() > 0 ? "," : "") + address); } setPropertySetDataString(ILLEGAL_ADDRESSES_PROPERTYSET_KEY, sb.toString()); } setParameter(ILLEGAL_ADDRESSES_PARAMETER, new ArrayList()); } /** * */ private void process() throws WorkflowException { if(illegalAddresses.isEmpty()) { initializeMailService(); createMessage(); sendMessage(); } } /** * */ private void createMessage() throws WorkflowException { if(attachments.isEmpty()) { createSimpleMessage(); } else { createMultipartMessage(); } } /** * */ private void createSimpleMessage() throws WorkflowException { logger.debug("Creating simple message."); initializeMessage(); initializeSimpleBody(); } /** * */ private void createMultipartMessage() throws WorkflowException { logger.debug("Creating message."); initializeMessage(); initializeMultipart(); createMainBodyPart(); createAttachments(); } /** * */ private void initializeMessage() throws WorkflowException { logger.debug("Initializing message."); message = service.createMessage(); initializeTo(); initializeFrom(); initializeSubject(); } /** * */ private void initializeSimpleBody() throws WorkflowException { logger.debug("Initializing simple body."); try { message.setDataHandler(getDataHandler(translate(getArgument(BODY_ARGUMENT)), translate(getArgument(BODY_TYPE_ARGUMENT)))); } catch(Exception e) { throwException(e); } } /** * */ private void initializeMultipart() throws WorkflowException { logger.debug("Initializing multipart."); try { multipart = new MimeMultipart(); message.setContent(multipart); } catch(Exception e) { throwException(e); } } /** * */ private void initializeTo() throws WorkflowException { logger.debug("Initializing to."); try { if(argumentExists(TO_ARGUMENT)) { logger.debug("Adding 'to' from argument [" + getArgument(TO_ARGUMENT) + "]."); message.addRecipients(Message.RecipientType.TO, createAddresses(getArgument(TO_ARGUMENT))); } if(parameterExists(TO_PARAMETER)) { logger.debug("Adding 'to' from parameters"); message.addRecipients(Message.RecipientType.TO, addressesToArray((List) getParameter(TO_PARAMETER))); } } catch(Exception e) { throwException(e); } } /** * */ private void initializeFrom() throws WorkflowException { logger.debug("Initializing from."); try { if(argumentExists(FROM_ARGUMENT)) { logger.debug("Adding 'from' from argument [" + getArgument(FROM_ARGUMENT) + "]."); message.addFrom(createAddresses(getArgument(FROM_ARGUMENT))); } if(parameterExists(FROM_PARAMETER)) { logger.debug("Adding 'from' from parameter."); message.addFrom(addressesToArray((List) getParameter(FROM_PARAMETER))); } } catch(Exception e) { throwException(e); } } /** * */ private void initializeSubject() throws WorkflowException { logger.debug("Initializing subject."); try { message.setSubject(translate(getArgument(SUBJECT_ARGUMENT)), UTF8_ENCODING); } catch(Exception e) { throwException(e); } } /** * */ private void createMainBodyPart() throws WorkflowException { logger.debug("Initializing main body part."); try { final BodyPart part = new MimeBodyPart(); part.setDataHandler(getDataHandler(translate(getArgument(BODY_ARGUMENT)), translate(getArgument(BODY_TYPE_ARGUMENT)))); multipart.addBodyPart(part); } catch(Exception e) { throwException(e); } } /** * */ private void createAttachments() throws WorkflowException { logger.debug("Found " + attachments.size() + " attachments."); for(final Iterator i = attachments.iterator(); i.hasNext(); ) { createAttachment((Attachment) i.next()); } } /** * */ private void createAttachment(final Attachment attachment) throws WorkflowException { try { final BodyPart part = new MimeBodyPart(); part.setDataHandler(getDataHandler(attachment.getBytes(), attachment.getContentType())); part.setFileName(attachment.getName()); multipart.addBodyPart(part); } catch(Exception e) { throwException(e); } } /** * */ private InternetAddress[] createAddresses(final String s) throws WorkflowException { final List addresses = new ArrayList(); for(final StringTokenizer st = new StringTokenizer(s, ADDRESS_DELIMITER); st.hasMoreTokens(); ) { final Address address = createAddress(st.nextToken()); if(address != null) // illegal address? { addresses.add(address); } } return addressesToArray(addresses); } /** * */ private InternetAddress[] addressesToArray(final List list) { final InternetAddress[] addresses = new InternetAddress[list.size()]; for(int i = 0; i < list.size(); ++i) { addresses[i] = (InternetAddress) list.get(i); } return addresses; } /** * */ private InternetAddress createAddress(final String email) { try { return new InternetAddress(email); } catch(Exception e) { illegalAddresses.add(email); } return null; } /** * */ private void initializeMailService() throws WorkflowException { logger.debug("Initializing mail service."); try { service = MailServiceFactory.getService(); } catch(Exception e) { throwException(e); } } /** * */ private void sendMessage() throws WorkflowException { logger.debug("Sending message."); if(illegalAddresses.isEmpty()) { try { if(hasRecipients()) { service.send(message); } setFunctionStatus(STATUS_OK); } catch(SystemException e) { handleSendException(e); } } } /** * */ private boolean hasRecipients() throws WorkflowException { try { return (message.getAllRecipients() != null) && message.getAllRecipients().length > 0; } catch(Exception e) { throwException(e); } return false; } /** * */ private void handleSendException(final SystemException e) throws WorkflowException { if(e.getCause() instanceof SendFailedException) { populateIllegalAddresses((SendFailedException) e.getCause()); } else { throwException(e); } } /** * */ private void populateIllegalAddresses(final SendFailedException e) { final Address[] invalidAddresses = (e.getInvalidAddresses() == null) ? new Address[0] : e.getInvalidAddresses(); for(int i=0; i<invalidAddresses.length; ++i) { illegalAddresses.add(invalidAddresses[i].toString()); } } /** * */ private DataHandler getDataHandler(final String content, final String type) { return new DataHandler(new StringDataSource(content, getContentType(type), UTF8_ENCODING)); } /** * */ private DataHandler getDataHandler(final byte[] content, final String type) { return new DataHandler(new ByteDataSource(content, type)); } /** * */ private String getContentType(final String type) { return type + ";charset=" + UTF8_ENCODING; } /** * Method used for initializing the function; will be called before <code>execute</code> is called. * <p><strong>Note</strong>! You must call <code>super.initialize()</code> first.</p> * * @throws WorkflowException if an error occurs during the initialization. */ protected void initialize() throws WorkflowException { super.initialize(); this.illegalAddresses = (Collection) getParameter(EmailFunction.ILLEGAL_ADDRESSES_PARAMETER, new ArrayList()); this.silentMode = getArgument(SILENT_MODE_ARGUMENT, "false").equalsIgnoreCase("true"); this.attachments = (Collection) getParameter(ATTACHMENTS_PARAMETER, new ArrayList()); } }