| 1 |  |   | 
  | 2 |  |   | 
  | 3 |  |   | 
  | 4 |  |   | 
  | 5 |  |   | 
  | 6 |  |   | 
  | 7 |  |   | 
  | 8 |  |   | 
  | 9 |  |   | 
  | 10 |  |   | 
  | 11 |  |   | 
  | 12 |  |   | 
  | 13 |  |   | 
  | 14 |  |   | 
  | 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 |  |   | 
  | 67 |  |   | 
  | 68 |  |   | 
  | 69 |  |   | 
  | 70 |  |   | 
  | 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 |  |           | 
  | 108 | 0 |          String fromAddress = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString( | 
  | 109 |  |                  KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.MAILER_DETAIL_TYPE, | 
  | 110 |  |                  KewApiConstants.EMAIL_REMINDER_FROM_ADDRESS); | 
  | 111 |  |           | 
  | 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 |  |   | 
  | 179 |  |   | 
  | 180 |  |   | 
  | 181 |  |   | 
  | 182 |  |   | 
  | 183 |  |   | 
  | 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 |  |           | 
  | 317 |  |           | 
  | 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 |  |   | 
  | 331 |  |   | 
  | 332 |  |   | 
  | 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 |  |   | 
  | 377 |  |   | 
  | 378 |  |   | 
  | 379 |  |   | 
  | 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 |  |   | 
  | 411 |  |   | 
  | 412 |  |   | 
  | 413 |  |   | 
  | 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 |  |           | 
  | 448 |  |   | 
  | 449 |  |   | 
  | 450 |  |   | 
  | 451 |  |   | 
  | 452 |  |   | 
  | 453 |  |   | 
  | 454 |  |   | 
  | 455 |  |   | 
  | 456 |  |   | 
  | 457 |  |   | 
  | 458 |  |   | 
  | 459 |  |   | 
  | 460 |  |   | 
  | 461 |  |   | 
  | 462 |  |   | 
  | 463 |  |   | 
  | 464 |  |   | 
  | 465 |  |   | 
  | 466 |  |   | 
  | 467 |  |   | 
  | 468 |  |   | 
  | 469 |  |   | 
  | 470 |  |   | 
  | 471 |  |   | 
  | 472 |  |   | 
  | 473 |  |   | 
  | 474 |  |   | 
  | 475 |  |   | 
  | 476 |  |   | 
  | 477 |  |   | 
  | 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 |  |           | 
  | 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 |  |           | 
  | 545 |  |           | 
  | 546 |  |           | 
  | 547 |  |           | 
  | 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 |  |           | 
  | 561 |  |           | 
  | 562 |  |           | 
  | 563 |  |           | 
  | 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 |  |  } |