View Javadoc

1   /*******************************************************************************
2    *  Imixs Workflow 
3    *  Copyright (C) 2001, 2011 Imixs Software Solutions GmbH,  
4    *  http://www.imixs.com
5    *  
6    *  This program is free software; you can redistribute it and/or 
7    *  modify it under the terms of the GNU General Public License 
8    *  as published by the Free Software Foundation; either version 2 
9    *  of the License, or (at your option) any later version.
10   *  
11   *  This program is distributed in the hope that it will be useful, 
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
14   *  General Public License for more details.
15   *  
16   *  You can receive a copy of the GNU General Public
17   *  License at http://www.gnu.org/licenses/gpl.html
18   *  
19   *  Project: 
20   *  	http://www.imixs.org
21   *  	http://java.net/projects/imixs-workflow
22   *  
23   *  Contributors:  
24   *  	Imixs Software Solutions GmbH - initial API and implementation
25   *  	Ralph Soika - Software Developer
26   *******************************************************************************/
27  
28  package org.imixs.workflow.plugins.jee;
29  
30  import java.util.Date;
31  import java.util.Enumeration;
32  import java.util.List;
33  import java.util.Vector;
34  import java.util.logging.Logger;
35  
36  import javax.annotation.Resource;
37  import javax.mail.Message;
38  import javax.mail.MessagingException;
39  import javax.mail.Multipart;
40  import javax.mail.Session;
41  import javax.mail.Transport;
42  import javax.mail.internet.AddressException;
43  import javax.mail.internet.InternetAddress;
44  import javax.mail.internet.MimeBodyPart;
45  import javax.mail.internet.MimeMessage;
46  import javax.mail.internet.MimeMultipart;
47  import javax.naming.InitialContext;
48  import javax.naming.NamingException;
49  
50  import org.imixs.workflow.ItemCollection;
51  import org.imixs.workflow.Plugin;
52  import org.imixs.workflow.WorkflowContext;
53  import org.imixs.workflow.WorkflowKernel;
54  import org.imixs.workflow.exceptions.PluginException;
55  
56  /**
57   * This plugin supports a Mail interface to send mail like defined in the model
58   * using the Mail tab in an activity Entity. This plugin uses the JEE Mail
59   * Interface Currentyl no HTML Mail is supported
60   * 
61   * @author Ralph Soika
62   * 
63   */
64  public class MailPlugin extends AbstractPlugin {
65  
66  	
67  	// Mail objects
68  	Session mailSession;
69  	MimeMessage mailMessage = null;
70  	Multipart mimeMultipart = null;
71  
72  	@Resource(name = "IX_MAIL_SESSION")
73  	private String sIXMailSession = "org.imixs.workflow.jee.mailsession";
74  	
75  	private static Logger logger = Logger.getLogger("org.imixs.workflow");
76  
77  
78  
79  
80  	/**
81  	 * the init method is responsible for initializing the mail session object
82  	 * receifed from the jndi context
83  	 * 
84  	 * The Default name of the Mail Session is
85  	 * 'org.imixs.workflow.jee.mailsession' The name can be overwritten by the
86  	 * EJB Properties of the workflowmanager
87  	 * 
88  	 * @throws NamingException
89  	 */
90  	public void init(WorkflowContext actx) throws PluginException {
91  		super.init(actx);
92  		// Initialize mail session
93  		InitialContext ic;
94  		try {
95  			ic = new InitialContext();
96  
97  			String snName = "";
98  			snName = "java:comp/env/mail/" + sIXMailSession;
99  			mailSession = (Session) ic.lookup(snName);
100 			
101 		} catch (NamingException e) {
102 			throw new PluginException(e.getMessage(),e);
103 		}
104 		
105 	}
106 
107 	public int run(ItemCollection documentContext,
108 			ItemCollection documentActivity) throws PluginException {
109 
110 		String sFrom;
111 		String sReplyTo = "";
112 		// adocumentContext = documentContext;
113 
114 		InternetAddress[] recipientsTo, recipientsCC;
115 
116 		try {
117 			// reset mailMessage object
118 			mailMessage = null;
119 
120 			// check if mail is active?
121 			if ("1".equals(documentActivity
122 					.getItemValueString("keyMailInactive")))
123 				return Plugin.PLUGIN_OK;
124 
125 			// check if recipients are defined
126 			String snamMailReceifer = documentActivity
127 					.getItemValueString("namMailReceiver");
128 			String skeyMailReceiverFields = documentActivity
129 					.getItemValueString("keyMailReceiverFields");
130 
131 			InternetAddress inetAddr = null;
132 			if (((snamMailReceifer != null) && (!"".equals(documentActivity
133 					.getItemValueString("namMailReceiver"))))
134 					|| ((skeyMailReceiverFields != null) && (!""
135 							.equals(documentActivity
136 									.getItemValueString("keyMailReceiverFields"))))) {
137 
138 				sFrom = getUserName();
139 
140 				// check if sender is defined....
141 				if ((sFrom == null) || ("".equals(sFrom)))
142 					return Plugin.PLUGIN_OK;
143 
144 				// first initialize mail message object
145 				initializeMailMessage();
146 
147 				// check for ReplyTo...
148 				if ("1".equals(documentActivity
149 						.getItemValueString("keyMailReplyToCurrentUser")))
150 					sReplyTo = getUserName();
151 				else
152 					sReplyTo = documentActivity
153 							.getItemValueString("namMailReplyToUser");
154 
155 				// sender = CurrentUser?
156 				mailMessage.setFrom(getInternetAddress(sFrom));
157 
158 				// replay to?
159 				if ((sReplyTo != null) && (!"".equals(sReplyTo))) {
160 					InternetAddress[] resplysAdrs = new InternetAddress[1];
161 					resplysAdrs[0] = getInternetAddress(sReplyTo);
162 					mailMessage.setReplyTo(resplysAdrs);
163 				}
164 
165 				// build Recipient from Vector namMailReceiver
166 				List vectorRecipients = documentActivity
167 						.getItemValue("namMailReceiver");
168 				if (vectorRecipients == null)
169 					vectorRecipients = new Vector();
170 
171 				// read keyMailReceiverFields (mulit value)
172 				// here are the field names defined
173 				mergeMappedFieldValues(documentContext, vectorRecipients,
174 						documentActivity.getItemValue("keyMailReceiverFields"));
175 
176 				// cancel send mail if no receipiens defined
177 				if (vectorRecipients.size() == 0) {
178 					mailMessage = null;
179 					return Plugin.PLUGIN_OK;
180 				}
181 
182 				/*
183 				 * In the following code the vector with email addresses will be
184 				 * transformed into a InternetAddress array. Therefore the
185 				 * helper getInternetAddress() method will be called which can
186 				 * be over written by a subclass. The Method call
187 				 * getInternetAddressArray ensures additional that no 'null'
188 				 * values will be stored into the array as this would throw a
189 				 * exception into the setReceipients call of the mailMessage
190 				 * object
191 				 */
192 
193 				// set TO Recipient
194 				recipientsTo = getInternetAddressArray(vectorRecipients);
195 				mailMessage.setRecipients(Message.RecipientType.TO,
196 						recipientsTo);
197 
198 				// build Recipient Vector from namMailReceiver
199 				vectorRecipients = documentActivity
200 						.getItemValue("namMailReceiverCC");
201 				if (vectorRecipients == null)
202 					vectorRecipients = new Vector();
203 
204 				// now read keyMailReceiverFieldsCC (multi value)
205 				mergeMappedFieldValues(documentContext, vectorRecipients,
206 						documentActivity
207 								.getItemValue("keyMailReceiverFieldsCC"));
208 
209 				// set CC Recipients
210 				// build array...
211 				recipientsCC = getInternetAddressArray(vectorRecipients);
212 				mailMessage.setRecipients(Message.RecipientType.CC,
213 						recipientsCC);
214 
215 				// set Subject
216 				mailMessage.setSubject(replaceDynamicValues(
217 						documentActivity.getItemValueString("txtMailSubject"),
218 						documentContext));
219 
220 				// build mail body...
221 				String aBodyText = documentActivity
222 						.getItemValueString("rtfMailBody");
223 				if (aBodyText != null) {
224 					aBodyText = replaceDynamicValues(aBodyText, documentContext);
225 					// set mailbody
226 					MimeBodyPart messagePart = new MimeBodyPart();
227 					messagePart.setText(aBodyText);
228 					mimeMultipart.addBodyPart(messagePart);
229 					// mimeMulitPart object can be extended from subclases
230 				}
231 
232 				// write debug Log
233 				if ((recipientsTo.length > 0) && ctx.getLogLevel()==WorkflowKernel.LOG_LEVEL_FINE) {
234 					System.out
235 							.println("[MailPlugin] New Mail prepered for sending...");
236 					System.out.println("[MailPlugin] Type: PlainText");
237 					System.out.println("[MailPlugin] From: " + sFrom);
238 					System.out.println("[MailPlugin] SendTo ("
239 							+ recipientsTo.length + " Receipients):");
240 
241 					for (int j = 0; j < recipientsTo.length; j++)
242 						System.out.println("[MailPlugin]     "
243 								+ recipientsTo[j].getAddress());
244 
245 					System.out.println("[MailPlugin] CopyTo ("
246 							+ recipientsCC.length + " Receipients):");
247 					for (int j = 0; j < recipientsCC.length; j++)
248 						System.out.println("[MailPlugin]     "
249 								+ recipientsCC[j].getAddress());
250 				}
251 
252 			} else {
253 				if (ctx.getLogLevel()==WorkflowKernel.LOG_LEVEL_FINE)
254 					logger.info("[MailPlugin] No Receipients defined for this Activity...");
255 
256 			}
257 
258 		} catch (Exception e) {
259 			logger.warning("[MailPlugin] run - Warning:" + e.toString());
260 			return Plugin.PLUGIN_WARNING;
261 		}
262 
263 		return Plugin.PLUGIN_OK;
264 	}
265 
266 	public void close(int status) throws PluginException {
267 		if (status == Plugin.PLUGIN_OK && mailSession != null
268 				&& mailMessage != null) {
269 			// Send the message
270 			try {
271 				if (ctx.getLogLevel()==WorkflowKernel.LOG_LEVEL_FINE)
272 					logger.info("[MailPlugin] SendMessage now...");
273 
274 				// if send message fails (e.g. for policy reasons) the process
275 				// will
276 				// continue. only a exception is thrown
277 
278 				// Transport.send(mailMessage);
279 
280 				// A simple transport.send command did not work if mail host
281 				// needs
282 				// a authentification. Therefor we use a manual smtp connection
283 
284 				Transport trans = mailSession.getTransport("smtp");
285 				trans.connect(mailSession.getProperty("mail.smtp.user"),
286 						mailSession.getProperty("mail.smtp.password"));
287 
288 				mailMessage.setContent(mimeMultipart);
289 
290 				mailMessage.saveChanges();
291 				trans.sendMessage(mailMessage, mailMessage.getAllRecipients());
292 				trans.close();
293 
294 			} catch (Exception esend) {
295 				logger.warning("[MailPlugin] close - Warning:" + esend.toString());
296 			}
297 		}
298 	}
299 
300 	/**
301 	 * initializes a new mail Message object
302 	 * 
303 	 * @throws AddressException
304 	 * @throws MessagingException
305 	 */
306 	public void initializeMailMessage() throws AddressException,
307 			MessagingException {
308 
309 		// Alle Properties ausgeben....
310 		/*
311 		 * Properties props = mailSession.getProperties(); Enumeration
312 		 * enumer=props.keys(); while (enumer.hasMoreElements()) { String
313 		 * aKey=enumer.nextElement().toString(); System.out
314 		 * .println("[MailPlugin]  ProperyName= "+aKey); System.out
315 		 * .println("[MailPlugin]  PropertyValue= "
316 		 * +props.getProperty(aKey).toString()); }
317 		 */
318 		mailMessage = new MimeMessage(mailSession);
319 		mailMessage.setSentDate(new Date());
320 		mailMessage.setFrom();
321 		mimeMultipart = new MimeMultipart();
322 	}
323 
324 	
325 
326 	/**
327 	 * this helper method creates an internet address from a string if the
328 	 * string has illegal characters like whitespace the string will be
329 	 * surrounded with "". If you subclass this MailPlugin Class you can
330 	 * overwrite this method to return a different mail-address name or lookup a
331 	 * mail attribute in a directory like a ldap directory.
332 	 * 
333 	 * @param aAddr
334 	 * @return
335 	 * @throws AddressException
336 	 */
337 	public InternetAddress getInternetAddress(String aAddr)
338 			throws AddressException {
339 
340 		InternetAddress inetAddr = null;
341 
342 		try {
343 			// surround with "" if space
344 			if (aAddr.indexOf(" ") > -1)
345 				inetAddr = new InternetAddress("\"" + aAddr + "\"");
346 			else
347 				inetAddr = new InternetAddress(aAddr);
348 
349 		} catch (AddressException ae) {
350 			// return empty address part
351 			ae.printStackTrace();
352 			return null;
353 		}
354 		return inetAddr;
355 	}
356 
357 	/**
358 	 * this method transforms a vector of emails into a InternetAddress Array.
359 	 * Null values will be removed from list
360 	 * 
361 	 * @param aList
362 	 * @return
363 	 */
364 	private InternetAddress[] getInternetAddressArray(List aList) {
365 		// set TO Recipient
366 		// store valid addresses into atemp vector to avoid null values
367 		InternetAddress inetAddr = null;
368 		Vector vReceipsTemp = new Vector();
369 		for (int i = 0; i < aList.size(); i++) {
370 			try {
371 				inetAddr = getInternetAddress(aList.get(i).toString());
372 				if (inetAddr != null && !"".equals(inetAddr.getAddress()))
373 					vReceipsTemp.add(inetAddr);
374 			} catch (AddressException e) {
375 				// no todo
376 			}
377 
378 		}
379 
380 		// rebuild new InternetAddress array from TempVector...
381 		InternetAddress[] receipsAdrs = new InternetAddress[vReceipsTemp.size()];
382 		for (int i = 0; i < vReceipsTemp.size(); i++) {
383 			receipsAdrs[i] = (InternetAddress) vReceipsTemp.elementAt(i);
384 		}
385 		return receipsAdrs;
386 	}
387 
388 	public Session getMailSession() {
389 		return mailSession;
390 	}
391 
392 	public Message getMailMessage() {
393 		return mailMessage;
394 	}
395 
396 	public Multipart getMultipart() {
397 		return mimeMultipart;
398 	}
399 
400 }