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.kuali.rice.kew.actionrequest.ActionRequestFactory;
020 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
021 import org.kuali.rice.kew.actionrequest.KimGroupRecipient;
022 import org.kuali.rice.kew.actionrequest.KimPrincipalRecipient;
023 import org.kuali.rice.kew.actionrequest.Recipient;
024 import org.kuali.rice.kew.engine.node.RouteNodeInstance;
025 import org.kuali.rice.kew.api.exception.InvalidActionTakenException;
026 import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
027 import org.kuali.rice.kew.service.KEWServiceLocator;
028 import org.kuali.rice.kew.api.KewApiConstants;
029 import org.kuali.rice.kim.api.identity.principal.PrincipalContract;
030 import org.kuali.rice.kim.api.group.Group;
031
032
033 import java.util.List;
034
035
036 /**
037 * Responsible for creating adhoc requests that are requested from the client.
038 *
039 * @author Kuali Rice Team (rice.collab@kuali.org)
040 */
041 public class AdHocAction extends ActionTakenEvent {
042 /**
043 * AdHoc actions don't actually result in an action being taken...it's a special case that generates other action requests
044 */
045 private static final String NO_ACTION_TAKEN_CODE = null;
046
047 private String actionRequested;
048 private String nodeName;
049 private Integer priority;
050 private String responsibilityDesc;
051 private Boolean forceAction;
052 private Recipient recipient;
053 private String annotation;
054 private String requestLabel;
055
056 public AdHocAction(DocumentRouteHeaderValue routeHeader, PrincipalContract principal) {
057 super(NO_ACTION_TAKEN_CODE, routeHeader, principal);
058 }
059
060 public AdHocAction(DocumentRouteHeaderValue routeHeader, PrincipalContract principal, String annotation, String actionRequested, String nodeName, Integer priority, Recipient recipient, String responsibilityDesc, Boolean forceAction, String requestLabel) {
061 super(NO_ACTION_TAKEN_CODE, routeHeader, principal, annotation);
062 this.actionRequested = actionRequested;
063 this.nodeName = nodeName;
064 this.priority = priority;
065 this.responsibilityDesc = responsibilityDesc;
066 this.forceAction = forceAction;
067 this.recipient = recipient;
068 this.annotation = annotation;
069 this.requestLabel = requestLabel;
070 }
071
072 public void recordAction() throws InvalidActionTakenException {
073 String errorMessage = validateActionRules();
074 if (!org.apache.commons.lang.StringUtils.isEmpty(errorMessage)) {
075 throw new InvalidActionTakenException(errorMessage);
076 }
077 List targetNodes = KEWServiceLocator.getRouteNodeService().getCurrentNodeInstances(getDocumentId());
078 String error = adhocRouteAction(targetNodes, false);
079 if (!org.apache.commons.lang.StringUtils.isEmpty(error)) {
080 throw new InvalidActionTakenException(error);
081 }
082 }
083
084 /* (non-Javadoc)
085 * @see org.kuali.rice.kew.actions.ActionTakenEvent#validateActionRules()
086 */
087 @Override
088 public String validateActionRules() {
089 List targetNodes = KEWServiceLocator.getRouteNodeService().getCurrentNodeInstances(getDocumentId());
090 return validateActionRulesInternal(targetNodes);
091 }
092
093 @Override
094 public String validateActionRules(List<ActionRequestValue> actionRequests) {
095 return validateActionRules();
096 }
097
098 private String validateActionRulesInternal(List<RouteNodeInstance> targetNodes) {
099 // recipient will be null when this is invoked from ActionRegistry.getValidActions
100 if (recipient != null) {
101 if (recipient instanceof KimPrincipalRecipient) {
102 KimPrincipalRecipient principalRecipient = (KimPrincipalRecipient)recipient;
103 if (!KEWServiceLocator.getDocumentTypePermissionService().canReceiveAdHocRequest(principalRecipient.getPrincipalId(), getRouteHeader(), actionRequested)) {
104 return "The principal '" + principalRecipient.getPrincipal().getPrincipalName() + "' does not have permission to recieve ad hoc requests on DocumentType '" + getRouteHeader().getDocumentType().getName() + "'";
105 }
106 } else if (recipient instanceof KimGroupRecipient) {
107 Group group = ((KimGroupRecipient)recipient).getGroup();
108 if (!KEWServiceLocator.getDocumentTypePermissionService().canGroupReceiveAdHocRequest("" + group.getId(), getRouteHeader(), actionRequested)) {
109 return "The group '" + group.getName() + "' does not have permission to recieve ad hoc requests on DocumentType '" + getRouteHeader().getDocumentType().getName() + "'";
110 }
111 } else {
112 return "Invalid Recipient type encountered: " + recipient.getClass();
113 }
114 }
115 return adhocRouteAction(targetNodes, true);
116 }
117
118 private String adhocRouteAction(List<RouteNodeInstance> targetNodes, boolean forValidationOnly) {
119 //if (targetNodes.isEmpty()) {
120 // return "Could not locate an node instance on the document with the name '" + nodeName + "'";
121 //}
122 boolean requestCreated = false;
123 for (RouteNodeInstance routeNode : targetNodes)
124 {
125 // if the node name is null, then adhoc it to the first available node
126 if (nodeName == null || routeNode.getName().equals(nodeName))
127 {
128 String message = createAdHocRequest(routeNode, forValidationOnly);
129 if (StringUtils.isNotBlank(message))
130 {
131 return message;
132 }
133 requestCreated = true;
134 if (nodeName == null)
135 {
136 break;
137 }
138 }
139 }
140
141 if (!requestCreated && targetNodes.isEmpty()) {
142 String message = createAdHocRequest(null, forValidationOnly);
143 if (StringUtils.isNotBlank(message)) {
144 return message;
145 }
146 requestCreated = true;
147 }
148
149 if (!requestCreated) {
150 return "Didn't create request. The node name " + nodeName + " given is probably invalid ";
151 }
152 return "";
153 }
154
155 private String createAdHocRequest(RouteNodeInstance routeNode, boolean forValidationOnly) {
156 ActionRequestValue adhocRequest = new ActionRequestValue();
157 if (!forValidationOnly) {
158 ActionRequestFactory arFactory = new ActionRequestFactory(routeHeader, routeNode);
159 adhocRequest = arFactory.createActionRequest(actionRequested, recipient, responsibilityDesc, forceAction, annotation);
160 adhocRequest.setResponsibilityId(KewApiConstants.ADHOC_REQUEST_RESPONSIBILITY_ID);
161 adhocRequest.setRequestLabel(requestLabel);
162 if (priority != null) {
163 adhocRequest.setPriority(priority);
164 }
165 } else {
166 adhocRequest.setActionRequested(actionRequested);
167 }
168 if (adhocRequest.isApproveOrCompleteRequest() && ! (routeHeader.isEnroute() || routeHeader.isStateInitiated() ||
169 routeHeader.isStateSaved())) {
170 return "Cannot AdHoc a Complete or Approve request when document is in state '" + routeHeader.getDocRouteStatusLabel() + "'.";
171 }
172 if (!forValidationOnly) {
173
174 if (routeHeader.isDisaproved() || routeHeader.isCanceled() || routeHeader.isFinal() || routeHeader.isProcessed()) {
175 getActionRequestService().activateRequest(adhocRequest);
176 } else {
177 KEWServiceLocator.getActionRequestService().saveActionRequest(adhocRequest);
178 }
179 }
180 return "";
181 }
182 }