View Javadoc

1   /**
2    * Copyright 2005-2011 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.postprocessor.kew;
17  
18  import org.apache.log4j.Logger;
19  import org.kuali.rice.ken.bo.NotificationMessageDelivery;
20  import org.kuali.rice.ken.core.GlobalNotificationServiceLocator;
21  import org.kuali.rice.ken.deliverer.impl.KEWActionListMessageDeliverer;
22  import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
23  import org.kuali.rice.ken.service.NotificationService;
24  import org.kuali.rice.ken.util.NotificationConstants;
25  import org.kuali.rice.ken.util.Util;
26  import org.kuali.rice.kew.api.KewApiConstants;
27  import org.kuali.rice.kew.api.WorkflowDocument;
28  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
29  import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
30  import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
31  import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent;
32  import org.kuali.rice.kew.framework.postprocessor.DeleteEvent;
33  import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
34  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
35  import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
36  import org.kuali.rice.kew.framework.postprocessor.PostProcessor;
37  import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
38  
39  import java.io.ByteArrayInputStream;
40  import java.io.IOException;
41  import java.util.List;
42  import java.util.Properties;
43  
44  
45  /**
46   * This class is the post processor that gets run when workflow state changes occur for the 
47   * underlying core NotificationDocumentType that all notifications go into KEW as.  This class is responsible for changing 
48   * the state of the associated notification message delivery record after someone FYIs or ACKs their notification 
49   * in the KEW Action List.
50   * @author Kuali Rice Team (rice.collab@kuali.org)
51   */
52  public class NotificationPostProcessor implements PostProcessor {
53      private static final Logger LOG = Logger.getLogger(NotificationPostProcessor.class);
54  
55      NotificationService notificationService;
56      NotificationMessageDeliveryService msgDeliverySvc;
57  
58      /**
59       * Constructs a NotificationPostProcessor instance.
60       */
61      public NotificationPostProcessor() {
62          this.msgDeliverySvc = GlobalNotificationServiceLocator.getInstance().getNotificationMessageDeliveryService();
63          this.notificationService = GlobalNotificationServiceLocator.getInstance().getNotificationService();
64      }
65  
66      /**
67       * Need to intercept ACKNOWLEDGE or FYI actions taken on notification workflow documents and set the local state of the 
68       * Notification to REMOVED as well.
69       * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doActionTaken(org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent)
70       */
71      public ProcessDocReport doActionTaken(ActionTakenEvent event) throws Exception {
72          LOG.debug("ENTERING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId());
73  
74          // NOTE: this action could be happening because the user initiated it via KEW, OR because a dismiss or autoremove action
75          // has been invoked programmatically and the KEWActionListMessageDeliverer is taking an action...so there is a risk of being
76          // invoked recursively (which will lead to locking issues and other problems).  We therefore mark the document in the KEWActionList
77          // MessageDeliverer before performing an action, so that we can detect this scenario here, and avoid invoking KEN again.
78  
79          LOG.debug("ACTION TAKEN=" + event.getActionTaken().getActionTaken());
80  
81          String actionTakenCode = event.getActionTaken().getActionTaken().getCode();
82  
83          Properties p = new Properties();
84          WorkflowDocument doc = WorkflowDocumentFactory.loadDocument(event.getActionTaken().getPrincipalId(), event.getDocumentId());
85          try {
86              p.load(new ByteArrayInputStream(doc.getAttributeContent().getBytes()));
87          } catch (IOException ioe) {
88              throw new RuntimeException(ioe);
89          }
90          String internalCommand = p.getProperty(KEWActionListMessageDeliverer.INTERNAL_COMMAND_FLAG);
91  
92          if (Boolean.valueOf(internalCommand).booleanValue()) {
93              LOG.info("Internal command detected by NotificationPostProcessor - will not invoke KEN");
94              return new ProcessDocReport(true, "");
95          }
96          
97          LOG.info("NotificationPostProcessor detected end-user action " + event.getActionTaken().getActionTaken() + " on document " + event.getActionTaken().getDocumentId());
98  
99          if(actionTakenCode.equals(KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD) || actionTakenCode.equals(KewApiConstants.ACTION_TAKEN_FYI_CD)) {
100             LOG.debug("User has taken either acknowledge or fy action (action code=" + actionTakenCode + 
101                     ") for Notification action item with document ID: " + event.getDocumentId() + 
102             ".  We are now changing the status of the associated NotificationMessageDelivery to REMOVED.");
103 
104             try {
105                 NotificationMessageDelivery nmd = msgDeliverySvc.getNotificationMessageDeliveryByDelivererId(event.getDocumentId());
106 
107                 if (nmd == null) {
108                     throw new RuntimeException("Could not find message delivery from workflow document " + event.getDocumentId() + " to dismiss");
109                 }
110 
111                 //get the id of the associated notification message delivery record
112                 String cause;
113                 if (KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD.equals(actionTakenCode)) {
114                     cause = NotificationConstants.ACK_CAUSE;
115                 } else if (KewApiConstants.ACTION_TAKEN_FYI_CD.equals(actionTakenCode)) {
116                     cause = NotificationConstants.FYI_CAUSE;
117                 } else {
118                     cause = "unknown";
119                 }
120 
121                 LOG.info("Dismissing message id " + nmd.getId() + " due to cause: " + cause);
122                 notificationService.dismissNotificationMessageDelivery(nmd.getId(),
123                         Util.getNotificationSystemUser(),
124                         cause);
125             } catch(Exception e) {
126                 throw new RuntimeException("Error dismissing message", e);
127             }
128         }
129 
130         LOG.debug("LEAVING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId());
131         return new ProcessDocReport(true);
132     }
133 
134     /**
135      * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doDeleteRouteHeader(org.kuali.rice.kew.framework.postprocessor.DeleteEvent)
136      */
137     public ProcessDocReport doDeleteRouteHeader(DeleteEvent arg0) throws Exception {
138         return new ProcessDocReport(true, "");
139     }
140 
141     /**
142      * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doRouteLevelChange(org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange)
143      */
144     public ProcessDocReport doRouteLevelChange(DocumentRouteLevelChange arg0) throws Exception {
145         return new ProcessDocReport(true, "");
146     }
147 
148     /**
149      * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doRouteStatusChange(org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange)
150      */
151     public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange arg0) throws Exception {
152         return new ProcessDocReport(true, "");
153     }
154 
155     /**
156      * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#beforeProcess(org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent)
157      */
158     public ProcessDocReport beforeProcess(BeforeProcessEvent beforeProcessEvent) throws Exception {
159         return new ProcessDocReport(true, "");
160     }
161 
162     /**
163      * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#afterProcess(org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent)
164      */
165     public ProcessDocReport afterProcess(AfterProcessEvent afterProcessEvent) throws Exception {
166         return new ProcessDocReport(true, "");
167     }
168 
169     /**
170      * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#getDocumentIdsToLock(org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent)
171      */
172 	public List<String> getDocumentIdsToLock(DocumentLockingEvent documentLockingEvent) throws Exception {
173 		return null;
174 	}
175     
176     
177     
178     
179 }