001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.mail;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.LinkedHashMap;
024: import java.util.List;
025:
026: import org.kuali.rice.core.Core;
027:
028: import edu.iu.uis.eden.EdenConstants;
029: import edu.iu.uis.eden.KEWServiceLocator;
030: import edu.iu.uis.eden.actionitem.ActionItem;
031: import edu.iu.uis.eden.actionlist.ActionListService;
032: import edu.iu.uis.eden.actionrequests.ActionRequestValue;
033: import edu.iu.uis.eden.clientapp.IDocHandler;
034: import edu.iu.uis.eden.clientapp.vo.ActionRequestVO;
035: import edu.iu.uis.eden.clientapp.vo.RouteHeaderVO;
036: import edu.iu.uis.eden.doctype.DocumentType;
037: import edu.iu.uis.eden.plugin.attributes.CustomEmailAttribute;
038: import edu.iu.uis.eden.preferences.Preferences;
039: import edu.iu.uis.eden.routeheader.DocumentRouteHeaderValue;
040: import edu.iu.uis.eden.server.BeanConverter;
041: import edu.iu.uis.eden.user.UserService;
042: import edu.iu.uis.eden.user.WorkflowUser;
043: import edu.iu.uis.eden.user.WorkflowUserId;
044: import edu.iu.uis.eden.useroptions.UserOptions;
045: import edu.iu.uis.eden.useroptions.UserOptionsService;
046: import edu.iu.uis.eden.util.Utilities;
047:
048: /**
049: * Implementation of the {@link ActionListEmailService}.
050: *
051: * @author xqi
052: * @author rkirkend
053: * @author ewestfal
054: */
055: public class ActionListEmailServiceImpl implements
056: ActionListEmailService {
057: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
058: .getLogger(ActionListEmailServiceImpl.class);
059:
060: private static final String DEFAULT_EMAIL_FROM_ADDRESS = "workflow@indiana.edu";
061:
062: private static final String ACTION_LIST_REMINDER = "OneStart Action List Reminder";
063:
064: private String deploymentEnvironment;
065:
066: public String getDocumentTypeEmailAddress(DocumentType documentType) {
067: String fromAddress = (documentType == null ? null
068: : documentType.getNotificationFromAddress());
069: if (Utilities.isEmpty(fromAddress)) {
070: fromAddress = getApplicationEmailAddress();
071: }
072: return fromAddress;
073: }
074:
075: public String getApplicationEmailAddress() {
076: // first check the configured value
077: String fromAddress = Utilities
078: .getApplicationConstant(EdenConstants.EMAIL_REMINDER_FROM_ADDRESS_KEY);
079: // if there's no value configured, use the default
080: if (Utilities.isEmpty(fromAddress)) {
081: fromAddress = DEFAULT_EMAIL_FROM_ADDRESS;
082: }
083: return fromAddress;
084: }
085:
086: private String getHelpLink() {
087: return getHelpLink(null);
088: }
089:
090: private String getHelpLink(DocumentType documentType) {
091: return "For additional help, email " + "<mailto:"
092: + getDocumentTypeEmailAddress(documentType) + ">";
093: }
094:
095: EmailSubject getEmailSubject() {
096: return new EmailSubject(ACTION_LIST_REMINDER);
097: }
098:
099: EmailSubject getEmailSubject(String customSubject) {
100: return new EmailSubject(ACTION_LIST_REMINDER + " "
101: + customSubject);
102: }
103:
104: private EmailFrom getEmailFrom(DocumentType documentType) {
105: return new EmailFrom(getDocumentTypeEmailAddress(documentType));
106: }
107:
108: private void sendEmail(WorkflowUser user, EmailSubject subject,
109: EmailBody body) {
110: sendEmail(user, subject, body, null);
111: }
112:
113: private void sendEmail(WorkflowUser user, EmailSubject subject,
114: EmailBody body, DocumentType documentType) {
115: try {
116: if (isProduction()) {
117: KEWServiceLocator.getEmailService().sendEmail(
118: getEmailFrom(documentType),
119: new EmailTo(user.getEmailAddress()), subject,
120: body, false);
121: } else {
122: KEWServiceLocator
123: .getEmailService()
124: .sendEmail(
125: getEmailFrom(documentType),
126: new EmailTo(
127: Utilities
128: .getApplicationConstant(EdenConstants.ACTIONLIST_EMAIL_TEST_ADDRESS)),
129: subject, body, false);
130: }
131: } catch (Exception e) {
132: LOG.error("Error sending email.", e);
133: }
134: }
135:
136: public void sendImmediateReminder(WorkflowUser user,
137: ActionItem actionItem) {
138: if (sendActionListEmailNotification()) {
139: DocumentRouteHeaderValue document = KEWServiceLocator
140: .getRouteHeaderService().getRouteHeader(
141: actionItem.getRouteHeaderId());
142: StringBuffer emailBody = new StringBuffer(
143: buildImmediateReminderBody(user, actionItem,
144: document.getDocumentType()));
145: StringBuffer emailSubject = new StringBuffer();
146: try {
147: CustomEmailAttribute customEmailAttribute = actionItem
148: .getRouteHeader().getCustomEmailAttribute();
149: if (customEmailAttribute != null) {
150: RouteHeaderVO routeHeaderVO = BeanConverter
151: .convertRouteHeader(actionItem
152: .getRouteHeader(), user);
153: ActionRequestValue actionRequest = KEWServiceLocator
154: .getActionRequestService()
155: .findByActionRequestId(
156: actionItem.getActionRequestId());
157: ActionRequestVO actionRequestVO = BeanConverter
158: .convertActionRequest(actionRequest);
159: customEmailAttribute
160: .setRouteHeaderVO(routeHeaderVO);
161: customEmailAttribute
162: .setActionRequestVO(actionRequestVO);
163: String customBody = customEmailAttribute
164: .getCustomEmailBody();
165: if (!Utilities.isEmpty(customBody)) {
166: emailBody.append(customBody);
167: }
168: String customEmailSubject = customEmailAttribute
169: .getCustomEmailSubject();
170: if (!Utilities.isEmpty(customEmailSubject)) {
171: emailSubject.append(customEmailSubject);
172: }
173: }
174: } catch (Exception e) {
175: LOG
176: .error(
177: "Error when checking for custom email body and subject.",
178: e);
179: }
180: sendEmail(user, getEmailSubject(emailSubject.toString()),
181: new EmailBody(emailBody.toString()), document
182: .getDocumentType());
183: }
184:
185: }
186:
187: private boolean isProduction() {
188: return EdenConstants.PROD_DEPLOYMENT_CODE
189: .equals(getDeploymentEnvironment());
190: }
191:
192: public void sendDailyReminder() {
193: if (sendActionListEmailNotification()) {
194: Collection users = getUsersWithEmailSetting(EdenConstants.EMAIL_RMNDR_DAY_VAL);
195: for (Iterator userIter = users.iterator(); userIter
196: .hasNext();) {
197: WorkflowUser user = (WorkflowUser) userIter.next();
198: try {
199: Collection actionItems = getActionListService()
200: .getActionList(user, null);
201: if (actionItems != null && actionItems.size() > 0) {
202: sendReminder(user, actionItems,
203: EdenConstants.EMAIL_RMNDR_DAY_VAL);
204: }
205: } catch (Exception e) {
206: LOG.error(
207: "Error sending daily action list reminder to user: "
208: + user.getEmailAddress(), e);
209: }
210: }
211: }
212: LOG.debug("Daily action list emails sent successful");
213: }
214:
215: public void sendWeeklyReminder() {
216: if (sendActionListEmailNotification()) {
217: Collection users = getUsersWithEmailSetting(EdenConstants.EMAIL_RMNDR_WEEK_VAL);
218: for (Iterator userIter = users.iterator(); userIter
219: .hasNext();) {
220: WorkflowUser user = (WorkflowUser) userIter.next();
221: try {
222: Collection actionItems = getActionListService()
223: .getActionList(user, null);
224: if (actionItems != null && actionItems.size() > 0) {
225: sendReminder(user, actionItems,
226: EdenConstants.EMAIL_RMNDR_WEEK_VAL);
227: }
228: } catch (Exception e) {
229: LOG.error(
230: "Error sending weekly action list reminder to user: "
231: + user.getEmailAddress(), e);
232: }
233: }
234: }
235: LOG.debug("Weekly action list emails sent successful");
236: }
237:
238: private void sendReminder(WorkflowUser user,
239: Collection actionItems, String emailSetting) {
240: String emailBody = null;
241: actionItems = filterActionItemsToNotify(user, actionItems);
242: // if there are no action items after being filtered, there's no
243: // reason to send the email
244: if (actionItems.isEmpty()) {
245: return;
246: }
247: if (EdenConstants.EMAIL_RMNDR_DAY_VAL.equals(emailSetting)) {
248: emailBody = buildDailyReminderBody(user, actionItems);
249: } else if (EdenConstants.EMAIL_RMNDR_WEEK_VAL
250: .equals(emailSetting)) {
251: emailBody = buildWeeklyReminderBody(user, actionItems);
252: }
253: sendEmail(user, getEmailSubject(), new EmailBody(emailBody));
254: }
255:
256: /**
257: * Returns a filtered Collection of {@link ActionItem}s which are
258: * filtered according to the user's preferences. If they have opted
259: * not to recieve secondary or primary delegation emails then they
260: * will not be included.
261: */
262: private Collection filterActionItemsToNotify(WorkflowUser user,
263: Collection actionItems) {
264: List filteredItems = new ArrayList();
265: Preferences preferences = KEWServiceLocator
266: .getPreferencesService().getPreferences(user);
267: for (Iterator iterator = actionItems.iterator(); iterator
268: .hasNext();) {
269: ActionItem actionItem = (ActionItem) iterator.next();
270: if (!actionItem.getWorkflowId()
271: .equals(user.getWorkflowId())) {
272: LOG
273: .warn("Encountered an ActionItem with an incorrect workflow ID. Was "
274: + actionItem.getWorkflowId()
275: + " but expected "
276: + user.getWorkflowId());
277: continue;
278: }
279: boolean includeItem = true;
280: if (EdenConstants.DELEGATION_PRIMARY.equals(actionItem
281: .getDelegationType())) {
282: includeItem = EdenConstants.PREFERENCES_YES_VAL
283: .equals(preferences
284: .getNotifyPrimaryDelegation());
285: } else if (EdenConstants.DELEGATION_SECONDARY
286: .equals(actionItem.getDelegationType())) {
287: includeItem = EdenConstants.PREFERENCES_YES_VAL
288: .equals(preferences
289: .getNotifySecondaryDelegation());
290: }
291: if (includeItem) {
292: filteredItems.add(actionItem);
293: }
294: }
295: return filteredItems;
296: }
297:
298: private List getUsersWithEmailSetting(String setting) {
299: List users = new ArrayList();
300: Collection userOptions = getUserOptionsService()
301: .findByOptionValue(EdenConstants.EMAIL_RMNDR_KEY,
302: setting);
303: for (Iterator iter = userOptions.iterator(); iter.hasNext();) {
304: String workflowId = ((UserOptions) iter.next())
305: .getWorkflowId();
306: try {
307: users.add(getUserService().getWorkflowUser(
308: new WorkflowUserId(workflowId)));
309: } catch (Exception e) {
310: LOG.error("error retrieving workflow user with ID: "
311: + workflowId);
312: }
313: }
314: return users;
315: }
316:
317: String buildImmediateReminderBody(WorkflowUser user,
318: ActionItem actionItem, DocumentType documentType) {
319: String docHandlerUrl = actionItem.getRouteHeader()
320: .getDocumentType().getDocHandlerUrl();
321: if (docHandlerUrl.indexOf("?") == -1) {
322: docHandlerUrl += "?";
323: } else {
324: docHandlerUrl += "&";
325: }
326: docHandlerUrl += IDocHandler.ROUTEHEADER_ID_PARAMETER + "="
327: + actionItem.getRouteHeaderId();
328: docHandlerUrl += "&" + IDocHandler.COMMAND_PARAMETER + "="
329: + IDocHandler.ACTIONLIST_COMMAND;
330: StringBuffer sf = new StringBuffer();
331:
332: sf
333: .append("Your OneStart Action List has an eDoc(electronic document) that needs your attention: \n\n");
334: sf.append("Document ID:\t" + actionItem.getRouteHeaderId()
335: + "\n");
336: sf.append("Initiator:\t\t");
337: try {
338: sf.append(actionItem.getRouteHeader().getInitiatorUser()
339: .getDisplayName()
340: + "\n");
341: } catch (Exception e) {
342: LOG.error("Error retrieving initiator for action item "
343: + actionItem.getRouteHeaderId());
344: sf.append("\n");
345: }
346: sf.append("Type:\t\t"
347: + "Add/Modify "
348: + actionItem.getRouteHeader().getDocumentType()
349: .getName() + "\n");
350: sf.append("Title:\t\t" + actionItem.getDocTitle() + "\n");
351: sf.append("\n\n");
352: sf.append("To respond to this eDoc: \n");
353: sf.append("\tGo to " + docHandlerUrl + "\n\n");
354: sf
355: .append("\tOr you may access the eDoc from your Action List: \n");
356: sf.append("\tGo to " + getActionListUrl()
357: + ", and then click on the numeric Document ID: "
358: + actionItem.getRouteHeaderId()
359: + " in the first column of the List. \n");
360: sf.append("\n\n\n");
361: sf
362: .append("To change how these email notifications are sent(daily, weekly or none): \n");
363: sf.append("\tGo to " + getPreferencesUrl() + "\n");
364: sf.append("\n\n\n");
365: sf.append(getHelpLink(documentType) + "\n\n\n");
366:
367: // for debugging purposes on the immediate reminder only
368: if (!isProduction()) {
369: try {
370: sf.append("Action Item sent to "
371: + actionItem.getUser()
372: .getAuthenticationUserId()
373: .getAuthenticationId());
374: if (actionItem.getDelegationType() != null) {
375: sf.append(" for delegation type "
376: + actionItem.getDelegationType());
377: }
378: } catch (Exception e) {
379: throw new RuntimeException(e);
380: }
381: }
382:
383: return sf.toString();
384: }
385:
386: String buildDailyReminderBody(WorkflowUser user,
387: Collection actionItems) {
388: StringBuffer sf = new StringBuffer();
389: sf.append(getDailyWeeklyMessageBody(actionItems));
390: sf
391: .append("To change how these email notifications are sent (immediately, weekly or none): \n");
392: sf.append("\tGo to " + getPreferencesUrl() + "\n");
393: // sf.append("\tSend as soon as you get an eDoc\n\t" +
394: // getPreferencesUrl() + "\n\n");
395: // sf.append("\tSend weekly\n\t" + getPreferencesUrl() + "\n\n");
396: // sf.append("\tDo not send\n\t" + getPreferencesUrl() + "\n");
397: sf.append("\n\n\n");
398: sf.append(getHelpLink() + "\n\n\n");
399: return sf.toString();
400: }
401:
402: String buildWeeklyReminderBody(WorkflowUser user,
403: Collection actionItems) {
404: StringBuffer sf = new StringBuffer();
405: sf.append(getDailyWeeklyMessageBody(actionItems));
406: sf
407: .append("To change how these email notifications are sent (immediately, daily or none): \n");
408: sf.append("\tGo to " + getPreferencesUrl() + "\n");
409: // sf.append("\tSend as soon as you get an eDoc\n\t" +
410: // getPreferencesUrl() + "\n\n");
411: // sf.append("\tSend daily\n\t" + getPreferencesUrl() + "\n\n");
412: // sf.append("\tDo not send\n\t" + getPreferencesUrl() + "\n");
413: sf.append("\n\n\n");
414: sf.append(getHelpLink() + "\n\n\n");
415: return sf.toString();
416: }
417:
418: String getDailyWeeklyMessageBody(Collection actionItems) {
419: StringBuffer sf = new StringBuffer();
420: HashMap docTypes = getActionListItemsStat(actionItems);
421:
422: sf
423: .append("Your OneStart Action List has "
424: + actionItems.size()
425: + " eDocs(electronic documents) that need your attention: \n\n");
426: Iterator iter = docTypes.keySet().iterator();
427: while (iter.hasNext()) {
428: String docTypeName = (String) iter.next();
429: sf.append("\t"
430: + ((Integer) docTypes.get(docTypeName)).toString()
431: + "\t" + docTypeName + "\n");
432: }
433: sf.append("\n\n");
434: sf.append("To respond to each of these eDocs: \n");
435: sf
436: .append("\tGo to "
437: + getActionListUrl()
438: + ", and then click on its numeric Document ID in the first column of the List.\n");
439: sf.append("\n\n\n");
440: return sf.toString();
441: }
442:
443: private HashMap getActionListItemsStat(Collection actionItems) {
444: HashMap docTypes = new LinkedHashMap();
445: Iterator iter = actionItems.iterator();
446:
447: while (iter.hasNext()) {
448: String docTypeName = ((ActionItem) iter.next())
449: .getRouteHeader().getDocumentType().getName();
450: if (docTypes.containsKey(docTypeName)) {
451: docTypes.put(docTypeName, new Integer(
452: ((Integer) docTypes.get(docTypeName))
453: .intValue() + 1));
454: } else {
455: docTypes.put(docTypeName, new Integer(1));
456: }
457: }
458: return docTypes;
459: }
460:
461: private boolean sendActionListEmailNotification() {
462: return EdenConstants.ACTION_LIST_SEND_EMAIL_NOTIFICATION_VALUE
463: .equals(Utilities
464: .getApplicationConstant(EdenConstants.ACTION_LIST_SEND_EMAIL_NOTIFICATION_KEY));
465: }
466:
467: public UserService getUserService() {
468: return (UserService) KEWServiceLocator.getUserService();
469: }
470:
471: private UserOptionsService getUserOptionsService() {
472: return (UserOptionsService) KEWServiceLocator
473: .getUserOptionsService();
474: }
475:
476: private ActionListService getActionListService() {
477: return (ActionListService) KEWServiceLocator
478: .getActionListService();
479: }
480:
481: public String getDeploymentEnvironment() {
482: return deploymentEnvironment;
483: }
484:
485: public void setDeploymentEnvironment(String deploymentEnvironment) {
486: this .deploymentEnvironment = deploymentEnvironment;
487: }
488:
489: private String getActionListUrl() {
490: return Core.getCurrentContextConfig().getBaseUrl()
491: + Utilities
492: .getApplicationConstant(EdenConstants.APPLICATION_CONTEXT_KEY)
493: + "/" + "ActionList.do";
494: }
495:
496: private String getPreferencesUrl() {
497: return Core.getCurrentContextConfig().getBaseUrl()
498: + Utilities
499: .getApplicationConstant(EdenConstants.APPLICATION_CONTEXT_KEY)
500: + "/" + "Preferences.do";
501: }
502: }
|