001 /*
002 * Copyright 2007 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 java.io.ByteArrayInputStream;
019 import java.io.IOException;
020 import java.rmi.RemoteException;
021 import java.util.Properties;
022
023 import org.apache.log4j.Logger;
024 import org.kuali.rice.ken.bo.NotificationMessageDelivery;
025 import org.kuali.rice.ken.core.GlobalNotificationServiceLocator;
026 import org.kuali.rice.ken.deliverer.impl.KEWActionListMessageDeliverer;
027 import org.kuali.rice.ken.service.NotificationMessageDeliveryService;
028 import org.kuali.rice.ken.service.NotificationService;
029 import org.kuali.rice.ken.util.NotificationConstants;
030 import org.kuali.rice.ken.util.Util;
031 import org.kuali.rice.kew.api.WorkflowDocument;
032 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
033 import org.kuali.rice.kew.dto.ActionTakenEventDTO;
034 import org.kuali.rice.kew.dto.AfterProcessEventDTO;
035 import org.kuali.rice.kew.dto.BeforeProcessEventDTO;
036 import org.kuali.rice.kew.dto.DeleteEventDTO;
037 import org.kuali.rice.kew.dto.DocumentLockingEventDTO;
038 import org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO;
039 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
040 import org.kuali.rice.kew.postprocessor.PostProcessorRemote;
041 import org.kuali.rice.kew.util.KEWConstants;
042
043
044 /**
045 * This class is the post processor that gets run when workflow state changes occur for the
046 * underlying core NotificationDocumentType that all notifications go into KEW as. This class is responsible for changing
047 * the state of the associated notification message delivery record after someone FYIs or ACKs their notification
048 * in the KEW Action List.
049 * @author Kuali Rice Team (rice.collab@kuali.org)
050 */
051 public class NotificationPostProcessor implements PostProcessorRemote {
052 private static final Logger LOG = Logger.getLogger(NotificationPostProcessor.class);
053
054 NotificationService notificationService;
055 NotificationMessageDeliveryService msgDeliverySvc;
056
057 /**
058 * Constructs a NotificationPostProcessor instance.
059 */
060 public NotificationPostProcessor() {
061 this.msgDeliverySvc = GlobalNotificationServiceLocator.getInstance().getNotificationMessageDeliveryService();
062 this.notificationService = GlobalNotificationServiceLocator.getInstance().getNotificationService();
063 }
064
065 /**
066 * Need to intercept ACKNOWLEDGE or FYI actions taken on notification workflow documents and set the local state of the
067 * Notification to REMOVED as well.
068 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#doActionTaken(org.kuali.rice.kew.dto.ActionTakenEventDTO)
069 */
070 public boolean doActionTaken(ActionTakenEventDTO event) throws RemoteException {
071 LOG.debug("ENTERING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId());
072
073 // NOTE: this action could be happening because the user initiated it via KEW, OR because a dismiss or autoremove action
074 // has been invoked programmatically and the KEWActionListMessageDeliverer is taking an action...so there is a risk of being
075 // invoked recursively (which will lead to locking issues and other problems). We therefore mark the document in the KEWActionList
076 // MessageDeliverer before performing an action, so that we can detect this scenario here, and avoid invoking KEN again.
077
078 LOG.debug("ACTION TAKEN=" + event.getActionTaken().getActionTaken());
079
080 String actionTakenCode = event.getActionTaken().getActionTaken();
081
082 Properties p = new Properties();
083 WorkflowDocument doc = WorkflowDocumentFactory.loadDocument(event.getActionTaken().getPrincipalId(), event.getDocumentId());
084 try {
085 p.load(new ByteArrayInputStream(doc.getAttributeContent().getBytes()));
086 } catch (IOException ioe) {
087 throw new RuntimeException(ioe);
088 }
089 String internalCommand = p.getProperty(KEWActionListMessageDeliverer.INTERNAL_COMMAND_FLAG);
090
091 if (Boolean.valueOf(internalCommand)) {
092 LOG.info("Internal command detected by NotificationPostProcessor - will not invoke KEN");
093 return true;
094 }
095
096 LOG.info("NotificationPostProcessor detected end-user action " + event.getActionTaken().getActionTaken() + " on document " + event.getActionTaken().getDocumentId());
097
098 if(actionTakenCode.equals(KEWConstants.ACTION_TAKEN_ACKNOWLEDGED_CD) || actionTakenCode.equals(KEWConstants.ACTION_TAKEN_FYI_CD)) {
099 LOG.debug("User has taken either acknowledge or fy action (action code=" + actionTakenCode +
100 ") for Notification action item with document ID: " + event.getDocumentId() +
101 ". We are now changing the status of the associated NotificationMessageDelivery to REMOVED.");
102
103 try {
104 NotificationMessageDelivery nmd = msgDeliverySvc.getNotificationMessageDeliveryByDelivererId(event.getDocumentId());
105
106 if (nmd == null) {
107 throw new RuntimeException("Could not find message delivery from workflow document " + event.getDocumentId() + " to dismiss");
108 }
109
110 //get the id of the associated notification message delivery record
111 String cause;
112 if (KEWConstants.ACTION_TAKEN_ACKNOWLEDGED_CD.equals(actionTakenCode)) {
113 cause = NotificationConstants.ACK_CAUSE;
114 } else if (KEWConstants.ACTION_TAKEN_FYI_CD.equals(actionTakenCode)) {
115 cause = NotificationConstants.FYI_CAUSE;
116 } else {
117 cause = "unknown";
118 }
119
120 LOG.info("Dismissing message id " + nmd.getId() + " due to cause: " + cause);
121 notificationService.dismissNotificationMessageDelivery(nmd.getId(),
122 Util.getNotificationSystemUser(),
123 cause);
124 } catch(Exception e) {
125 throw new RuntimeException("Error dismissing message", e);
126 }
127 }
128
129 LOG.debug("LEAVING NotificationPostProcessor.doActionTaken() for Notification action item with document ID: " + event.getDocumentId());
130 return true;
131 }
132
133 /**
134 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#doDeleteRouteHeader(org.kuali.rice.kew.dto.DeleteEventDTO)
135 */
136 public boolean doDeleteRouteHeader(DeleteEventDTO arg0) throws RemoteException {
137 return true;
138 }
139
140 /**
141 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#doRouteLevelChange(org.kuali.rice.kew.dto.DocumentRouteLevelChangeDTO)
142 */
143 public boolean doRouteLevelChange(DocumentRouteLevelChangeDTO arg0) throws RemoteException {
144 return true;
145 }
146
147 /**
148 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#doRouteStatusChange(org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO)
149 */
150 public boolean doRouteStatusChange(DocumentRouteStatusChangeDTO arg0) throws RemoteException {
151 return true;
152 }
153
154 /**
155 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#beforeProcess(org.kuali.rice.kew.dto.BeforeProcessEventDTO)
156 */
157 public boolean beforeProcess(BeforeProcessEventDTO beforeProcessEvent) throws Exception {
158 return true;
159 }
160
161 /**
162 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#afterProcess(org.kuali.rice.kew.dto.AfterProcessEventDTO)
163 */
164 public boolean afterProcess(AfterProcessEventDTO afterProcessEvent) throws Exception {
165 return true;
166 }
167
168 /**
169 * @see org.kuali.rice.kew.postprocessor.PostProcessorRemote#getDocumentIdsToLock(org.kuali.rice.kew.dto.DocumentLockingEventDTO)
170 */
171 public String[] getDocumentIdsToLock(DocumentLockingEventDTO documentLockingEvent) throws Exception {
172 return null;
173 }
174
175
176
177
178 }