001 /**
002 * Copyright 2005-2012 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.framework.postprocessor.ActionTakenEvent;
030 import org.kuali.rice.kew.framework.postprocessor.AfterProcessEvent;
031 import org.kuali.rice.kew.framework.postprocessor.BeforeProcessEvent;
032 import org.kuali.rice.kew.framework.postprocessor.DeleteEvent;
033 import org.kuali.rice.kew.framework.postprocessor.DocumentLockingEvent;
034 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteLevelChange;
035 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
036 import org.kuali.rice.kew.framework.postprocessor.PostProcessor;
037 import org.kuali.rice.kew.framework.postprocessor.ProcessDocReport;
038
039 import java.io.ByteArrayInputStream;
040 import java.io.IOException;
041 import java.util.List;
042 import java.util.Properties;
043
044
045 /**
046 * This class is the post processor that gets run when workflow state changes occur for the
047 * underlying core NotificationDocumentType that all notifications go into KEW as. This class is responsible for changing
048 * the state of the associated notification message delivery record after someone FYIs or ACKs their notification
049 * in the KEW Action List.
050 * @author Kuali Rice Team (rice.collab@kuali.org)
051 */
052 public class NotificationPostProcessor implements PostProcessor {
053 private static final Logger LOG = Logger.getLogger(NotificationPostProcessor.class);
054
055 NotificationService notificationService;
056 NotificationMessageDeliveryService msgDeliverySvc;
057
058 /**
059 * Constructs a NotificationPostProcessor instance.
060 */
061 public NotificationPostProcessor() {
062 this.msgDeliverySvc = GlobalNotificationServiceLocator.getInstance().getNotificationMessageDeliveryService();
063 this.notificationService = GlobalNotificationServiceLocator.getInstance().getNotificationService();
064 }
065
066 /**
067 * Need to intercept ACKNOWLEDGE or FYI actions taken on notification workflow documents and set the local state of the
068 * Notification to REMOVED as well.
069 * @see org.kuali.rice.kew.framework.postprocessor.PostProcessor#doActionTaken(org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent)
070 */
071 public ProcessDocReport doActionTaken(ActionTakenEvent event) throws Exception {
072 LOG.debug("ENTERING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId());
073
074 // NOTE: this action could be happening because the user initiated it via KEW, OR because a dismiss or autoremove action
075 // has been invoked programmatically and the KEWActionListMessageDeliverer is taking an action...so there is a risk of being
076 // invoked recursively (which will lead to locking issues and other problems). We therefore mark the document in the KEWActionList
077 // MessageDeliverer before performing an action, so that we can detect this scenario here, and avoid invoking KEN again.
078
079 LOG.debug("ACTION TAKEN=" + event.getActionTaken().getActionTaken());
080
081 String actionTakenCode = event.getActionTaken().getActionTaken().getCode();
082
083 Properties p = new Properties();
084 WorkflowDocument doc = WorkflowDocumentFactory.loadDocument(event.getActionTaken().getPrincipalId(), event.getDocumentId());
085 try {
086 p.load(new ByteArrayInputStream(doc.getAttributeContent().getBytes()));
087 } catch (IOException ioe) {
088 throw new RuntimeException(ioe);
089 }
090 String internalCommand = p.getProperty(KEWActionListMessageDeliverer.INTERNAL_COMMAND_FLAG);
091
092 if (Boolean.valueOf(internalCommand).booleanValue()) {
093 LOG.info("Internal command detected by NotificationPostProcessor - will not invoke KEN");
094 return new ProcessDocReport(true, "");
095 }
096
097 LOG.info("NotificationPostProcessor detected end-user action " + event.getActionTaken().getActionTaken() + " on document " + event.getActionTaken().getDocumentId());
098
099 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 }