1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.ken.web.spring;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.log4j.Logger;
20 import org.kuali.rice.core.framework.persistence.dao.GenericDao;
21 import org.kuali.rice.ken.bo.Notification;
22 import org.kuali.rice.ken.bo.NotificationChannel;
23 import org.kuali.rice.ken.bo.NotificationChannelReviewer;
24 import org.kuali.rice.ken.bo.NotificationContentType;
25 import org.kuali.rice.ken.bo.NotificationPriority;
26 import org.kuali.rice.ken.bo.NotificationProducer;
27 import org.kuali.rice.ken.bo.NotificationRecipient;
28 import org.kuali.rice.ken.bo.NotificationSender;
29 import org.kuali.rice.ken.document.kew.NotificationWorkflowDocument;
30 import org.kuali.rice.ken.exception.ErrorList;
31 import org.kuali.rice.ken.service.NotificationChannelService;
32 import org.kuali.rice.ken.service.NotificationMessageContentService;
33 import org.kuali.rice.ken.service.NotificationRecipientService;
34 import org.kuali.rice.ken.service.NotificationService;
35 import org.kuali.rice.ken.service.NotificationWorkflowDocumentService;
36 import org.kuali.rice.ken.util.NotificationConstants;
37 import org.kuali.rice.ken.util.Util;
38 import org.kuali.rice.kew.api.WorkflowDocument;
39 import org.kuali.rice.kew.rule.GenericAttributeContent;
40 import org.kuali.rice.kim.api.KimConstants.KimGroupMemberTypes;
41 import org.springframework.web.servlet.ModelAndView;
42
43 import javax.servlet.ServletException;
44 import javax.servlet.http.HttpServletRequest;
45 import javax.servlet.http.HttpServletResponse;
46 import java.io.IOException;
47 import java.sql.Timestamp;
48 import java.text.ParseException;
49 import java.util.Date;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53
54
55
56
57
58 public class SendNotificationMessageController extends BaseSendNotificationController {
59
60 private static final Logger LOG = Logger
61 .getLogger(SendNotificationMessageController.class);
62
63 private static final String NONE_CHANNEL = "___NONE___";
64 private static final long REASONABLE_IMMEDIATE_TIME_THRESHOLD = 1000 * 60 * 5;
65
66
67
68
69
70
71
72
73 private boolean timeIsInTheFuture(long time) {
74 boolean future = (time - System.currentTimeMillis()) > REASONABLE_IMMEDIATE_TIME_THRESHOLD;
75 LOG.info("Time: " + new Date(time) + " is in the future? " + future);
76 return future;
77 }
78
79
80
81
82
83
84
85
86
87 private boolean hasPotentialRecipients(Notification notification) {
88 LOG.info("notification channel " + notification.getChannel() + " is subscribable: "
89 + notification.getChannel().isSubscribable());
90 return notification.getChannel().getRecipientLists().size() > 0
91 ||
92 notification.getChannel().getSubscriptions().size() > 0
93 ||
94 (notification.getChannel().isSubscribable() && timeIsInTheFuture(notification.getSendDateTime()
95 .getTime()));
96 }
97
98 protected NotificationService notificationService;
99
100 protected NotificationWorkflowDocumentService notificationWorkflowDocService;
101
102 protected NotificationChannelService notificationChannelService;
103
104 protected NotificationRecipientService notificationRecipientService;
105
106 protected NotificationMessageContentService messageContentService;
107
108 protected GenericDao businessObjectDao;
109
110
111
112
113
114 public void setNotificationService(NotificationService notificationService) {
115 this.notificationService = notificationService;
116 }
117
118
119
120
121
122 public void setNotificationWorkflowDocumentService(
123 NotificationWorkflowDocumentService s) {
124 this.notificationWorkflowDocService = s;
125 }
126
127
128
129
130
131 public void setNotificationChannelService(
132 NotificationChannelService notificationChannelService) {
133 this.notificationChannelService = notificationChannelService;
134 }
135
136
137
138
139
140 public void setNotificationRecipientService(
141 NotificationRecipientService notificationRecipientService) {
142 this.notificationRecipientService = notificationRecipientService;
143 }
144
145
146
147
148
149 public void setMessageContentService(
150 NotificationMessageContentService notificationMessageContentService) {
151 this.messageContentService = notificationMessageContentService;
152 }
153
154
155
156
157
158 public void setBusinessObjectDao(GenericDao businessObjectDao) {
159 this.businessObjectDao = businessObjectDao;
160 }
161
162
163
164
165
166
167
168
169
170 public ModelAndView sendSimpleNotificationMessage(
171 HttpServletRequest request, HttpServletResponse response)
172 throws ServletException, IOException {
173 String view = "SendSimpleNotificationMessage";
174
175 LOG.debug("remoteUser: " + request.getRemoteUser());
176
177 Map<String, Object> model = setupModelForSendSimpleNotification(request);
178 model.put("errors", new ErrorList());
179
180 return new ModelAndView(view, model);
181 }
182
183
184
185
186
187
188 private Map<String, Object> setupModelForSendSimpleNotification(
189 HttpServletRequest request) {
190 Map<String, Object> model = new HashMap<String, Object>();
191 model.put("defaultSender", request.getRemoteUser());
192 model.put("channels", notificationChannelService
193 .getAllNotificationChannels());
194 model.put("priorities", businessObjectDao
195 .findAll(NotificationPriority.class));
196
197 String sendDateTime = request.getParameter("sendDateTime");
198 String currentDateTime = Util.getCurrentDateTime();
199 if (StringUtils.isEmpty(sendDateTime)) {
200 sendDateTime = currentDateTime;
201 }
202 model.put("sendDateTime", sendDateTime);
203
204
205
206 if (request.getParameter("originalDateTime") == null) {
207 model.put("originalDateTime", currentDateTime);
208 } else {
209 model.put("originalDateTime", request.getParameter("originalDateTime"));
210 }
211
212 model.put("userRecipients", request.getParameter("userRecipients"));
213 model.put("workgroupRecipients", request.getParameter("workgroupRecipients"));
214 model.put("workgroupNamespaceCodes", request.getParameter("workgroupNamespaceCodes"));
215
216 return model;
217 }
218
219
220
221
222
223
224
225
226
227 public ModelAndView submitSimpleNotificationMessage(
228 HttpServletRequest request, HttpServletResponse response)
229 throws ServletException, IOException {
230 LOG.debug("remoteUser: " + request.getRemoteUser());
231
232
233
234 String initiatorId = request.getRemoteUser();
235
236
237 WorkflowDocument document;
238 Map<String, Object> model = new HashMap<String, Object>();
239 String view;
240 try {
241 document = NotificationWorkflowDocument.createNotificationDocument(
242 initiatorId,
243 NotificationConstants.KEW_CONSTANTS.SEND_NOTIFICATION_REQ_DOC_TYPE);
244
245
246 Notification notification = populateNotificationInstance(request,
247 model);
248
249
250 String notificationAsXml = messageContentService
251 .generateNotificationMessage(notification);
252
253 Map<String, String> attrFields = new HashMap<String, String>();
254 List<NotificationChannelReviewer> reviewers = notification.getChannel().getReviewers();
255 int ui = 0;
256 int gi = 0;
257 for (NotificationChannelReviewer reviewer : reviewers) {
258 String prefix;
259 int index;
260 if (KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.equals(reviewer.getReviewerType())) {
261 prefix = "user";
262 index = ui;
263 ui++;
264 } else if (KimGroupMemberTypes.GROUP_MEMBER_TYPE.equals(reviewer.getReviewerType())) {
265 prefix = "group";
266 index = gi;
267 gi++;
268 } else {
269 LOG.error("Invalid type for reviewer " + reviewer.getReviewerId() + ": "
270 + reviewer.getReviewerType());
271 continue;
272 }
273 attrFields.put(prefix + index, reviewer.getReviewerId());
274 }
275 GenericAttributeContent gac = new GenericAttributeContent("channelReviewers");
276 document.setApplicationContent(notificationAsXml);
277 document.setAttributeContent("<attributeContent>" + gac.generateContent(attrFields) + "</attributeContent>");
278
279 document.setTitle(notification.getTitle());
280
281 document.route("This message was submitted via the simple notification message submission form by user "
282 + initiatorId);
283
284 view = "SendSimpleNotificationMessage";
285
286
287 ErrorList el = new ErrorList();
288 el.addError("Notification(s) sent.");
289 model.put("errors", el);
290
291 } catch (ErrorList el) {
292
293 Map<String, Object> model2 = setupModelForSendSimpleNotification(request);
294 model.putAll(model2);
295 model.put("errors", el);
296
297 view = "SendSimpleNotificationMessage";
298 } catch (Exception e) {
299 throw new RuntimeException(e);
300 }
301
302 return new ModelAndView(view, model);
303 }
304
305
306
307
308
309
310
311
312 private Notification populateNotificationInstance(
313 HttpServletRequest request, Map<String, Object> model)
314 throws IllegalArgumentException, ErrorList {
315 ErrorList errors = new ErrorList();
316
317 Notification notification = new Notification();
318
319
320
321 String channelName = request.getParameter("channelName");
322 if (StringUtils.isEmpty(channelName) || StringUtils.equals(channelName, NONE_CHANNEL)) {
323 errors.addError("You must choose a channel.");
324 } else {
325 model.put("channelName", channelName);
326 }
327
328
329 String priorityName = request.getParameter("priorityName");
330 if (StringUtils.isEmpty(priorityName)) {
331 errors.addError("You must choose a priority.");
332 } else {
333 model.put("priorityName", priorityName);
334 }
335
336
337 String senderNames = request.getParameter("senderNames");
338 String[] senders = null;
339 if (StringUtils.isEmpty(senderNames)) {
340 errors.addError("You must enter at least one sender.");
341 } else {
342 senders = StringUtils.split(senderNames, ",");
343
344 model.put("senderNames", senderNames);
345 }
346
347
348 String deliveryType = request.getParameter("deliveryType");
349 if (StringUtils.isEmpty(deliveryType)) {
350 errors.addError("You must choose a type.");
351 } else {
352 if (deliveryType
353 .equalsIgnoreCase(NotificationConstants.DELIVERY_TYPES.FYI)) {
354 deliveryType = NotificationConstants.DELIVERY_TYPES.FYI;
355 } else {
356 deliveryType = NotificationConstants.DELIVERY_TYPES.ACK;
357 }
358 model.put("deliveryType", deliveryType);
359 }
360
361
362 String originalDateTime = request.getParameter("originalDateTime");
363 Date origdate = null;
364 Date senddate = null;
365 Date removedate = null;
366 try {
367 origdate = Util.parseUIDateTime(originalDateTime);
368 } catch (ParseException pe) {
369 errors.addError("Original date is invalid.");
370 }
371
372 String sendDateTime = request.getParameter("sendDateTime");
373 if (StringUtils.isBlank(sendDateTime)) {
374 sendDateTime = Util.getCurrentDateTime();
375 }
376
377 try {
378 senddate = Util.parseUIDateTime(sendDateTime);
379 } catch (ParseException pe) {
380 errors.addError("You specified an invalid Send Date/Time. Please use the calendar picker.");
381 }
382
383 if (senddate != null && senddate.before(origdate)) {
384 errors.addError("Send Date/Time cannot be in the past.");
385 }
386
387 model.put("sendDateTime", sendDateTime);
388
389
390 String autoRemoveDateTime = request.getParameter("autoRemoveDateTime");
391 if (StringUtils.isNotBlank(autoRemoveDateTime)) {
392 try {
393 removedate = Util.parseUIDateTime(autoRemoveDateTime);
394 } catch (ParseException pe) {
395 errors.addError("You specified an invalid Auto-Remove Date/Time. Please use the calendar picker.");
396 }
397
398 if (removedate != null) {
399 if (removedate.before(origdate)) {
400 errors.addError("Auto-Remove Date/Time cannot be in the past.");
401 } else if (senddate != null && removedate.before(senddate)) {
402 errors.addError("Auto-Remove Date/Time cannot be before the Send Date/Time.");
403 }
404 }
405 }
406
407 model.put("autoRemoveDateTime", autoRemoveDateTime);
408
409
410 String[] userRecipients = parseUserRecipients(request);
411
412
413 String[] workgroupRecipients = parseWorkgroupRecipients(request);
414
415
416 String[] workgroupNamespaceCodes = parseWorkgroupNamespaceCodes(request);
417
418
419 String title = request.getParameter("title");
420 if (!StringUtils.isEmpty(title)) {
421 model.put("title", title);
422 } else {
423 errors.addError("You must fill in a title");
424 }
425
426
427 String message = request.getParameter("message");
428 if (StringUtils.isEmpty(message)) {
429 errors.addError("You must fill in a message.");
430 } else {
431 model.put("message", message);
432 }
433
434
435 if (errors.getErrors().size() > 0) {
436 throw errors;
437 }
438
439
440 NotificationChannel channel = Util.retrieveFieldReference("channel",
441 "name", channelName, NotificationChannel.class,
442 businessObjectDao);
443 notification.setChannel(channel);
444
445 NotificationPriority priority = Util.retrieveFieldReference("priority",
446 "name", priorityName, NotificationPriority.class,
447 businessObjectDao);
448 notification.setPriority(priority);
449
450 NotificationContentType contentType = Util.retrieveFieldReference(
451 "contentType", "name",
452 NotificationConstants.CONTENT_TYPES.SIMPLE_CONTENT_TYPE,
453 NotificationContentType.class, businessObjectDao);
454 notification.setContentType(contentType);
455
456 NotificationProducer producer = Util
457 .retrieveFieldReference(
458 "producer",
459 "name",
460 NotificationConstants.KEW_CONSTANTS.NOTIFICATION_SYSTEM_USER_NAME,
461 NotificationProducer.class, businessObjectDao);
462 notification.setProducer(producer);
463
464 for (String senderName : senders) {
465 if (StringUtils.isEmpty(senderName)) {
466 errors.addError("A sender's name cannot be blank.");
467 } else {
468 NotificationSender ns = new NotificationSender();
469 ns.setSenderName(senderName.trim());
470 notification.addSender(ns);
471 }
472 }
473
474 boolean recipientsExist = false;
475
476 if (userRecipients != null && userRecipients.length > 0) {
477 recipientsExist = true;
478 for (String userRecipientId : userRecipients) {
479 if (isUserRecipientValid(userRecipientId, errors)) {
480 NotificationRecipient recipient = new NotificationRecipient();
481 recipient.setRecipientType(KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE.getCode());
482 recipient.setRecipientId(userRecipientId);
483 notification.addRecipient(recipient);
484 }
485 }
486 }
487
488 if (workgroupRecipients != null && workgroupRecipients.length > 0) {
489 recipientsExist = true;
490 if (workgroupNamespaceCodes != null && workgroupNamespaceCodes.length > 0) {
491 if (workgroupNamespaceCodes.length == workgroupRecipients.length) {
492 for (int i = 0; i < workgroupRecipients.length; i++) {
493 if (isWorkgroupRecipientValid(workgroupRecipients[i], workgroupNamespaceCodes[i], errors)) {
494 NotificationRecipient recipient = new NotificationRecipient();
495 recipient.setRecipientType(KimGroupMemberTypes.GROUP_MEMBER_TYPE.getCode());
496 recipient.setRecipientId(
497 getGroupService().getGroupByNamespaceCodeAndName(workgroupNamespaceCodes[i],
498 workgroupRecipients[i]).getId());
499 notification.addRecipient(recipient);
500 }
501 }
502 } else {
503 errors.addError("The number of groups must match the number of namespace codes");
504 }
505 } else {
506 errors.addError("You must specify a namespace code for every group name");
507 }
508 } else if (workgroupNamespaceCodes != null && workgroupNamespaceCodes.length > 0) {
509 errors.addError("You must specify a group name for every namespace code");
510 }
511
512
513 if (errors.getErrors().size() > 0) {
514 throw errors;
515 }
516
517 notification.setTitle(title);
518
519 notification.setDeliveryType(deliveryType);
520
521
522 Date d = null;
523 if (StringUtils.isNotBlank(sendDateTime)) {
524 try {
525 d = Util.parseUIDateTime(sendDateTime);
526 } catch (ParseException pe) {
527 errors.addError("You specified an invalid send date and time. Please use the calendar picker.");
528 }
529 notification.setSendDateTime(new Timestamp(d.getTime()));
530 }
531
532 Date d2 = null;
533 if (StringUtils.isNotBlank(autoRemoveDateTime)) {
534 try {
535 d2 = Util.parseUIDateTime(autoRemoveDateTime);
536 if (d2.before(d)) {
537 errors.addError("Auto Remove Date/Time cannot be before Send Date/Time.");
538 }
539 } catch (ParseException pe) {
540 errors.addError("You specified an invalid auto remove date and time. Please use the calendar picker.");
541 }
542 notification.setAutoRemoveDateTime(new Timestamp(d2.getTime()));
543 }
544
545 if (!recipientsExist && !hasPotentialRecipients(notification)) {
546 errors.addError("You must specify at least one user or group recipient.");
547 }
548
549
550 if (errors.getErrors().size() > 0) {
551 throw errors;
552 }
553
554 notification
555 .setContent(NotificationConstants.XML_MESSAGE_CONSTANTS.CONTENT_SIMPLE_OPEN
556 + NotificationConstants.XML_MESSAGE_CONSTANTS.MESSAGE_OPEN
557 + message
558 + NotificationConstants.XML_MESSAGE_CONSTANTS.MESSAGE_CLOSE
559 + NotificationConstants.XML_MESSAGE_CONSTANTS.CONTENT_CLOSE);
560
561 return notification;
562 }
563 }