001    /*
002     * Copyright 2005-2007 The Kuali Foundation
003     *
004     *
005     * Licensed under the Educational Community License, Version 2.0 (the "License");
006     * you may not use this file except in compliance with the License.
007     * You may obtain a copy of the License at
008     *
009     * http://www.opensource.org/licenses/ecl2.php
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.kuali.rice.kew.actions;
018    
019    import java.util.ArrayList;
020    import java.util.List;
021    
022    import org.apache.log4j.MDC;
023    import org.kuali.rice.kew.actionrequest.ActionRequestFactory;
024    import org.kuali.rice.kew.actionrequest.ActionRequestValue;
025    import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
026    import org.kuali.rice.kew.actiontaken.ActionTakenValue;
027    import org.kuali.rice.kew.doctype.bo.DocumentType;
028    import org.kuali.rice.kew.exception.InvalidActionTakenException;
029    import org.kuali.rice.kew.exception.WorkflowException;
030    import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
031    import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl;
032    import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
033    import org.kuali.rice.kew.service.KEWServiceLocator;
034    import org.kuali.rice.kew.util.KEWConstants;
035    import org.kuali.rice.kew.util.Utilities;
036    import org.kuali.rice.kim.bo.entity.KimPrincipal;
037    
038    
039    /**
040     * Super user Approves a single action request.
041     *
042     * @author Kuali Rice Team (rice.collab@kuali.org)
043     */
044    public class SuperUserActionRequestApproveEvent extends SuperUserActionTakenEvent {
045        /**
046         * This is the only action which is polymorphic...the action taken code is dynamically determined
047         * based on action requested.  All other actions' action taken code is immutable, so the field could otherwise
048         * be set to final and initialized in the constructor...however it would not be advisable to perform in the
049         * constructor the work required by this class to determine the action taken.  So for now the class initializes
050         * the action taken to null (this would be the behavior anyway if the constructor did not enforce an action taken code
051         * to be supplied).  An alternative would be to do away with the stored superclass field and simply delegate to a subclass
052         * getActionTakenCode implementation when necessary.  It is also not clear that this would be a good choice as it may be
053         * called multiple times in arbitrary contexts.
054         */
055        private static final String UNDEFINED_ACTION_TAKEN_CODE = null;
056    
057        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SuperUserActionRequestApproveEvent.class);
058        private Long actionRequestId;
059    
060        public SuperUserActionRequestApproveEvent(DocumentRouteHeaderValue routeHeader, KimPrincipal principal) {
061            super(UNDEFINED_ACTION_TAKEN_CODE, routeHeader, principal);
062            this.superUserAction = KEWConstants.SUPER_USER_ACTION_REQUEST_APPROVE;
063        }
064    
065        public SuperUserActionRequestApproveEvent(DocumentRouteHeaderValue routeHeader, KimPrincipal principal, Long actionRequestId, String annotation, boolean runPostProcessor) {
066            super(UNDEFINED_ACTION_TAKEN_CODE, routeHeader, principal, annotation, runPostProcessor);
067            this.superUserAction = KEWConstants.SUPER_USER_ACTION_REQUEST_APPROVE;
068            this.actionRequestId = actionRequestId;
069        }
070    
071        public void setActionTaken() {
072            String actionRequestCode = "";
073    
074            ActionRequestValue actionRequest = getActionRequestService().findByActionRequestId(actionRequestId);
075    
076            setActionRequest(actionRequest);
077    
078            actionRequestCode = actionRequest.getActionRequested();
079            //This has been set up for all of the actions, but this class only does approvals
080            if (KEWConstants.ACTION_REQUEST_APPROVE_REQ.equals(actionRequestCode)) {
081                this.setActionTakenCode(KEWConstants.ACTION_TAKEN_SU_ACTION_REQUEST_APPROVED_CD);
082            } else if (KEWConstants.ACTION_REQUEST_COMPLETE_REQ.equals(actionRequestCode)) {
083                this.setActionTakenCode(KEWConstants.ACTION_TAKEN_SU_ACTION_REQUEST_COMPLETED_CD);
084            } else if (KEWConstants.ACTION_REQUEST_FYI_REQ.equals(actionRequestCode)) {
085                this.setActionTakenCode(KEWConstants.ACTION_TAKEN_SU_ACTION_REQUEST_FYI_CD);
086            } else if (KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ.equals(actionRequestCode)) {
087                this.setActionTakenCode(KEWConstants.ACTION_TAKEN_SU_ACTION_REQUEST_ACKNOWLEDGED_CD);
088            } else {
089                //TODO this should be checked
090                LOG.error("Invalid SU delegation action request code: " + actionRequestCode);
091                throw new RuntimeException("Invalid SU delegation action request code: " + actionRequestCode);
092            }
093        }
094    
095        protected void processActionRequests() throws InvalidActionTakenException {
096            //this method has been written to process all of the actions though only approvals are currently processed
097    
098            DocumentType docType = getRouteHeader().getDocumentType();
099    //        boolean userAuthorized = getDocumentTypeService().verifySUAuthority(docType, getUser());
100    
101            String errorMessage = super.validateActionRules();
102            if (!Utilities.isEmpty(errorMessage)) {
103                LOG.info("User not authorized");
104                List<WorkflowServiceErrorImpl> errors = new ArrayList<WorkflowServiceErrorImpl>();
105                errors.add(new WorkflowServiceErrorImpl(errorMessage, SuperUserActionTakenEvent.AUTHORIZATION));
106                throw new WorkflowServiceErrorException(errorMessage, errors);
107            }
108    //        if (!docType.isSuperUser(getUser())) {
109    //            List errors = new ArrayList();
110    //            errors.add(new WorkflowServiceErrorImpl("User not authorized for super user action", SuperUserActionTakenEvent.AUTHORIZATION));
111    //            throw new WorkflowServiceErrorException("Super User Authorization Error", errors);
112    //        }
113    
114            this.setActionTaken();
115    
116            MDC.put("docId", getRouteHeader().getRouteHeaderId());
117    
118            LOG.debug("Super User Delegation Action on action request: " + annotation);
119            KimPrincipalRecipient superUserRecipient = null;
120            if (getActionRequest().getPrincipal() != null) {
121                    superUserRecipient = new KimPrincipalRecipient(getActionRequest().getPrincipal());
122            }
123            
124            ActionTakenValue actionTaken = this.saveActionTaken(superUserRecipient);
125    
126            LOG.debug("Deactivate this action request");
127    
128            ActionRequestValue request = getActionRequest();
129            getActionRequestService().deactivateRequest(actionTaken, request);
130            if (docType.getSuperUserApproveNotificationPolicy().getPolicyValue() && request.isApproveOrCompleteRequest()) {
131                    KEWServiceLocator.getActionRequestService().activateRequest(
132                    new ActionRequestFactory(this.getRouteHeader()).createNotificationRequest(KEWConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, request.getPrincipal(), this.getActionTakenCode(), getPrincipal(), null));
133            }
134            notifyActionTaken(actionTaken);
135    
136            if (!(KEWConstants.ACTION_TAKEN_SU_ACTION_REQUEST_FYI_CD.equals(this.getActionTakenCode()) && KEWConstants.ACTION_TAKEN_SU_ACTION_REQUEST_ACKNOWLEDGED_CD.equals(this.getActionTakenCode()))) {
137                if (getRouteHeader().isInException()) {
138                    LOG.debug("Moving document back to Enroute from Exception");
139    
140                    String oldStatus = getRouteHeader().getDocRouteStatus();
141                    this.getRouteHeader().markDocumentEnroute();
142    
143                    String newStatus = getRouteHeader().getDocRouteStatus();
144                    this.notifyStatusChange(newStatus, oldStatus);
145                    KEWServiceLocator.getRouteHeaderService().saveRouteHeader(getRouteHeader());
146                }
147                else if (getRouteHeader().isStateSaved()) {
148                    if (KEWConstants.SAVED_REQUEST_RESPONSIBILITY_ID.equals(request.getResponsibilityId())) {
149                        LOG.debug("Moving document to Enroute from Saved because action request was request generated by save action");
150                    
151                        String oldStatus = getRouteHeader().getDocRouteStatus();
152                        this.getRouteHeader().markDocumentEnroute();
153                        String newStatus = getRouteHeader().getDocRouteStatus();
154                        this.notifyStatusChange(newStatus, oldStatus);
155                        KEWServiceLocator.getRouteHeaderService().saveRouteHeader(getRouteHeader());
156                    }
157                }
158            }
159        }
160    
161        public void recordAction() throws InvalidActionTakenException {
162            this.processActionRequests();
163            this.queueDocumentProcessing();
164        }
165    
166        protected void markDocument() throws WorkflowException {
167        }
168    }