001 /** 002 * Copyright 2005-2013 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.kew.actions; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.apache.log4j.Logger; 020 import org.kuali.rice.core.api.reflect.DataDefinition; 021 import org.kuali.rice.core.api.reflect.ObjectDefinition; 022 import org.kuali.rice.core.api.util.ClassLoaderUtils; 023 import org.kuali.rice.core.framework.resourceloader.ObjectDefinitionResolver; 024 import org.kuali.rice.kew.actionrequest.ActionRequestValue; 025 import org.kuali.rice.kew.api.WorkflowRuntimeException; 026 import org.kuali.rice.kew.api.action.ActionRequestStatus; 027 import org.kuali.rice.kew.api.action.ActionType; 028 import org.kuali.rice.kew.api.exception.ResourceUnavailableException; 029 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 030 import org.kuali.rice.kew.api.KewApiConstants; 031 import org.kuali.rice.kim.api.identity.principal.PrincipalContract; 032 033 import java.util.ArrayList; 034 import java.util.Collections; 035 import java.util.HashMap; 036 import java.util.List; 037 import java.util.Map; 038 039 040 041 /** 042 * A simple implementation of an ActionRegistry which includes all of the default Workflow Actions. 043 * 044 * @author Kuali Rice Team (rice.collab@kuali.org) 045 */ 046 public class ActionRegistryImpl implements ActionRegistry { 047 private static final Logger LOG = Logger.getLogger(ActionRegistryImpl.class); 048 049 private static Map<String, String> actionMap = new HashMap<String, String>(); 050 static { 051 actionMap.put(KewApiConstants.ACTION_TAKEN_ACKNOWLEDGED_CD, AcknowledgeAction.class.getName()); 052 actionMap.put(KewApiConstants.ACTION_TAKEN_ADHOC_CD, AdHocAction.class.getName()); 053 actionMap.put(KewApiConstants.ACTION_TAKEN_ADHOC_REVOKED_CD, RevokeAdHocAction.class.getName()); 054 actionMap.put(KewApiConstants.ACTION_TAKEN_APPROVED_CD, ApproveAction.class.getName()); 055 actionMap.put(KewApiConstants.ACTION_TAKEN_BLANKET_APPROVE_CD, BlanketApproveAction.class.getName()); 056 actionMap.put(KewApiConstants.ACTION_TAKEN_CANCELED_CD, CancelAction.class.getName()); 057 actionMap.put(KewApiConstants.ACTION_TAKEN_COMPLETED_CD, CompleteAction.class.getName()); 058 actionMap.put(KewApiConstants.ACTION_TAKEN_ROUTED_CD, RouteDocumentAction.class.getName()); 059 actionMap.put(KewApiConstants.ACTION_TAKEN_DENIED_CD, DisapproveAction.class.getName()); 060 actionMap.put(KewApiConstants.ACTION_TAKEN_FYI_CD, ClearFYIAction.class.getName()); 061 actionMap.put(KewApiConstants.ACTION_TAKEN_LOG_DOCUMENT_ACTION_CD, LogDocumentActionAction.class.getName()); 062 actionMap.put(KewApiConstants.ACTION_TAKEN_MOVE_CD, MoveDocumentAction.class.getName()); 063 actionMap.put(KewApiConstants.ACTION_TAKEN_TAKE_WORKGROUP_AUTHORITY_CD, TakeWorkgroupAuthority.class.getName()); 064 actionMap.put(KewApiConstants.ACTION_TAKEN_RELEASE_WORKGROUP_AUTHORITY_CD, ReleaseWorkgroupAuthority.class.getName()); 065 actionMap.put(KewApiConstants.ACTION_TAKEN_RETURNED_TO_PREVIOUS_CD, ReturnToPreviousNodeAction.class.getName()); 066 actionMap.put(KewApiConstants.ACTION_TAKEN_SAVED_CD, SaveActionEvent.class.getName()); 067 //actionMap.put(KewApiConstants.ACTION_TAKEN_SU_ACTION_REQUEST_ACKNOWLEDGED_CD, SuperUserActionRequestAcknowledgeEvent.class.getName()); 068 actionMap.put(KewApiConstants.ACTION_TAKEN_SU_ACTION_REQUEST_APPROVED_CD, SuperUserActionRequestApproveEvent.class.getName()); 069 //actionMap.put(KewApiConstants.ACTION_TAKEN_SU_ACTION_REQUEST_COMPLETED_CD, SuperUserActionRequestCompleteEvent.class.getName()); 070 //actionMap.put(KewApiConstants.ACTION_TAKEN_SU_ACTION_REQUEST_FYI_CD, SuperUserActionRequestFYIEvent.class.getName()); 071 actionMap.put(KewApiConstants.ACTION_TAKEN_SU_APPROVED_CD, SuperUserApproveEvent.class.getName()); 072 actionMap.put(KewApiConstants.ACTION_TAKEN_SU_CANCELED_CD, SuperUserCancelEvent.class.getName()); 073 actionMap.put(KewApiConstants.ACTION_TAKEN_SU_DISAPPROVED_CD, SuperUserDisapproveEvent.class.getName()); 074 actionMap.put(KewApiConstants.ACTION_TAKEN_SU_RETURNED_TO_PREVIOUS_CD, SuperUserReturnToPreviousNodeAction.class.getName()); 075 actionMap.put(KewApiConstants.ACTION_TAKEN_SU_ROUTE_LEVEL_APPROVED_CD, SuperUserNodeApproveEvent.class.getName()); 076 actionMap.put(ActionType.RECALL.getCode(), RecallAction.class.getName()); 077 } 078 079 public void registerAction(String actionCode, String actionClass) { 080 if (actionClass == null) { 081 throw new IllegalArgumentException("Action Code '" + actionCode + "' cannot be registered with a null action class."); 082 } 083 if (actionMap.containsKey(actionCode)) { 084 throw new WorkflowRuntimeException("Action Code is already in use. [" + 085 actionCode + ", " + actionClass + "]. "+ 086 "Please unregister the existing implementation first."); 087 } 088 actionMap.put(actionCode, actionClass); 089 } 090 091 public void unregisterAction(String actionCode) { 092 actionMap.remove(actionCode); 093 } 094 095 public Map getActionMap() { 096 return Collections.unmodifiableMap(actionMap); 097 } 098 099 /* (non-Javadoc) 100 * @see org.kuali.rice.kew.actions.ActionRegistry#createAction(java.lang.String, java.util.List) 101 */ 102 public ActionTakenEvent createAction(String actionCode, List<DataDefinition> parameters) throws ResourceUnavailableException { 103 String actionClassName = actionMap.get(actionCode); 104 if (actionClassName == null) { 105 throw new IllegalArgumentException("No action has been registered for the given action code of '" + actionCode + "'."); 106 } 107 ObjectDefinition actionDefinition = new ObjectDefinition(actionClassName); 108 if (parameters != null && !parameters.isEmpty()) { 109 actionDefinition.setConstructorParameters(parameters); 110 } 111 try { 112 //ActionTakenEvent actionTaken = (ActionTakenEvent)GlobalResourceLoader.getResourceLoader().getObject(actionDefinition); 113 // TODO ActionTakenEvent is not an interface so we can't fetch them through the GlobalResourceLoader, for now, just use 114 // the ObjectDefinitionResolver 115 ActionTakenEvent actionTaken = (ActionTakenEvent) ObjectDefinitionResolver.createObject(actionDefinition, ClassLoaderUtils.getDefaultClassLoader(), false); 116 if (actionTaken == null) { 117 // TODO the exception handling here is a bit wonky 118 throw new ResourceUnavailableException("Could not locate action taken class '" + actionClassName + "'"); 119 } 120 return actionTaken; 121 } catch (Exception e) { 122 LOG.debug("createAction() Exception thrown while working with action class name '" + actionClassName + "'"); 123 if (e instanceof ResourceUnavailableException) { 124 throw (ResourceUnavailableException)e; 125 } 126 throw new ResourceUnavailableException(e); 127 } 128 } 129 130 public org.kuali.rice.kew.api.action.ValidActions getValidActions(PrincipalContract principal, DocumentRouteHeaderValue document) { 131 try { 132 org.kuali.rice.kew.api.action.ValidActions.Builder builder = org.kuali.rice.kew.api.action.ValidActions.Builder.create(); 133 List<ActionRequestValue> activeRequests = new ArrayList<ActionRequestValue>(); 134 // this looks like ActionRequestServiceImpl.findAllPendingRequests 135 for ( ActionRequestValue ar : document.getActionRequests() ) { 136 if ( (ar.getCurrentIndicator() != null && ar.getCurrentIndicator()) && StringUtils.equals( ar.getStatus(), ActionRequestStatus.ACTIVATED.getCode() ) ) { 137 activeRequests.add(ar); 138 } 139 } 140 for (String actionTakenCode : actionMap.keySet()) 141 { 142 List<DataDefinition> parameters = new ArrayList<DataDefinition>(); 143 parameters.add(new DataDefinition(document)); 144 parameters.add(new DataDefinition(principal)); 145 ActionTakenEvent actionEvent = createAction(actionTakenCode, parameters); 146 if (StringUtils.isEmpty(actionEvent.validateActionRules(activeRequests))) 147 { 148 builder.addValidAction(ActionType.fromCode(actionTakenCode)); 149 } 150 } 151 return builder.build(); 152 } catch (ResourceUnavailableException e) { 153 throw new WorkflowRuntimeException(e); 154 } 155 } 156 }