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    }