001 /**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.ken.web.spring;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.apache.log4j.Logger;
020 import org.kuali.rice.core.api.criteria.QueryByCriteria;
021 import org.kuali.rice.core.api.exception.RiceIllegalArgumentException;
022 import org.kuali.rice.core.framework.persistence.dao.GenericDao;
023 import org.kuali.rice.coreservice.api.namespace.Namespace;
024 import org.kuali.rice.coreservice.api.namespace.NamespaceService;
025 import org.kuali.rice.ken.bo.NotificationBo;
026 import org.kuali.rice.ken.bo.NotificationChannelBo;
027 import org.kuali.rice.ken.bo.NotificationChannelReviewerBo;
028 import org.kuali.rice.ken.bo.NotificationPriorityBo;
029 import org.kuali.rice.ken.bo.NotificationProducerBo;
030 import org.kuali.rice.ken.bo.NotificationRecipientBo;
031 import org.kuali.rice.ken.bo.NotificationSenderBo;
032 import org.kuali.rice.ken.document.kew.NotificationWorkflowDocument;
033 import org.kuali.rice.ken.exception.ErrorList;
034 import org.kuali.rice.ken.service.NotificationChannelService;
035 import org.kuali.rice.ken.service.NotificationMessageContentService;
036 import org.kuali.rice.ken.service.NotificationRecipientService;
037 import org.kuali.rice.ken.service.NotificationService;
038 import org.kuali.rice.ken.service.NotificationWorkflowDocumentService;
039 import org.kuali.rice.ken.util.NotificationConstants;
040 import org.kuali.rice.ken.util.Util;
041 import org.kuali.rice.kew.api.WorkflowDocument;
042 import org.kuali.rice.kew.rule.GenericAttributeContent;
043 import org.kuali.rice.kim.api.KimConstants;
044 import org.kuali.rice.kim.api.group.Group;
045 import org.kuali.rice.kim.api.group.GroupService;
046 import org.kuali.rice.kim.api.identity.IdentityService;
047 import org.kuali.rice.kim.api.identity.principal.Principal;
048 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
049 import org.kuali.rice.coreservice.api.CoreServiceApiServiceLocator;
050 import org.kuali.rice.krad.data.DataObjectService;
051 import org.springframework.web.servlet.ModelAndView;
052 import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
053
054 import javax.servlet.ServletException;
055 import javax.servlet.http.HttpServletRequest;
056 import java.io.IOException;
057 import java.sql.Timestamp;
058 import java.text.ParseException;
059 import java.util.ArrayList;
060 import java.util.Date;
061 import java.util.HashMap;
062 import java.util.List;
063 import java.util.Map;
064
065 /**
066 * Base class for KEN controllers for sending notifications
067 *
068 * @author Kuali Rice Team (rice.collab@kuali.org)
069 *
070 */
071 public class BaseSendNotificationController extends MultiActionController {
072 private static final Logger LOG = Logger.getLogger(BaseSendNotificationController.class);
073
074 private static final String USER_RECIPS_PARAM = "userRecipients";
075 private static final String WORKGROUP_RECIPS_PARAM = "workgroupRecipients";
076 private static final String WORKGROUP_NAMESPACE_CODES_PARAM = "workgroupNamespaceCodes";
077 private static final String SPLIT_REGEX = "(%2C|,)";
078
079 private static final String NONE_CHANNEL = "___NONE___";
080 private static final long REASONABLE_IMMEDIATE_TIME_THRESHOLD = 1000 * 60 * 5; // <= 5 minutes is "immediate"
081
082 private static IdentityService identityService;
083 private static GroupService groupService;
084 private static NamespaceService namespaceService;
085
086 protected NotificationService notificationService;
087 protected NotificationWorkflowDocumentService notificationWorkflowDocService;
088 protected NotificationChannelService notificationChannelService;
089 protected NotificationRecipientService notificationRecipientService;
090 protected NotificationMessageContentService notificationMessageContentService;
091 protected DataObjectService dataObjectService;
092
093 protected static IdentityService getIdentityService() {
094 if ( identityService == null ) {
095 identityService = KimApiServiceLocator.getIdentityService();
096 }
097 return identityService;
098 }
099
100 protected static GroupService getGroupService() {
101 if ( groupService == null ) {
102 groupService = KimApiServiceLocator.getGroupService();
103 }
104 return groupService;
105 }
106
107 protected static NamespaceService getNamespaceService() {
108 if ( namespaceService == null ) {
109 namespaceService = CoreServiceApiServiceLocator.getNamespaceService();
110 }
111 return namespaceService;
112 }
113
114 /**
115 * Sets the {@link NotificationService}.
116 *
117 * @param notificationService the service to set
118 */
119 public void setNotificationService(NotificationService notificationService) {
120 this.notificationService = notificationService;
121 }
122
123 /**
124 * Sets the {@link NotificationWorkflowDocumentService}.
125 *
126 * @param notificationWorkflowDocService the service to set
127 */
128 public void setNotificationWorkflowDocumentService(NotificationWorkflowDocumentService notificationWorkflowDocService) {
129 this.notificationWorkflowDocService = notificationWorkflowDocService;
130 }
131
132 /**
133 * Sets the {@link NotificationChannelService}.
134 *
135 * @param notificationChannelService the service to set
136 */
137 public void setNotificationChannelService(NotificationChannelService notificationChannelService) {
138 this.notificationChannelService = notificationChannelService;
139 }
140
141 /**
142 * Sets the {@link NotificationRecipientService}.
143 *
144 * @param notificationRecipientService the service to set
145 */
146 public void setNotificationRecipientService(NotificationRecipientService notificationRecipientService) {
147 this.notificationRecipientService = notificationRecipientService;
148 }
149
150 /**
151 * Sets the {@link NotificationMessageContentService}.
152 *
153 * @param notificationMessageContentService the service to set
154 */
155 public void setNotificationMessageContentService(NotificationMessageContentService notificationMessageContentService) {
156 this.notificationMessageContentService = notificationMessageContentService;
157 }
158
159 /**
160 * Sets the businessObjectDao attribute value.
161 * @param dataObjectService the service to set
162 */
163 public void setDataObjectService(DataObjectService dataObjectService) {
164 this.dataObjectService = dataObjectService;
165 }
166
167
168 protected String getParameter(HttpServletRequest request, String parameterName, Map<String, Object> model, ErrorList errors, String errorMessage) {
169 String parameter = request.getParameter(parameterName);
170
171 if (StringUtils.isNotEmpty(parameter)) {
172 model.put(parameterName, parameter);
173 } else {
174 errors.addError(errorMessage);
175 }
176
177 return parameter;
178 }
179
180 protected String getParameter(HttpServletRequest request, String parameterName, Map<String, Object> model, ErrorList errors, String errorMessage, String defaultValue) {
181 String parameter = StringUtils.defaultIfBlank(request.getParameter(parameterName), defaultValue);
182
183 if (StringUtils.isNotEmpty(parameter)) {
184 model.put(parameterName, parameter);
185 } else {
186 errors.addError(errorMessage);
187 }
188
189 return parameter;
190 }
191
192 protected String[] getParameterList(HttpServletRequest request, String parameterName, Map<String, Object> model, ErrorList errors, String errorMessage) {
193 String parameter = request.getParameter(parameterName);
194 String[] senders = null;
195
196 if (StringUtils.isNotEmpty(parameter)) {
197 senders = StringUtils.split(parameter, ",");
198 model.put(parameterName, parameter);
199 } else {
200 errors.addError(errorMessage);
201 }
202
203 return senders;
204 }
205
206 protected Date getDate(String parameter, ErrorList errors, String errorMessage) {
207 Date date = null;
208
209 try {
210 date = Util.parseUIDateTime(parameter);
211 } catch (ParseException pe) {
212 errors.addError(errorMessage);
213 }
214
215 return date;
216 }
217
218 protected String[] parseUserRecipients(HttpServletRequest request) {
219 return parseCommaSeparatedValues(request, USER_RECIPS_PARAM);
220 }
221
222 protected String[] parseWorkgroupRecipients(HttpServletRequest request) {
223 return parseCommaSeparatedValues(request, WORKGROUP_RECIPS_PARAM);
224 }
225
226 protected String[] parseWorkgroupNamespaceCodes(HttpServletRequest request) {
227 return parseCommaSeparatedValues(request, WORKGROUP_NAMESPACE_CODES_PARAM);
228 }
229
230 protected String[] parseCommaSeparatedValues(HttpServletRequest request, String param) {
231 String vals = request.getParameter(param);
232 if (vals != null) {
233 String[] split = vals.split(SPLIT_REGEX);
234 List<String> strs = new ArrayList<String>();
235 for (String component: split) {
236 if (StringUtils.isNotBlank(component)) {
237 strs.add(component.trim());
238 }
239 }
240 return strs.toArray(new String[strs.size()]);
241 } else {
242 return new String[0];
243 }
244 }
245
246 protected boolean isUserRecipientValid(String user, ErrorList errors) {
247 boolean valid = true;
248 Principal principal = getIdentityService().getPrincipalByPrincipalName(user);
249 if (principal == null) {
250 valid = false;
251 errors.addError("'" + user + "' is not a valid principal name");
252 }
253
254 return valid;
255 }
256
257 protected boolean isWorkgroupRecipientValid(String groupName, String namespaceCode, ErrorList errors) {
258 Namespace nSpace = getNamespaceService().getNamespace(namespaceCode);
259 if (nSpace == null) {
260 errors.addError((new StringBuilder()).append('\'').append(namespaceCode).append("' is not a valid namespace code").toString());
261 return false;
262 } else {
263 Group i = getGroupService().getGroupByNamespaceCodeAndName(namespaceCode, groupName);
264 if (i == null) {
265 errors.addError((new StringBuilder()).append('\'').append(groupName).append(
266 "' is not a valid group name for namespace code '").append(namespaceCode).append('\'').toString());
267 return false;
268 } else {
269 return true;
270 }
271 }
272 }
273 protected String getPrincipalIdFromIdOrName(String principalIdOrName) {
274 Principal principal = KimApiServiceLocator.getIdentityService().getPrincipal(principalIdOrName);
275 if (principal == null) {
276 principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalIdOrName);
277 }
278 if (principal == null) {
279 throw new RiceIllegalArgumentException("Could not locate a principal as initiator with the given remoteUser of " + principalIdOrName);
280 }
281 return principal.getPrincipalId();
282 }
283
284 /**
285 * Submits the actual event notification message.
286 *
287 * @param request the servlet request
288 * @param routeMessage the message to attach to the route action
289 * @param viewName the name of the view to forward to after completion
290 *
291 * @return the next view to show
292 * @throws javax.servlet.ServletException
293 * @throws java.io.IOException
294 */
295 protected ModelAndView submitNotificationMessage(HttpServletRequest request, String routeMessage, String viewName)
296 throws ServletException, IOException {
297 LOG.debug("remoteUser: " + request.getRemoteUser());
298
299 // obtain a workflow user object first
300 //WorkflowIdDTO initiator = new WorkflowIdDTO(request.getRemoteUser());
301 String initiatorId = getPrincipalIdFromIdOrName( request.getRemoteUser());
302 LOG.debug("initiatorId: " + initiatorId);
303
304 // now construct the workflow document, which will interact with workflow
305 Map<String, Object> model = new HashMap<String, Object>();
306
307 try {
308 WorkflowDocument document = createNotificationWorkflowDocument(request, initiatorId, model);
309
310 document.route(routeMessage + initiatorId);
311
312 // This ain't pretty, but it gets the job done for now.
313 ErrorList el = new ErrorList();
314 el.addError("Notification(s) sent.");
315 model.put("errors", el);
316 } catch (ErrorList el) {
317 // route back to the send form again
318 Map<String, Object> model2 = setupModelForSendNotification(request);
319 model.putAll(model2);
320 model.put("errors", el);
321 } catch (Exception e) {
322 throw new RuntimeException(e);
323 }
324
325 return new ModelAndView(viewName, model);
326 }
327
328 /**
329 * Creates a notification {@link WorkflowDocument}.
330 *
331 * @param request the servlet request
332 * @param initiatorId the user sending the notification
333 * @param model the Spring MVC model
334 *
335 * @return a {@link WorkflowDocument} for the notification
336 * @throws java.lang.IllegalArgumentException
337 * @throws org.kuali.rice.ken.exception.ErrorList
338 */
339 protected WorkflowDocument createNotificationWorkflowDocument(HttpServletRequest request, String initiatorId,
340 Map<String, Object> model) throws IllegalArgumentException, ErrorList {
341 WorkflowDocument document = NotificationWorkflowDocument.createNotificationDocument(initiatorId,
342 NotificationConstants.KEW_CONSTANTS.SEND_NOTIFICATION_REQ_DOC_TYPE);
343
344 //parse out the application content into a Notification BO
345 NotificationBo notification = populateNotificationInstance(request, model);
346
347 // now get that content in an understandable XML format and pass into document
348 String notificationAsXml = notificationMessageContentService.generateNotificationMessage(notification);
349
350 Map<String, String> attrFields = new HashMap<String,String>();
351 List<NotificationChannelReviewerBo> reviewers = notification.getChannel().getReviewers();
352 int ui = 0;
353 int gi = 0;
354 for (NotificationChannelReviewerBo reviewer: reviewers) {
355 String prefix;
356 int index;
357 if (KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode().equals(reviewer.getReviewerType())) {
358 prefix = "user";
359 index = ui;
360 ui++;
361 } else if (KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode().equals(reviewer.getReviewerType())) {
362 prefix = "group";
363 index = gi;
364 gi++;
365 } else {
366 LOG.error("Invalid type for reviewer " + reviewer.getReviewerId() + ": " + reviewer.getReviewerType());
367 continue;
368 }
369 attrFields.put(prefix + index, reviewer.getReviewerId());
370 }
371 GenericAttributeContent gac = new GenericAttributeContent("channelReviewers");
372 document.setApplicationContent(notificationAsXml);
373 document.setAttributeContent("<attributeContent>" + gac.generateContent(attrFields) + "</attributeContent>");
374
375 document.setTitle(notification.getTitle());
376
377 return document;
378 }
379
380 /**
381 * Creates a new {@link NotificationBo} instance.
382 *
383 * @param request the servlet request
384 * @param model the Spring MVC model
385 *
386 * @return a new notification
387 * @throws java.lang.IllegalArgumentException
388 * @throws org.kuali.rice.ken.exception.ErrorList
389 */
390 protected NotificationBo populateNotificationInstance(HttpServletRequest request, Map<String, Object> model)
391 throws IllegalArgumentException, ErrorList {
392 return createNotification(request, model, new ErrorList());
393 }
394
395 /**
396 * Provides an overridable method in which to customize a created {@link NotificationBo} instance.
397 *
398 * @param request the servlet request
399 * @param model the Spring MVC model
400 * @param errors the error list
401 *
402 * @return a new notification
403 * @throws ErrorList
404 */
405 protected NotificationBo createNotification(HttpServletRequest request, Map<String, Object> model, ErrorList errors)
406 throws ErrorList {
407 String channelName = getChannelName(request, model, errors);
408 String priorityName = getParameter(request, "priorityName", model, errors, "You must choose a priority.");
409 String[] senders = getParameterList(request, "senderNames", model, errors, "You must enter at least one sender.");
410 String deliveryType = getDeliveryType(request, model, errors);
411
412 Date originalDate = getDate(request.getParameter("originalDateTime"), errors, "Original date is invalid.");
413
414 String sendDateTime = StringUtils.defaultIfBlank(request.getParameter("sendDateTime"), Util.getCurrentDateTime());
415 Date sendDate = getDate(sendDateTime, errors, "You specified an invalid Send Date/Time. Please use the calendar picker.");
416 if (sendDate != null && sendDate.before(originalDate)) {
417 errors.addError("Send Date/Time cannot be in the past.");
418 }
419 model.put("sendDateTime", sendDateTime);
420
421 String autoRemoveDateTime = request.getParameter("autoRemoveDateTime");
422 Date removeDate = getDate(autoRemoveDateTime, errors, "You specified an invalid Auto-Remove Date/Time. Please use the calendar picker.");
423 if (removeDate != null) {
424 if (removeDate.before(originalDate)) {
425 errors.addError("Auto-Remove Date/Time cannot be in the past.");
426 } else if (sendDate != null && removeDate.before(sendDate)) {
427 errors.addError("Auto-Remove Date/Time cannot be before the Send Date/Time.");
428 }
429 }
430 model.put("autoRemoveDateTime", autoRemoveDateTime);
431
432 // user recipient names
433 String[] userRecipients = parseUserRecipients(request);
434
435 // workgroup recipient names
436 String[] workgroupRecipients = parseWorkgroupRecipients(request);
437
438 // workgroup namespace codes
439 String[] workgroupNamespaceCodes = parseWorkgroupNamespaceCodes(request);
440
441 String title = getParameter(request, "title", model, errors, "You must fill in a title.");
442
443 // check to see if there were any errors
444 if (!errors.getErrors().isEmpty()) {
445 throw errors;
446 }
447
448 return createNotification(title, deliveryType, sendDate, removeDate, channelName, priorityName,
449 senders, userRecipients, workgroupRecipients, workgroupNamespaceCodes, errors);
450 }
451
452 private NotificationBo createNotification(String title, String deliveryType, Date sendDate, Date removeDate,
453 String channelName, String priorityName, String[] senders, String[] userRecipients,
454 String[] workgroupRecipients, String[] workgroupNamespaceCodes, ErrorList errors) throws ErrorList {
455 NotificationBo notification = new NotificationBo();
456 notification.setTitle(title);
457 notification.setDeliveryType(deliveryType);
458 notification.setSendDateTimeValue(new Timestamp(sendDate.getTime()));
459 notification.setAutoRemoveDateTimeValue(new Timestamp(removeDate.getTime()));
460
461 NotificationChannelBo channel = Util.retrieveFieldReference("channel", "name", channelName,
462 NotificationChannelBo.class, dataObjectService);
463 notification.setChannel(channel);
464
465 NotificationPriorityBo priority = Util.retrieveFieldReference("priority", "name", priorityName,
466 NotificationPriorityBo.class, dataObjectService);
467 notification.setPriority(priority);
468
469 NotificationProducerBo producer = Util.retrieveFieldReference("producer", "name",
470 NotificationConstants.KEW_CONSTANTS.NOTIFICATION_SYSTEM_USER_NAME, NotificationProducerBo.class,
471 dataObjectService);
472 notification.setProducer(producer);
473
474 for (String senderName : senders) {
475 if (StringUtils.isEmpty(senderName)) {
476 errors.addError("A sender's name cannot be blank.");
477 } else {
478 NotificationSenderBo ns = new NotificationSenderBo();
479 ns.setSenderName(senderName.trim());
480 notification.addSender(ns);
481 }
482 }
483
484 if (userRecipients != null && userRecipients.length > 0) {
485 for (String userRecipientId : userRecipients) {
486 if (isUserRecipientValid(userRecipientId, errors)) {
487 NotificationRecipientBo recipient = new NotificationRecipientBo();
488 recipient.setRecipientType(KimConstants.KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode());
489 recipient.setRecipientId(userRecipientId);
490 notification.addRecipient(recipient);
491 }
492 }
493 }
494
495 if (workgroupRecipients != null && workgroupRecipients.length > 0) {
496 if (workgroupNamespaceCodes != null && workgroupNamespaceCodes.length > 0) {
497 if (workgroupNamespaceCodes.length == workgroupRecipients.length) {
498 for (int i = 0; i < workgroupRecipients.length; i++) {
499 if (isWorkgroupRecipientValid(workgroupRecipients[i], workgroupNamespaceCodes[i], errors)) {
500 NotificationRecipientBo recipient = new NotificationRecipientBo();
501 recipient.setRecipientType(KimConstants.KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode());
502 recipient.setRecipientId(
503 getGroupService().getGroupByNamespaceCodeAndName(workgroupNamespaceCodes[i],
504 workgroupRecipients[i]).getId());
505 notification.addRecipient(recipient);
506 }
507 }
508 } else {
509 errors.addError("The number of groups must match the number of namespace codes");
510 }
511 } else {
512 errors.addError("You must specify a namespace code for every group name");
513 }
514 } else if (workgroupNamespaceCodes != null && workgroupNamespaceCodes.length > 0) {
515 errors.addError("You must specify a group name for every namespace code");
516 }
517
518 if (!recipientsExist(userRecipients, workgroupRecipients) && !hasPotentialRecipients(notification)) {
519 errors.addError("You must specify at least one user or group recipient.");
520 }
521
522 notification.setContent(NotificationConstants.XML_MESSAGE_CONSTANTS.CONTENT_SIMPLE_OPEN
523 + NotificationConstants.XML_MESSAGE_CONSTANTS.MESSAGE_OPEN
524 + NotificationConstants.XML_MESSAGE_CONSTANTS.MESSAGE_CLOSE
525 + NotificationConstants.XML_MESSAGE_CONSTANTS.CONTENT_CLOSE);
526
527 return notification;
528 }
529
530 private String getChannelName(HttpServletRequest request, Map<String, Object> model, ErrorList errors) {
531 String channelName = request.getParameter("channelName");
532
533 if (StringUtils.isEmpty(channelName) || StringUtils.equals(channelName, NONE_CHANNEL)) {
534 errors.addError("You must choose a channel.");
535 } else {
536 model.put("channelName", channelName);
537 }
538
539 return channelName;
540 }
541
542 private String getDeliveryType(HttpServletRequest request, Map<String, Object> model, ErrorList errors) {
543 String deliveryType = request.getParameter("deliveryType");
544
545 if (StringUtils.isNotEmpty(deliveryType)) {
546 if (deliveryType.equalsIgnoreCase(NotificationConstants.DELIVERY_TYPES.FYI)) {
547 deliveryType = NotificationConstants.DELIVERY_TYPES.FYI;
548 } else {
549 deliveryType = NotificationConstants.DELIVERY_TYPES.ACK;
550 }
551 model.put("deliveryType", deliveryType);
552 } else {
553 errors.addError("You must choose a delivery type.");
554 }
555
556 return deliveryType;
557 }
558
559 /**
560 * Prepares the model used for sending the notification.
561 *
562 * @param request the servlet request
563 *
564 * @return the Spring MVC model
565 */
566 protected Map<String, Object> setupModelForSendNotification(HttpServletRequest request) {
567 Map<String, Object> model = new HashMap<String, Object>();
568
569 model.put("defaultSender", request.getRemoteUser());
570 model.put("channels", notificationChannelService.getAllNotificationChannels());
571 model.put("priorities", dataObjectService.findMatching(NotificationPriorityBo.class,
572 QueryByCriteria.Builder.create().build()).getResults());
573
574 // set sendDateTime to current datetime if not provided
575 String sendDateTime = request.getParameter("sendDateTime");
576 String currentDateTime = Util.getCurrentDateTime();
577 if (StringUtils.isEmpty(sendDateTime)) {
578 sendDateTime = currentDateTime;
579 }
580 model.put("sendDateTime", sendDateTime);
581
582 // retain the original date time or set to current if it was not in the request
583 if (request.getParameter("originalDateTime") == null) {
584 model.put("originalDateTime", currentDateTime);
585 } else {
586 model.put("originalDateTime", request.getParameter("originalDateTime"));
587 }
588
589 model.put("userRecipients", request.getParameter("userRecipients"));
590 model.put("workgroupRecipients", request.getParameter("workgroupRecipients"));
591 model.put("workgroupNamespaceCodes", request.getParameter("workgroupNamespaceCodes"));
592
593 return model;
594 }
595
596 /**
597 * Returns whether the specified time is considered "in the future", based on some reasonable threshold.
598 *
599 * @param time the time to test
600 *
601 * @return true if the specified time is considered "in the future", false otherwise
602 */
603 private boolean timeIsInTheFuture(long time) {
604 boolean future = (time - System.currentTimeMillis()) > REASONABLE_IMMEDIATE_TIME_THRESHOLD;
605 LOG.info("Time: " + new Date(time) + " is in the future? " + future);
606 return future;
607 }
608
609 /**
610 * Returns whether recipients exist either, from users or workgroups.
611 *
612 * @param userRecipients the list of user recipients
613 * @param workgroupRecipients the list of workgroup recipients
614 *
615 * @return true if there are any recipients, false otherwise
616 */
617 private boolean recipientsExist(String[] userRecipients, String[] workgroupRecipients) {
618 return (userRecipients != null && userRecipients.length > 0)
619 || (workgroupRecipients != null && workgroupRecipients.length > 0);
620 }
621
622 /**
623 * Returns whether the specified Notification can be reasonably expected to have recipients.
624 *
625 * This is determined on whether the channel has default recipients, is subscribable, and whether the send date time
626 * is far enough in the future to expect that if there are no subscribers, there may actually be some by the time
627 * the notification is sent.
628 * @param notification the notification to test
629 *
630 * @return whether the specified Notification can be reasonably expected to have recipients
631 */
632 private boolean hasPotentialRecipients(NotificationBo notification) {
633 LOG.info("notification channel " + notification.getChannel() + " is subscribable: " + notification.getChannel().isSubscribable());
634 return !notification.getChannel().getRecipientLists().isEmpty() ||
635 !notification.getChannel().getSubscriptions().isEmpty() ||
636 (notification.getChannel().isSubscribable() && timeIsInTheFuture(notification.getSendDateTimeValue().getTime()));
637 }
638 }