Coverage Report - org.kuali.rice.kew.mail.service.impl.ActionListEmailServiceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ActionListEmailServiceImpl
0%
0/252
0%
0/112
2.971
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kew.mail.service.impl;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.api.config.property.ConfigContext;
 20  
 import org.kuali.rice.core.api.delegation.DelegationType;
 21  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 22  
 import org.kuali.rice.core.mail.EmailBody;
 23  
 import org.kuali.rice.core.mail.EmailFrom;
 24  
 import org.kuali.rice.core.mail.EmailSubject;
 25  
 import org.kuali.rice.core.mail.EmailTo;
 26  
 import org.kuali.rice.core.mail.Mailer;
 27  
 import org.kuali.rice.kew.actionlist.service.ActionListService;
 28  
 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
 29  
 import org.kuali.rice.kew.api.KewApiServiceLocator;
 30  
 import org.kuali.rice.kew.api.action.ActionItem;
 31  
 import org.kuali.rice.kew.api.action.ActionRequest;
 32  
 import org.kuali.rice.kew.api.document.Document;
 33  
 import org.kuali.rice.kew.api.preferences.Preferences;
 34  
 import org.kuali.rice.kew.doctype.bo.DocumentType;
 35  
 import org.kuali.rice.kew.mail.CustomEmailAttribute;
 36  
 import org.kuali.rice.kew.mail.DailyEmailJob;
 37  
 import org.kuali.rice.kew.mail.WeeklyEmailJob;
 38  
 import org.kuali.rice.kew.mail.service.ActionListEmailService;
 39  
 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
 40  
 import org.kuali.rice.kew.service.KEWServiceLocator;
 41  
 import org.kuali.rice.kew.useroptions.UserOptions;
 42  
 import org.kuali.rice.kew.useroptions.UserOptionsService;
 43  
 import org.kuali.rice.kew.api.KewApiConstants;
 44  
 import org.kuali.rice.kim.api.identity.Person;
 45  
 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
 46  
 import org.kuali.rice.krad.util.KRADConstants;
 47  
 import org.kuali.rice.ksb.service.KSBServiceLocator;
 48  
 import org.quartz.CronTrigger;
 49  
 import org.quartz.JobDetail;
 50  
 import org.quartz.ObjectAlreadyExistsException;
 51  
 import org.quartz.Scheduler;
 52  
 import org.quartz.SchedulerException;
 53  
 import org.quartz.Trigger;
 54  
 
 55  
 import java.text.FieldPosition;
 56  
 import java.text.MessageFormat;
 57  
 import java.util.ArrayList;
 58  
 import java.util.Collection;
 59  
 import java.util.HashMap;
 60  
 import java.util.Iterator;
 61  
 import java.util.LinkedHashMap;
 62  
 import java.util.List;
 63  
 import java.util.Map;
 64  
 
 65  
 /**
 66  
  * ActionListeEmailService which generates messages whose body and subject can be customized via KEW
 67  
  * configuration parameters, 'immediate.reminder.email.message' and
 68  
  * 'immediate.reminder.email.subject'. The immediate reminder email message key should specify a
 69  
  * MessageFormat string. See code for the parameters to this MessageFormat.
 70  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 71  
  */
 72  0
 public class ActionListEmailServiceImpl implements ActionListEmailService {
 73  0
     private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
 74  
             .getLogger(ActionListEmailServiceImpl.class);
 75  
 
 76  
     private static final String DEFAULT_EMAIL_FROM_ADDRESS = "admin@localhost";
 77  
 
 78  
     private static final String ACTION_LIST_REMINDER = "Action List Reminder";
 79  
 
 80  
     private static final String IMMEDIATE_REMINDER_EMAIL_MESSAGE_KEY = "immediate.reminder.email.message";
 81  
 
 82  
     private static final String IMMEDIATE_REMINDER_EMAIL_SUBJECT_KEY = "immediate.reminder.email.subject";
 83  
 
 84  
     private static final String DAILY_TRIGGER_NAME = "Daily Email Trigger";
 85  
     private static final String DAILY_JOB_NAME = "Daily Email";
 86  
     private static final String WEEKLY_TRIGGER_NAME = "Weekly Email Trigger";
 87  
     private static final String WEEKLY_JOB_NAME = "Weekly Email";
 88  
 
 89  
     private String deploymentEnvironment;
 90  
 
 91  
     private Mailer mailer;
 92  
 
 93  
     public void setMailer(Mailer mailer) {
 94  0
         this.mailer = mailer;
 95  0
     }
 96  
 
 97  
     public String getDocumentTypeEmailAddress(DocumentType documentType) {
 98  0
         String fromAddress = (documentType == null ? null : documentType
 99  
                 .getNotificationFromAddress());
 100  0
         if (org.apache.commons.lang.StringUtils.isEmpty(fromAddress)) {
 101  0
             fromAddress = getApplicationEmailAddress();
 102  
         }
 103  0
         return fromAddress;
 104  
     }
 105  
 
 106  
     public String getApplicationEmailAddress() {
 107  
         // first check the configured value
 108  0
         String fromAddress = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(
 109  
                 KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.MAILER_DETAIL_TYPE,
 110  
                 KewApiConstants.EMAIL_REMINDER_FROM_ADDRESS);
 111  
         // if there's no value configured, use the default
 112  0
         if (org.apache.commons.lang.StringUtils.isEmpty(fromAddress)) {
 113  0
             fromAddress = DEFAULT_EMAIL_FROM_ADDRESS;
 114  
         }
 115  0
         return fromAddress;
 116  
     }
 117  
 
 118  
     protected String getHelpLink() {
 119  0
         return getHelpLink(null);
 120  
     }
 121  
 
 122  
     protected String getHelpLink(DocumentType documentType) {
 123  0
         return "For additional help, email " + "<mailto:"
 124  
                 + getDocumentTypeEmailAddress(documentType) + ">";
 125  
     }
 126  
 
 127  
     public EmailSubject getEmailSubject() {
 128  0
         String subject = ConfigContext.getCurrentContextConfig().getProperty(IMMEDIATE_REMINDER_EMAIL_SUBJECT_KEY);
 129  0
         if (subject == null) {
 130  0
             subject = ACTION_LIST_REMINDER;
 131  
         }
 132  0
         return new EmailSubject(subject);
 133  
     }
 134  
 
 135  
     public EmailSubject getEmailSubject(String customSubject) {
 136  0
         String subject = ConfigContext.getCurrentContextConfig().getProperty(IMMEDIATE_REMINDER_EMAIL_SUBJECT_KEY);
 137  0
         if (subject == null) {
 138  0
             subject = ACTION_LIST_REMINDER;
 139  
         }
 140  0
         return new EmailSubject(subject + " " + customSubject);
 141  
     }
 142  
 
 143  
     protected EmailFrom getEmailFrom(DocumentType documentType) {
 144  0
         return new EmailFrom(getDocumentTypeEmailAddress(documentType));
 145  
     }
 146  
 
 147  
     protected void sendEmail(Person user, EmailSubject subject,
 148  
             EmailBody body) {
 149  0
         sendEmail(user, subject, body, null);
 150  0
     }
 151  
 
 152  
     protected void sendEmail(Person user, EmailSubject subject,
 153  
             EmailBody body, DocumentType documentType) {
 154  
         try {
 155  0
             if (isProduction()) {
 156  0
                 mailer.sendEmail(getEmailFrom(documentType),
 157  
                         new EmailTo(user.getEmailAddressUnmasked()),
 158  
                         subject,
 159  
                         body,
 160  
                         false);
 161  
             } else {
 162  0
                 mailer.sendEmail(
 163  
                         getEmailFrom(documentType),
 164  
                         new EmailTo(CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(
 165  
                                 KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ACTION_LIST_DETAIL_TYPE,
 166  
                                 KewApiConstants.ACTIONLIST_EMAIL_TEST_ADDRESS)),
 167  
                         subject,
 168  
                         body,
 169  
                         false);
 170  
             }
 171  0
         } catch (Exception e) {
 172  0
             LOG.error("Error sending Action List email.", e);
 173  0
         }
 174  0
     }
 175  
 
 176  
     /**
 177  
      * 
 178  
      * This method checks the given principal's preferences and returns true or
 179  
      * false based on the type of action requested and whether the user wishes
 180  
      * to receive immediate notifications for that type of request.
 181  
      * 
 182  
      * @return Whether the immediate reminder should be suppressed based on the
 183  
      * principal's preferences
 184  
      */
 185  
     protected boolean suppressImmediateReminder(ActionItem actionItem, String principalId) {
 186  0
         Preferences preferences = KewApiServiceLocator.getPreferencesService().getPreferences(principalId);
 187  0
         String actionRequestCd = actionItem.getActionRequestCd();
 188  0
         return
 189  
         (StringUtils.equals(actionRequestCd, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ) && 
 190  
                 StringUtils.equals(preferences.getNotifyAcknowledge(), KewApiConstants.PREFERENCES_YES_VAL)) ||
 191  
         (StringUtils.equals(actionRequestCd, KewApiConstants.ACTION_REQUEST_APPROVE_REQ) && 
 192  
                 StringUtils.equals(preferences.getNotifyApprove(), KewApiConstants.PREFERENCES_YES_VAL)) ||
 193  
         (StringUtils.equals(actionRequestCd, KewApiConstants.ACTION_REQUEST_COMPLETE_REQ) && 
 194  
                 StringUtils.equals(preferences.getNotifyComplete(), KewApiConstants.PREFERENCES_YES_VAL)) ||
 195  
         (StringUtils.equals(actionRequestCd, KewApiConstants.ACTION_REQUEST_FYI_REQ) && 
 196  
                 StringUtils.equals(preferences.getNotifyFYI(), KewApiConstants.PREFERENCES_YES_VAL));
 197  
     }
 198  
     
 199  
     public void sendImmediateReminder(ActionItem actionItem, Boolean skipOnApprovals) {
 200  0
         if (actionItem == null) {
 201  0
             LOG.warn("Request to send immediate reminder to recipient of a null action item... aborting.");
 202  0
             return;
 203  
         }
 204  
         
 205  0
         if (actionItem.getPrincipalId() == null) {
 206  0
             LOG.warn("Request to send immediate reminder to null recipient of an action item... aborting.");
 207  0
             return;
 208  
         }
 209  
 
 210  0
         if (skipOnApprovals != null && skipOnApprovals.booleanValue()
 211  
                 && actionItem.getActionRequestCd().equals(KewApiConstants.ACTION_REQUEST_APPROVE_REQ)) {
 212  0
             LOG.debug("As requested, skipping immediate reminder notification on action item approval for " + actionItem.getPrincipalId());
 213  0
             return;
 214  
         }
 215  
         
 216  0
         if(suppressImmediateReminder(actionItem, actionItem.getPrincipalId())) {
 217  0
             LOG.debug("Email suppressed due to the user's preferences");
 218  0
             return;
 219  
         }
 220  
 
 221  0
         boolean shouldSendActionListEmailNotification = sendActionListEmailNotification();
 222  0
         if (shouldSendActionListEmailNotification) {
 223  0
             LOG.debug("sending immediate reminder");
 224  
 
 225  0
             Person person = KimApiServiceLocator.getPersonService().getPerson(actionItem.getPrincipalId());
 226  
             
 227  0
             DocumentRouteHeaderValue document = KEWServiceLocator.getRouteHeaderService().getRouteHeader(
 228  
                     actionItem.getDocumentId());
 229  0
             StringBuffer emailBody = new StringBuffer(buildImmediateReminderBody(person, actionItem,
 230  
                     document.getDocumentType()));
 231  0
             StringBuffer emailSubject = new StringBuffer();
 232  
             try {
 233  0
                 CustomEmailAttribute customEmailAttribute = document.getCustomEmailAttribute();
 234  0
                 if (customEmailAttribute != null) {
 235  0
                     Document routeHeaderVO = DocumentRouteHeaderValue.to(document);
 236  0
                     ActionRequestValue actionRequest = KEWServiceLocator
 237  
                             .getActionRequestService().findByActionRequestId(actionItem.getActionRequestId());
 238  0
                     ActionRequest actionRequestVO = ActionRequestValue.to(actionRequest);
 239  0
                     customEmailAttribute.setRouteHeaderVO(routeHeaderVO);
 240  0
                     customEmailAttribute.setActionRequestVO(actionRequestVO);
 241  0
                     String customBody = customEmailAttribute
 242  
                             .getCustomEmailBody();
 243  0
                     if (!org.apache.commons.lang.StringUtils.isEmpty(customBody)) {
 244  0
                         emailBody.append(customBody);
 245  
                     }
 246  0
                     String customEmailSubject = customEmailAttribute
 247  
                             .getCustomEmailSubject();
 248  0
                     if (!org.apache.commons.lang.StringUtils.isEmpty(customEmailSubject)) {
 249  0
                         emailSubject.append(customEmailSubject);
 250  
                     }
 251  
                 }
 252  0
             } catch (Exception e) {
 253  0
                 LOG
 254  
                         .error(
 255  
                                 "Error when checking for custom email body and subject.",
 256  
                                 e);
 257  0
             }
 258  0
             LOG.debug("Sending email to " + person);
 259  0
             sendEmail(person, getEmailSubject(emailSubject.toString()),
 260  
                     new EmailBody(emailBody.toString()), document
 261  
                             .getDocumentType());
 262  
         }
 263  
 
 264  0
     }
 265  
 
 266  
     protected boolean isProduction() {
 267  0
         return ConfigContext.getCurrentContextConfig().isProductionEnvironment();
 268  
     }
 269  
 
 270  
     public void sendDailyReminder() {
 271  0
         if (sendActionListEmailNotification()) {
 272  0
             Collection<Person> users = getUsersWithEmailSetting(KewApiConstants.EMAIL_RMNDR_DAY_VAL);
 273  0
             for (Iterator<Person> userIter = users.iterator(); userIter.hasNext();) {
 274  0
                 Person user = userIter.next();
 275  
                 try {
 276  0
                     Collection actionItems = getActionListService().getActionList(user.getPrincipalId(), null);
 277  0
                     if (actionItems != null && actionItems.size() > 0) {
 278  0
                         sendPeriodicReminder(user, actionItems,
 279  
                                 KewApiConstants.EMAIL_RMNDR_DAY_VAL);
 280  
                     }
 281  0
                 } catch (Exception e) {
 282  0
                     LOG.error(
 283  
                             "Error sending daily action list reminder to user: "
 284  
                                     + user.getEmailAddressUnmasked(), e);
 285  0
                 }
 286  0
             }
 287  
         }
 288  0
         LOG.debug("Daily action list emails sent successful");
 289  0
     }
 290  
 
 291  
     public void sendWeeklyReminder() {
 292  0
         if (sendActionListEmailNotification()) {
 293  0
             List<Person> users = getUsersWithEmailSetting(KewApiConstants.EMAIL_RMNDR_WEEK_VAL);
 294  0
             for (Iterator<Person> userIter = users.iterator(); userIter.hasNext();) {
 295  0
                 Person user = userIter.next();
 296  
                 try {
 297  0
                     Collection actionItems = getActionListService()
 298  
                             .getActionList(user.getPrincipalId(), null);
 299  0
                     if (actionItems != null && actionItems.size() > 0) {
 300  0
                         sendPeriodicReminder(user, actionItems,
 301  
                                 KewApiConstants.EMAIL_RMNDR_WEEK_VAL);
 302  
                     }
 303  0
                 } catch (Exception e) {
 304  0
                     LOG.error(
 305  
                             "Error sending weekly action list reminder to user: "
 306  
                                     + user.getEmailAddressUnmasked(), e);
 307  0
                 }
 308  0
             }
 309  
         }
 310  0
         LOG.debug("Weekly action list emails sent successful");
 311  0
     }
 312  
 
 313  
     protected void sendPeriodicReminder(Person user, Collection<ActionItem> actionItems, String emailSetting) {
 314  0
         String emailBody = null;
 315  0
         actionItems = filterActionItemsToNotify(user.getPrincipalId(), actionItems);
 316  
         // if there are no action items after being filtered, there's no
 317  
         // reason to send the email
 318  0
         if (actionItems.isEmpty()) {
 319  0
             return;
 320  
         }
 321  0
         if (KewApiConstants.EMAIL_RMNDR_DAY_VAL.equals(emailSetting)) {
 322  0
             emailBody = buildDailyReminderBody(user, actionItems);
 323  0
         } else if (KewApiConstants.EMAIL_RMNDR_WEEK_VAL.equals(emailSetting)) {
 324  0
             emailBody = buildWeeklyReminderBody(user, actionItems);
 325  
         }
 326  0
         sendEmail(user, getEmailSubject(), new EmailBody(emailBody));
 327  0
     }
 328  
 
 329  
     /**
 330  
      * Returns a filtered Collection of {@link ActionItem}s which are filtered according to the
 331  
      * user's preferences. If they have opted not to recieve secondary or primary delegation emails
 332  
      * then they will not be included.
 333  
      */
 334  
     protected Collection filterActionItemsToNotify(String principalId, Collection actionItems) {
 335  0
         List filteredItems = new ArrayList();
 336  0
         Preferences preferences = KewApiServiceLocator.getPreferencesService().getPreferences(principalId);
 337  0
         for (Iterator iterator = actionItems.iterator(); iterator.hasNext();) {
 338  0
             ActionItem actionItem = (ActionItem) iterator.next();
 339  0
             if (!actionItem.getPrincipalId().equals(principalId)) {
 340  0
                 LOG.warn("Encountered an ActionItem with an incorrect workflow ID.  Was " + actionItem.getPrincipalId()
 341  
                         +
 342  
                         " but expected " + principalId);
 343  0
                 continue;
 344  
             }
 345  0
             boolean includeItem = true;
 346  0
             if (DelegationType.PRIMARY.equals(actionItem.getDelegationType())) {
 347  0
                 includeItem = KewApiConstants.PREFERENCES_YES_VAL.equals(preferences.getNotifyPrimaryDelegation());
 348  0
             } else if (DelegationType.SECONDARY.equals(actionItem.getDelegationType())) {
 349  0
                 includeItem = KewApiConstants.PREFERENCES_YES_VAL.equals(preferences.getNotifySecondaryDelegation());
 350  
             }
 351  0
             if (includeItem) {
 352  0
                 filteredItems.add(actionItem);
 353  
             }
 354  0
         }
 355  0
         return filteredItems;
 356  
     }
 357  
 
 358  
     protected List<Person> getUsersWithEmailSetting(String setting) {
 359  0
         List users = new ArrayList();
 360  0
         Collection userOptions = getUserOptionsService().findByOptionValue(
 361  
                 KewApiConstants.EMAIL_RMNDR_KEY, setting);
 362  0
         for (Iterator iter = userOptions.iterator(); iter.hasNext();) {
 363  0
             String workflowId = ((UserOptions) iter.next()).getWorkflowId();
 364  
             try {
 365  
 
 366  0
                 users.add(KimApiServiceLocator.getPersonService().getPerson(workflowId));
 367  0
             } catch (Exception e) {
 368  0
                 LOG.error("error retrieving workflow user with ID: "
 369  
                         + workflowId);
 370  0
             }
 371  0
         }
 372  0
         return users;
 373  
     }
 374  
 
 375  
     /**
 376  
      * 0 = actionItem.getDocumentId() 1 =
 377  
      * actionItem.getRouteHeader().getInitiatorUser().getDisplayName() 2 =
 378  
      * actionItem.getRouteHeader().getDocumentType().getName() 3 = actionItem.getDocTitle() 4 =
 379  
      * docHandlerUrl 5 = getActionListUrl() 6 = getPreferencesUrl() 7 = getHelpLink(documentType)
 380  
      */
 381  0
     private static final MessageFormat DEFAULT_IMMEDIATE_REMINDER = new MessageFormat(
 382  
             "Your Action List has an eDoc(electronic document) that needs your attention: \n\n"
 383  
                     +
 384  
                     "Document ID:\t{0,number,#}\n"
 385  
                     +
 386  
                     "Initiator:\t\t{1}\n"
 387  
                     +
 388  
                     "Type:\t\tAdd/Modify {2}\n"
 389  
                     +
 390  
                     "Title:\t\t{3}\n"
 391  
                     +
 392  
                     "\n\n"
 393  
                     +
 394  
                     "To respond to this eDoc: \n"
 395  
                     +
 396  
                     "\tGo to {4}\n\n"
 397  
                     +
 398  
                     "\tOr you may access the eDoc from your Action List: \n"
 399  
                     +
 400  
                     "\tGo to {5}, and then click on the numeric Document ID: {0,number,#} in the first column of the List. \n"
 401  
                     +
 402  
                     "\n\n\n" +
 403  
                     "To change how these email notifications are sent(daily, weekly or none): \n" +
 404  
                     "\tGo to {6}\n" +
 405  
                     "\n\n\n" +
 406  
                     "{7}\n\n\n"
 407  
             );
 408  
 
 409  
     /**
 410  
      * 0 = actionItem.getDocumentId() 1 =
 411  
      * actionItem.getRouteHeader().getInitiatorUser().getDisplayName() 2 =
 412  
      * actionItem.getRouteHeader().getDocumentType().getName() 3 = actionItem.getDocTitle() 4 =
 413  
      * getActionListUrl() 5 = getPreferencesUrl() 6 = getHelpLink(documentType)
 414  
      */
 415  0
     private static final MessageFormat DEFAULT_IMMEDIATE_REMINDER_NO_DOC_HANDLER = new MessageFormat(
 416  
             "Your Action List has an eDoc(electronic document) that needs your attention: \n\n" +
 417  
                     "Document ID:\t{0,number,#}\n" +
 418  
                     "Initiator:\t\t{1}\n" +
 419  
                     "Type:\t\tAdd/Modify {2}\n" +
 420  
                     "Title:\t\t{3}\n" +
 421  
                     "\n\n" +
 422  
                     "To respond to this eDoc you may use your Action List: \n" +
 423  
                     "\tGo to {4}, and then take actions related to Document ID: {0,number,#}. \n" +
 424  
                     "\n\n\n" +
 425  
                     "To change how these email notifications are sent(daily, weekly or none): \n" +
 426  
                     "\tGo to {5}\n" +
 427  
                     "\n\n\n" +
 428  
                     "{6}\n\n\n"
 429  
             );
 430  
 
 431  
     public String buildImmediateReminderBody(Person person,
 432  
             ActionItem actionItem, DocumentType documentType) {
 433  0
         String docHandlerUrl = documentType.getDocHandlerUrl();
 434  0
         if (StringUtils.isNotBlank(docHandlerUrl)) {
 435  0
             if (!docHandlerUrl.contains("?")) {
 436  0
                 docHandlerUrl += "?";
 437  
             } else {
 438  0
                 docHandlerUrl += "&";
 439  
             }
 440  0
             docHandlerUrl += KewApiConstants.DOCUMENT_ID_PARAMETER + "="
 441  
                     + actionItem.getDocumentId();
 442  0
             docHandlerUrl += "&" + KewApiConstants.COMMAND_PARAMETER + "="
 443  
                     + KewApiConstants.ACTIONLIST_COMMAND;
 444  
         }
 445  0
         StringBuffer sf = new StringBuffer();
 446  
 
 447  
         /*sf
 448  
                         .append("Your Action List has an eDoc(electronic document) that needs your attention: \n\n");
 449  
         sf.append("Document ID:\t" + actionItem.getDocumentId() + "\n");
 450  
         sf.append("Initiator:\t\t");
 451  
         try {
 452  
                 sf.append(actionItem.getRouteHeader().getInitiatorUser()
 453  
                                 .getDisplayName()
 454  
                                 + "\n");
 455  
         } catch (Exception e) {
 456  
                 LOG.error("Error retrieving initiator for action item "
 457  
                                 + actionItem.getDocumentId());
 458  
                 sf.append("\n");
 459  
         }
 460  
         sf.append("Type:\t\t" + "Add/Modify "
 461  
                         + actionItem.getRouteHeader().getDocumentType().getName()
 462  
                         + "\n");
 463  
         sf.append("Title:\t\t" + actionItem.getDocTitle() + "\n");
 464  
         sf.append("\n\n");
 465  
         sf.append("To respond to this eDoc: \n");
 466  
         sf.append("\tGo to " + docHandlerUrl + "\n\n");
 467  
         sf.append("\tOr you may access the eDoc from your Action List: \n");
 468  
         sf.append("\tGo to " + getActionListUrl()
 469  
                         + ", and then click on the numeric Document ID: "
 470  
                         + actionItem.getDocumentId()
 471  
                         + " in the first column of the List. \n");
 472  
         sf.append("\n\n\n");
 473  
         sf
 474  
                         .append("To change how these email notifications are sent(daily, weekly or none): \n");
 475  
         sf.append("\tGo to " + getPreferencesUrl() + "\n");
 476  
         sf.append("\n\n\n");
 477  
         sf.append(getHelpLink(documentType) + "\n\n\n");*/
 478  
 
 479  0
         MessageFormat messageFormat = null;
 480  0
         String stringMessageFormat = ConfigContext.getCurrentContextConfig().getProperty(
 481  
                 IMMEDIATE_REMINDER_EMAIL_MESSAGE_KEY);
 482  0
         LOG.debug("Immediate reminder email message from configuration (" + IMMEDIATE_REMINDER_EMAIL_MESSAGE_KEY
 483  
                 + "): " + stringMessageFormat);
 484  0
         if (stringMessageFormat == null) {
 485  0
             messageFormat = DEFAULT_IMMEDIATE_REMINDER;
 486  
         } else {
 487  0
             messageFormat = new MessageFormat(stringMessageFormat);
 488  
         }
 489  0
         String initiatorUser = (person == null ? "" : person.getName());
 490  
 
 491  0
         if (StringUtils.isNotBlank(docHandlerUrl)) {
 492  0
             Object[] args = {actionItem.getDocumentId(),
 493  
                     initiatorUser,
 494  
                     documentType.getName(),
 495  
                     actionItem.getDocTitle(),
 496  
                     docHandlerUrl,
 497  
                     getActionListUrl(),
 498  
                     getPreferencesUrl(),
 499  
                     getHelpLink(documentType)
 500  
             };
 501  
 
 502  0
             messageFormat.format(args, sf, new FieldPosition(0));
 503  
 
 504  0
             LOG.debug("default immediate reminder: " + DEFAULT_IMMEDIATE_REMINDER.format(args));
 505  0
         } else {
 506  0
             Object[] args = {actionItem.getDocumentId(),
 507  
                     initiatorUser,
 508  
                     documentType.getName(),
 509  
                     actionItem.getDocTitle(),
 510  
                     getActionListUrl(),
 511  
                     getPreferencesUrl(),
 512  
                     getHelpLink(documentType)
 513  
             };
 514  
 
 515  0
             messageFormat.format(args, sf, new FieldPosition(0));
 516  
 
 517  0
             LOG.debug("default immediate reminder: " + DEFAULT_IMMEDIATE_REMINDER_NO_DOC_HANDLER.format(args));
 518  
         }
 519  0
         LOG.debug("immediate reminder: " + sf);
 520  
 
 521  
         // for debugging purposes on the immediate reminder only
 522  0
         if (!isProduction()) {
 523  
             try {
 524  0
                 sf.append("Action Item sent to " + actionItem.getPrincipalId());
 525  0
                 if (actionItem.getDelegationType() != null) {
 526  0
                     sf.append(" for delegation type "
 527  
                             + actionItem.getDelegationType());
 528  
                 }
 529  0
             } catch (Exception e) {
 530  0
                 throw new RuntimeException(e);
 531  0
             }
 532  
         }
 533  
 
 534  0
         return sf.toString();
 535  
     }
 536  
 
 537  
     public String buildDailyReminderBody(Person user,
 538  
             Collection actionItems) {
 539  0
         StringBuffer sf = new StringBuffer();
 540  0
         sf.append(getDailyWeeklyMessageBody(actionItems));
 541  0
         sf
 542  
                 .append("To change how these email notifications are sent (immediately, weekly or none): \n");
 543  0
         sf.append("\tGo to " + getPreferencesUrl() + "\n");
 544  
         // sf.append("\tSend as soon as you get an eDoc\n\t" +
 545  
         // getPreferencesUrl() + "\n\n");
 546  
         // sf.append("\tSend weekly\n\t" + getPreferencesUrl() + "\n\n");
 547  
         // sf.append("\tDo not send\n\t" + getPreferencesUrl() + "\n");
 548  0
         sf.append("\n\n\n");
 549  0
         sf.append(getHelpLink() + "\n\n\n");
 550  0
         return sf.toString();
 551  
     }
 552  
 
 553  
     public String buildWeeklyReminderBody(Person user,
 554  
             Collection actionItems) {
 555  0
         StringBuffer sf = new StringBuffer();
 556  0
         sf.append(getDailyWeeklyMessageBody(actionItems));
 557  0
         sf
 558  
                 .append("To change how these email notifications are sent (immediately, daily or none): \n");
 559  0
         sf.append("\tGo to " + getPreferencesUrl() + "\n");
 560  
         // sf.append("\tSend as soon as you get an eDoc\n\t" +
 561  
         // getPreferencesUrl() + "\n\n");
 562  
         // sf.append("\tSend daily\n\t" + getPreferencesUrl() + "\n\n");
 563  
         // sf.append("\tDo not send\n\t" + getPreferencesUrl() + "\n");
 564  0
         sf.append("\n\n\n");
 565  0
         sf.append(getHelpLink() + "\n\n\n");
 566  0
         return sf.toString();
 567  
     }
 568  
 
 569  
     String getDailyWeeklyMessageBody(Collection actionItems) {
 570  0
         StringBuffer sf = new StringBuffer();
 571  0
         HashMap docTypes = getActionListItemsStat(actionItems);
 572  
 
 573  0
         sf
 574  
                 .append("Your Action List has "
 575  
                         + actionItems.size()
 576  
                         + " eDocs(electronic documents) that need your attention: \n\n");
 577  0
         Iterator iter = docTypes.keySet().iterator();
 578  0
         while (iter.hasNext()) {
 579  0
             String docTypeName = (String) iter.next();
 580  0
             sf.append("\t" + ((Integer) docTypes.get(docTypeName)).toString()
 581  
                     + "\t" + docTypeName + "\n");
 582  0
         }
 583  0
         sf.append("\n\n");
 584  0
         sf.append("To respond to each of these eDocs: \n");
 585  0
         sf
 586  
                 .append("\tGo to "
 587  
                         + getActionListUrl()
 588  
                         + ", and then click on its numeric Document ID in the first column of the List.\n");
 589  0
         sf.append("\n\n\n");
 590  0
         return sf.toString();
 591  
     }
 592  
 
 593  
     private HashMap<String, Integer> getActionListItemsStat(Collection<ActionItem> actionItems) {
 594  0
         HashMap<String, Integer> docTypes = new LinkedHashMap<String, Integer>();
 595  0
         Map<String, DocumentRouteHeaderValue> routeHeaders = KEWServiceLocator.getRouteHeaderService()
 596  
                 .getRouteHeadersForActionItems(actionItems);
 597  0
         Iterator<ActionItem> iter = actionItems.iterator();
 598  
 
 599  0
         while (iter.hasNext()) {
 600  0
             String docTypeName = routeHeaders.get(iter.next().getDocumentId()).getDocumentType().getName();
 601  0
             if (docTypes.containsKey(docTypeName)) {
 602  0
                 docTypes.put(docTypeName, new Integer(docTypes.get(docTypeName).intValue() + 1));
 603  
             } else {
 604  0
                 docTypes.put(docTypeName, new Integer(1));
 605  
             }
 606  0
         }
 607  0
         return docTypes;
 608  
     }
 609  
 
 610  
     protected boolean sendActionListEmailNotification() {
 611  0
         if (LOG.isDebugEnabled())
 612  0
             LOG.debug("actionlistsendconstant: "
 613  
                     + CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(
 614  
                             KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ACTION_LIST_DETAIL_TYPE,
 615  
                             KewApiConstants.ACTION_LIST_SEND_EMAIL_NOTIFICATION_IND));
 616  
 
 617  0
         return KewApiConstants.ACTION_LIST_SEND_EMAIL_NOTIFICATION_VALUE
 618  
                 .equals(CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(
 619  
                         KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ACTION_LIST_DETAIL_TYPE,
 620  
                         KewApiConstants.ACTION_LIST_SEND_EMAIL_NOTIFICATION_IND));
 621  
     }
 622  
 
 623  
     public void scheduleBatchEmailReminders() throws Exception {
 624  0
         String emailBatchGroup = "Email Batch";
 625  0
         String dailyCron = ConfigContext.getCurrentContextConfig()
 626  
                 .getProperty(KewApiConstants.DAILY_EMAIL_CRON_EXPRESSION);
 627  0
         if (!StringUtils.isBlank(dailyCron)) {
 628  0
             LOG.info("Scheduling Daily Email batch with cron expression: " + dailyCron);
 629  0
             CronTrigger dailyTrigger = new CronTrigger(DAILY_TRIGGER_NAME, emailBatchGroup, dailyCron);
 630  0
             JobDetail dailyJobDetail = new JobDetail(DAILY_JOB_NAME, emailBatchGroup, DailyEmailJob.class);
 631  0
             dailyTrigger.setJobName(dailyJobDetail.getName());
 632  0
             dailyTrigger.setJobGroup(dailyJobDetail.getGroup());
 633  0
             addJobToScheduler(dailyJobDetail);
 634  0
             addTriggerToScheduler(dailyTrigger);
 635  0
         } else {
 636  0
             LOG.warn("No " + KewApiConstants.DAILY_EMAIL_CRON_EXPRESSION
 637  
                     + " parameter was configured.  Daily Email batch was not scheduled!");
 638  
         }
 639  
 
 640  0
         String weeklyCron = ConfigContext.getCurrentContextConfig().getProperty(
 641  
                 KewApiConstants.WEEKLY_EMAIL_CRON_EXPRESSION);
 642  0
         if (!StringUtils.isBlank(weeklyCron)) {
 643  0
             LOG.info("Scheduling Weekly Email batch with cron expression: " + weeklyCron);
 644  0
             CronTrigger weeklyTrigger = new CronTrigger(WEEKLY_TRIGGER_NAME, emailBatchGroup, weeklyCron);
 645  0
             JobDetail weeklyJobDetail = new JobDetail(WEEKLY_JOB_NAME, emailBatchGroup, WeeklyEmailJob.class);
 646  0
             weeklyTrigger.setJobName(weeklyJobDetail.getName());
 647  0
             weeklyTrigger.setJobGroup(weeklyJobDetail.getGroup());
 648  0
             addJobToScheduler(weeklyJobDetail);
 649  0
             addTriggerToScheduler(weeklyTrigger);
 650  0
         } else {
 651  0
             LOG.warn("No " + KewApiConstants.WEEKLY_EMAIL_CRON_EXPRESSION
 652  
                     + " parameter was configured.  Weekly Email batch was not scheduled!");
 653  
         }
 654  0
     }
 655  
 
 656  
     private void addJobToScheduler(JobDetail jobDetail) throws SchedulerException {
 657  0
         getScheduler().addJob(jobDetail, true);
 658  0
     }
 659  
 
 660  
     private void addTriggerToScheduler(Trigger trigger) throws SchedulerException {
 661  0
         boolean triggerExists = (getScheduler().getTrigger(trigger.getName(), trigger.getGroup()) != null);
 662  0
         if (!triggerExists) {
 663  
             try {
 664  0
                 getScheduler().scheduleJob(trigger);
 665  0
             } catch (ObjectAlreadyExistsException ex) {
 666  0
                 getScheduler().rescheduleJob(trigger.getName(), trigger.getGroup(), trigger);
 667  0
             }
 668  
         } else {
 669  0
             getScheduler().rescheduleJob(trigger.getName(), trigger.getGroup(), trigger);
 670  
         }
 671  0
     }
 672  
 
 673  
     private Scheduler getScheduler() {
 674  0
         return KSBServiceLocator.getScheduler();
 675  
     }
 676  
 
 677  
     private UserOptionsService getUserOptionsService() {
 678  0
         return (UserOptionsService) KEWServiceLocator
 679  
                 .getUserOptionsService();
 680  
     }
 681  
 
 682  
     protected ActionListService getActionListService() {
 683  0
         return (ActionListService) KEWServiceLocator.getActionListService();
 684  
     }
 685  
 
 686  
     public String getDeploymentEnvironment() {
 687  0
         return deploymentEnvironment;
 688  
     }
 689  
 
 690  
     public void setDeploymentEnvironment(String deploymentEnvironment) {
 691  0
         this.deploymentEnvironment = deploymentEnvironment;
 692  0
     }
 693  
 
 694  
     protected String getActionListUrl() {
 695  0
         return ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.WORKFLOW_URL_KEY)
 696  
                 + "/" + "ActionList.do";
 697  
     }
 698  
 
 699  
     protected String getPreferencesUrl() {
 700  0
         return ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.WORKFLOW_URL_KEY)
 701  
                 + "/" + "Preferences.do";
 702  
     }
 703  
 }