001 /**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.ken.postprocessor.kew;
017
018 import org.apache.log4j.Logger;
019 import org.kuali.rice.ken.bo.NotificationMessageDelivery;
020 import org.kuali.rice.ken.core.GlobalNotificationServiceLocator;
021 import org.kuali.rice.ken.deliverer.impl.KEWActionListMessageDeliverer;
022 import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
023 import org.kuali.rice.ken.service.NotificationService;
024 import org.kuali.rice.ken.util.NotificationConstants;
025 import org.kuali.rice.ken.util.Util;
026 import org.kuali.rice.kew.api.KewApiConstants;
027 import org.kuali.rice.kew.api.WorkflowDocument;
028 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
029 import org.kuali.rice.kew.api.action.ActionType;
030 import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
031 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
032 import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent;
033 import org.kuali.rice.kew.framework.postprocessor.DeleteEvent;
034 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
035 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
036 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
037 import org.kuali.rice.kew.framework.postprocessor.PostProcessor;
038 import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
039
040 import java.io.ByteArrayInputStream;
041 import java.io.IOException;
042 import java.util.List;
043 import java.util.Properties;
044
045
046 /**
047 * This class is the post processor that gets run when workflow state changes occur for the
048 * underlying core NotificationDocumentType that all notifications go into KEW as. This class is responsible for changing
049 * the state of the associated notification message delivery record after someone FYIs or ACKs their notification
050 * in the KEW Action List.
051 * @author Kuali Rice Team (rice.collab@kuali.org)
052 */
053 public class NotificationPostProcessor implements PostProcessor {
054 private static final Logger LOG = Logger.getLogger(NotificationPostProcessor.class);
055
056 NotificationService notificationService;
057 NotificationMessageDeliveryService msgDeliverySvc;
058
059 /**
060 * Constructs a NotificationPostProcessor instance.
061 */
062 public NotificationPostProcessor() {
063 this.msgDeliverySvc = GlobalNotificationServiceLocator.getInstance().getNotificationMessageDeliveryService();
064 this.notificationService = GlobalNotificationServiceLocator.getInstance().getNotificationService();
065 }
066
067 /**
068 * Need to intercept ACKNOWLEDGE or FYI actions taken on notification workflow documents and set the local state of the
069 * Notification to REMOVED as well.
070 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doActionTaken(org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent)
071 */
072 public ProcessDocReport doActionTaken(ActionTakenEvent event) throws Exception {
073 LOG.debug("ENTERING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId());
074
075 // NOTE: this action could be happening because the user initiated it via KEW, OR because a dismiss or autoremove action
076 // has been invoked programmatically and the KEWActionListMessageDeliverer is taking an action...so there is a risk of being
077 // invoked recursively (which will lead to locking issues and other problems). We therefore mark the document in the KEWActionList
078 // MessageDeliverer before performing an action, so that we can detect this scenario here, and avoid invoking KEN again.
079
080 LOG.debug("ACTION TAKEN=" + event.getActionTaken().getActionTaken());
081
082 String actionTakenCode = event.getActionTaken().getActionTaken().getCode();
083
084 Properties p = new Properties();
085 WorkflowDocument doc = WorkflowDocumentFactory.loadDocument(event.getActionTaken().getPrincipalId(), event.getDocumentId());
086 try {
087 p.load(new ByteArrayInputStream(doc.getAttributeContent().getBytes()));
088 } catch (IOException ioe) {
089 throw new RuntimeException(ioe);
090 }
091 String internalCommand = p.getProperty(KEWActionListMessageDeliverer.INTERNAL_COMMAND_FLAG);
092
093 if (Boolean.valueOf(internalCommand).booleanValue()) {
094 LOG.info("Internal command detected by NotificationPostProcessor - will not invoke KEN");
095 return new ProcessDocReport(true, "");
096 }
097
098 LOG.info("NotificationPostProcessor detected end-user action " + event.getActionTaken().getActionTaken() + " on document " + event.getActionTaken().getDocumentId());
099
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 }