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