View Javadoc

1   /**
2    * Copyright 2005-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.ken.web.spring;
17  
18  import java.io.IOException;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  
23  import javax.servlet.ServletException;
24  import javax.servlet.http.HttpServletRequest;
25  import javax.servlet.http.HttpServletResponse;
26  
27  import org.apache.log4j.Logger;
28  import org.kuali.rice.ken.bo.Notification;
29  import org.kuali.rice.ken.bo.NotificationMessageDelivery;
30  import org.kuali.rice.ken.bo.NotificationRecipient;
31  import org.kuali.rice.ken.bo.NotificationSender;
32  import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
33  import org.kuali.rice.ken.service.NotificationService;
34  import org.kuali.rice.ken.service.NotificationWorkflowDocumentService;
35  import org.kuali.rice.ken.util.NotificationConstants;
36  import org.kuali.rice.ken.util.Util;
37  import org.kuali.rice.kew.api.KewApiConstants;
38  import org.kuali.rice.kim.api.identity.principal.Principal;
39  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
40  import org.springframework.web.servlet.ModelAndView;
41  import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
42  
43  
44  /**
45   * This class is the controller for the basic notification related actions - viewing, etc.
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  public class NotificationController extends MultiActionController {
49      /** Logger for this class and subclasses */
50      private static final Logger LOG = Logger.getLogger(NotificationController.class);
51      
52      protected NotificationService notificationService;
53      protected NotificationWorkflowDocumentService notificationWorkflowDocService;
54      protected NotificationMessageDeliveryService messageDeliveryService;
55     
56      /**
57       * Set the NotificationService
58       * @param notificationService
59       */   
60      public void setNotificationService(NotificationService notificationService) {
61          this.notificationService = notificationService;
62      }
63  
64      /**
65       * This method sets the NotificationWorkflowDocumentService
66       * @param s
67       */
68      public void setNotificationWorkflowDocumentService(NotificationWorkflowDocumentService s) {
69          this.notificationWorkflowDocService = s;
70      }
71  
72      /**
73       * Sets the messageDeliveryService attribute value.
74       * @param messageDeliveryService The messageDeliveryService to set.
75       */
76      public void setMessageDeliveryService(NotificationMessageDeliveryService messageDeliveryService) {
77          this.messageDeliveryService = messageDeliveryService;
78      }
79  
80      /**
81       * Handles the display of the main home page in the system.
82       * @param request : a servlet request
83       * @param response : a servlet response
84       * @throws ServletException : an exception
85       * @throws IOException : an exception
86       * @return a ModelAndView object
87       */   
88      public ModelAndView displayHome(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
89          String view = "HomePage";
90          LOG.debug("remoteUser: "+request.getRemoteUser());
91          Map<String, Object> model = new HashMap<String, Object>(); 
92          return new ModelAndView(view, model);
93      }
94     
95      /**
96       * This method handles displaying the notifications that an individual sent.
97       * @param request
98       * @param response
99       * @return ModelAndView
100      * @throws ServletException
101      * @throws IOException
102      */
103     public ModelAndView displayNotificationsSent(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
104         String view = "NotificationsSent";
105         LOG.debug("remoteUser: "+request.getRemoteUser());
106         Map<String, Object> model = new HashMap<String, Object>();
107         model.put("userId", request.getRemoteUser());
108         return new ModelAndView(view, model);
109     }
110 
111     /**
112      * This method handles displaying the search screen.
113      * @param request
114      * @param response
115      * @return ModelAndView
116      * @throws ServletException
117      * @throws IOException
118      */
119     public ModelAndView displaySearch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
120         String view = "Search";
121         LOG.debug("remoteUser: "+request.getRemoteUser());
122         Map<String, Object> model = new HashMap<String, Object>(); 
123         return new ModelAndView(view, model);
124     }
125 
126     /**
127      * This method displays the user lookup screen.
128      * @param request
129      * @param response
130      * @return
131      * @throws ServletException
132      * @throws IOException
133      */
134     public ModelAndView displayLookupUsers(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
135         String view = "LookupUsers";
136         LOG.debug("remoteUser: "+request.getRemoteUser());
137         Map<String, Object> model = new HashMap<String, Object>(); 
138         return new ModelAndView(view, model);
139     }
140 
141     /**
142      * This method displays the workgroup lookup screen.
143      * @param request
144      * @param response
145      * @return
146      * @throws ServletException
147      * @throws IOException
148      */
149     public ModelAndView displayLookupWorkgroups(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
150         String view = "LookupWorkgroups";
151         LOG.debug("remoteUser: "+request.getRemoteUser());
152         Map<String, Object> model = new HashMap<String, Object>(); 
153         return new ModelAndView(view, model);
154     }
155 
156 
157     /**
158      * This method retrieves the NotificationMessageDelivery given an HttpServletRequest which
159      * may contain EITHER a message delivery id or a workflow doc id.  Therefore, this is a
160      * "special case" for handling the workflow deliverer.
161      * @param request the incoming {@link HttpServletRequest}
162      * @return the {@link NotificationMessageDelivery} or null if not found
163      */
164     protected NotificationMessageDelivery determineMessageFromRequest(HttpServletRequest request) {
165         /**
166          * We can get the NotificationMessageDelivery object given a workflow ID or a NotificationMessageDelivery
167          * Id.  This method might be called either from a workflow action list or
168          * as a link from a message deliverer endpoint such as an email message.
169          */
170         String messageDeliveryId = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.MSG_DELIVERY_ID);
171         String delivererId = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.DELIVERER_ID);
172         if (delivererId == null) {
173             delivererId = request.getParameter(KewApiConstants.DOCUMENT_ID_PARAMETER);
174         }
175 
176         NotificationMessageDelivery messageDelivery;
177         if (messageDeliveryId != null) { // this means that the request came in not from the action list, but rather from a delivery end point
178             LOG.debug("Looking up notification with messageDeliveryId: "+messageDeliveryId);
179             try {
180                 messageDelivery = messageDeliveryService.getNotificationMessageDelivery(new Long(messageDeliveryId));
181             } catch (Exception e) {
182                 throw new RuntimeException("Error getting message with id: " + messageDeliveryId, e);
183             }
184         } else if (delivererId != null) {  // this means that the request was triggered via the action list
185             LOG.debug("Looking up notification with workflowId: "+delivererId);
186             try {
187                 messageDelivery = messageDeliveryService.getNotificationMessageDeliveryByDelivererId(delivererId);
188             } catch (Exception e) {
189                 LOG.error("Error getting message with from deliverer id: " + delivererId, e);
190                 throw new RuntimeException("Error getting message with deliverer id: " + delivererId, e);
191             }
192         } else {
193             throw new RuntimeException("Neither message ('" + NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.MSG_DELIVERY_ID
194                                        + "') nor deliverer id ('" + NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.DELIVERER_ID + "') were specified in the request");
195         }
196         
197         return messageDelivery;
198     }
199 
200     /**
201      * @param req the {@link HttpServletRequest}
202      * @return whether the incoming request was from the action list
203      */
204     protected boolean requestIsFromKEW(HttpServletRequest req) {
205         return req.getParameter(KewApiConstants.DOCUMENT_ID_PARAMETER) != null;
206     }
207 
208     /**
209      * This controller handles displaying the appropriate notification details for a specific record.
210      * @param request : a servlet request
211      * @param response : a servlet response
212      * @throws ServletException : an exception
213      * @throws IOException : an exception
214      * @return a ModelAndView object
215      */   
216     public ModelAndView displayNotificationDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
217         String view = "NotificationDetail"; // default to full view
218 
219         String principalNm = request.getRemoteUser();
220         String command = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.COMMAND);
221         String standaloneWindow = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW);
222 
223         NotificationMessageDelivery messageDelivery = determineMessageFromRequest(request);
224         // now get the notification from the message delivery object
225         Notification notification = messageDelivery.getNotification();
226         boolean actionable = false;
227 
228         if (requestIsFromKEW(request)) {
229             // check to see if this was a standalone window by examining the command from KEW before setting it to INLINE to force an inline view
230             if(command != null && 
231                     (command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.NORMAL_VIEW) || 
232                             command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.DOC_SEARCH_VIEW))) {
233                 standaloneWindow = "true";
234             }
235 
236             // we want all messages from the action list in line
237             command = NotificationConstants.NOTIFICATION_DETAIL_VIEWS.INLINE;
238         }
239         
240         Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalNm);
241         if (principal != null) {
242         	actionable = (principal.getPrincipalId()).equals(messageDelivery.getUserRecipientId()) && NotificationConstants.MESSAGE_DELIVERY_STATUS.DELIVERED.equals(messageDelivery.getMessageDeliveryStatus());
243         } else {
244             throw new RuntimeException("There is no principal for principalNm " + principalNm);
245         }
246         
247         List<NotificationSender> senders = notification.getSenders();
248         List<NotificationRecipient> recipients = notification.getRecipients();
249 
250         String contenthtml = Util.transformContent(notification);
251 
252         // check to see if the details need to be rendered in line (no stuff around them)
253         if (command != null && command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.INLINE)) {
254             view = "NotificationDetailInline";   
255         } 
256 
257         Map<String, Object> model = new HashMap<String, Object>();
258         model.put("notification", notification);
259         model.put("senders", senders);
260         model.put("recipients", recipients);
261         model.put("contenthtml", contenthtml);
262         model.put("messageDeliveryId", messageDelivery.getId());
263         model.put("command", command);
264         model.put("actionable", actionable);
265         model.put(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW, standaloneWindow);
266         return new ModelAndView(view, model);
267     }
268 
269     /**
270      * This method handles user dismissal of a message
271      * @param request : a servlet request
272      * @param response : a servlet response
273      * @return a ModelAndView object
274      */   
275     public ModelAndView dismissMessage(HttpServletRequest request, HttpServletResponse response) {
276         String command = request.getParameter("action");
277         if (command == null) throw new RuntimeException("Dismissal command not specified");
278 
279         if (NotificationConstants.ACK_CAUSE.equals(command)) {
280             return dismissMessage(command, "Notificaton acknowledged.  Please refresh your action list.", request, response);
281         } else if (NotificationConstants.FYI_CAUSE.equals(command)) {
282             return dismissMessage(command, "Action Taken.  Please refresh your action list.", request, response);
283         } else {
284             throw new RuntimeException("Unknown dismissal command: " + command);
285         }
286     }
287 
288     /**
289      * This method takes an action on the message delivery - dismisses it with the action/cause that comes from the
290      * UI layer
291      * @param action the action or cause of the dismissal
292      * @param message the message to display to the user
293      * @param request the HttpServletRequest
294      * @param response the HttpServletResponse
295      * @return an appropriate ModelAndView
296      */
297     private ModelAndView dismissMessage(String action, String message, HttpServletRequest request, HttpServletResponse response) {
298         String view = "NotificationDetail";
299 
300         String principalNm = request.getRemoteUser();
301         String messageDeliveryId = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.MSG_DELIVERY_ID);
302         String command = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.COMMAND);
303         String standaloneWindow = request.getParameter(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW);
304 
305         if (messageDeliveryId == null) {
306             throw new RuntimeException("A null messageDeliveryId was provided.");
307         }
308 
309         LOG.debug("messageDeliveryId: "+messageDeliveryId);
310         LOG.debug("command: "+command);
311 
312         /**
313          * We can get the notification object given a workflow ID or a notification
314          * Id.  This method might be called either from a workflow action list or
315          * as a link from a message deliverer endpoint such as an email message.  
316          */        
317         NotificationMessageDelivery delivery = messageDeliveryService.getNotificationMessageDelivery(Long.decode(messageDeliveryId));
318         if (delivery == null) {
319             throw new RuntimeException("Could not find message delivery with id " + messageDeliveryId);
320         }
321         Notification notification = delivery.getNotification();
322 
323         /*
324          * dismiss the message delivery
325          */
326 
327         Principal principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(principalNm);
328         notificationService.dismissNotificationMessageDelivery(delivery.getId(), principal.getPrincipalId(), action);
329 
330         List<NotificationSender> senders = notification.getSenders();
331         List<NotificationRecipient> recipients = notification.getRecipients();
332 
333         String contenthtml = Util.transformContent(notification);       
334 
335         // first check to see if this is a standalone window, b/c if it is, we'll want to close
336         if(standaloneWindow != null && standaloneWindow.equals("true")) {
337             view = "NotificationActionTakenCloseWindow";
338         } else { // otherwise check to see if the details need to be rendered in line (no stuff around them)
339             if (command != null && command.equals(NotificationConstants.NOTIFICATION_DETAIL_VIEWS.INLINE)) { 
340                 view = "NotificationDetailInline";   
341             }
342         }
343 
344         Map<String, Object> model = new HashMap<String, Object>();
345         model.put("notification", notification);
346         model.put("message", message);
347         model.put("senders", senders);
348         model.put("recipients", recipients);
349         model.put("contenthtml", contenthtml);
350         model.put("messageDeliveryId", messageDeliveryId);
351         model.put("command", command);
352         model.put(NotificationConstants.NOTIFICATION_CONTROLLER_CONSTANTS.STANDALONE_WINDOW, standaloneWindow);
353         return new ModelAndView(view, model);
354     }
355 }