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