1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.lum.workflow;
17 import java.util.List;
18
19 import javax.xml.namespace.QName;
20
21 import org.apache.commons.lang.StringUtils;
22 import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
23 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
24 import org.kuali.rice.kew.actiontaken.ActionTakenValue;
25 import org.kuali.rice.kew.dto.ActionRequestDTO;
26 import org.kuali.rice.kew.postprocessor.ActionTakenEvent;
27 import org.kuali.rice.kew.postprocessor.AfterProcessEvent;
28 import org.kuali.rice.kew.postprocessor.BeforeProcessEvent;
29 import org.kuali.rice.kew.postprocessor.DeleteEvent;
30 import org.kuali.rice.kew.postprocessor.DocumentLockingEvent;
31 import org.kuali.rice.kew.postprocessor.DocumentRouteLevelChange;
32 import org.kuali.rice.kew.postprocessor.DocumentRouteStatusChange;
33 import org.kuali.rice.kew.postprocessor.IDocumentEvent;
34 import org.kuali.rice.kew.postprocessor.PostProcessor;
35 import org.kuali.rice.kew.postprocessor.ProcessDocReport;
36 import org.kuali.rice.kew.service.KEWServiceLocator;
37 import org.kuali.rice.kew.service.WorkflowDocument;
38 import org.kuali.rice.kew.util.KEWConstants;
39 import org.kuali.rice.kim.bo.entity.dto.KimPrincipalInfo;
40 import org.kuali.rice.kim.bo.types.dto.AttributeSet;
41 import org.kuali.rice.kim.service.KIMServiceLocator;
42 import org.kuali.rice.student.StudentWorkflowConstants;
43 import org.kuali.rice.student.bo.KualiStudentKimAttributes;
44 import org.kuali.student.common.exceptions.OperationFailedException;
45 import org.kuali.student.common.rice.StudentIdentityConstants;
46 import org.kuali.student.core.proposal.ProposalConstants;
47 import org.kuali.student.core.proposal.dto.ProposalInfo;
48 import org.kuali.student.core.proposal.service.ProposalService;
49 public class KualiStudentPostProcessorBase implements PostProcessor{
50 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiStudentPostProcessorBase.class);
51
52 private ProposalService proposalService;
53
54 public ProcessDocReport afterProcess(AfterProcessEvent arg0) throws Exception {
55 return new ProcessDocReport(true);
56 }
57
58 public ProcessDocReport beforeProcess(BeforeProcessEvent arg0) throws Exception {
59 return new ProcessDocReport(true);
60 }
61
62 public ProcessDocReport doActionTaken(ActionTakenEvent actionTakenEvent) throws Exception {
63 ActionTakenValue actionTaken = KEWServiceLocator.getActionTakenService().findByActionTakenId(actionTakenEvent.getActionTaken().getActionTakenId());
64 if (actionTaken == null) {
65 if (LOG.isInfoEnabled()) {
66 LOG.info("Could not find valid ActionTakenValue for doc id '" + actionTakenEvent.getRouteHeaderId() + "'" +
67 ((actionTakenEvent.getActionTaken() == null) ? "" : " for action: " + actionTakenEvent.getActionTaken().getActionTakenLabel()));
68 }
69 actionTaken = actionTakenEvent.getActionTaken();
70 }
71 boolean success = true;
72
73 if (!StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, actionTaken.getActionTaken())) {
74 ProposalInfo proposalInfo = getProposalService().getProposalByWorkflowId(actionTakenEvent.getRouteHeaderId().toString());
75 if (actionTaken == null) {
76 throw new OperationFailedException("No action taken found for document id " + actionTakenEvent.getRouteHeaderId());
77 }
78 if (StringUtils.equals(KEWConstants.ACTION_TAKEN_SU_DISAPPROVED_CD, actionTaken.getActionTaken())) {
79
80 processSuperUserDisapproveActionTaken(actionTakenEvent, actionTaken, proposalInfo);
81 }
82
83 else if (!StringUtils.equals(KEWConstants.ACTION_TAKEN_ADHOC_REVOKED_CD, actionTaken.getActionTaken())) {
84 for (ActionRequestValue actionRequest : actionTaken.getActionRequests()) {
85 if (actionRequest.isAdHocRequest() && actionRequest.isUserRequest()) {
86 processActionTakenOnAdhocRequest(actionTakenEvent, actionRequest);
87 }
88 }
89 }
90 success = processCustomActionTaken(actionTakenEvent, actionTaken, proposalInfo);
91 } else {
92 success = processCustomSaveActionTaken(actionTakenEvent, actionTaken);
93 }
94 return new ProcessDocReport(success);
95 }
96
97 protected boolean processCustomActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken, ProposalInfo proposalInfo) throws Exception {
98
99 return true;
100 }
101
102 protected boolean processCustomSaveActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken) throws Exception {
103
104 return true;
105 }
106
107 protected void processActionTakenOnAdhocRequest(ActionTakenEvent actionTakenEvent, ActionRequestValue actionRequestValue) throws Exception {
108 WorkflowDocument doc = new WorkflowDocument(getPrincipalIdForSystemUser(), actionTakenEvent.getRouteHeaderId());
109 LOG.info("Clearing EDIT permissions added via adhoc requests to principal id: " + actionRequestValue.getPrincipalId());
110 removeEditAdhocPermissions(actionRequestValue.getPrincipalId(), doc);
111 }
112
113 protected void processSuperUserDisapproveActionTaken(ActionTakenEvent actionTakenEvent, ActionTakenValue actionTaken, ProposalInfo proposalInfo) throws Exception {
114 LOG.info("Action taken was 'Super User Disapprove' which is a 'Withdraw' in Kuali Student");
115 LOG.info("Will set proposal state to '" + ProposalConstants.PROPOSAL_STATE_WITHDRAWN + "'");
116 updateProposal(actionTakenEvent, ProposalConstants.PROPOSAL_STATE_WITHDRAWN, proposalInfo);
117 processWithdrawActionTaken(actionTakenEvent, proposalInfo);
118 }
119
120 protected void processWithdrawActionTaken(ActionTakenEvent actionTakenEvent, ProposalInfo proposalInfo) throws Exception {
121
122 }
123
124 public ProcessDocReport doDeleteRouteHeader(DeleteEvent arg0) throws Exception {
125 return new ProcessDocReport(true);
126 }
127
128 public ProcessDocReport doRouteLevelChange(DocumentRouteLevelChange documentRouteLevelChange) throws Exception {
129 ProposalInfo proposalInfo = getProposalService().getProposalByWorkflowId(documentRouteLevelChange.getRouteHeaderId().toString());
130
131
132 if (StringUtils.equals(StudentWorkflowConstants.DEFAULT_WORKFLOW_DOCUMENT_START_NODE_NAME,documentRouteLevelChange.getOldNodeName())) {
133
134 WorkflowDocument doc = new WorkflowDocument(getPrincipalIdForSystemUser(), documentRouteLevelChange.getRouteHeaderId());
135 for (ActionRequestDTO actionRequestDTO : doc.getActionRequests()) {
136 if (actionRequestDTO.isAdHocRequest() && actionRequestDTO.isUserRequest() &&
137 StringUtils.equals(documentRouteLevelChange.getOldNodeName(),actionRequestDTO.getNodeName())) {
138 LOG.info("Clearing EDIT permissions added via adhoc requests to principal id: " + actionRequestDTO.getPrincipalId());
139 removeEditAdhocPermissions(actionRequestDTO.getPrincipalId(), doc);
140 }
141 }
142 }
143 else {
144 LOG.warn("Will not clear any permissions added via adhoc requests");
145 }
146 boolean success = processCustomRouteLevelChange(documentRouteLevelChange, proposalInfo);
147 return new ProcessDocReport(success);
148 }
149
150 protected boolean processCustomRouteLevelChange(
151 DocumentRouteLevelChange documentRouteLevelChange,
152 ProposalInfo proposalInfo) throws Exception {
153
154 proposalInfo.getAttributes().put("workflowNode", documentRouteLevelChange.getNewNodeName());
155 getProposalService().updateProposal(proposalInfo.getId(), proposalInfo);
156 return true;
157 }
158
159 public ProcessDocReport doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
160 boolean success = true;
161
162 if (StringUtils.equals(KEWConstants.ROUTE_HEADER_INITIATED_CD, statusChangeEvent.getOldRouteStatus()) &&
163 StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, statusChangeEvent.getNewRouteStatus())) {
164
165 success = processCustomRouteStatusSavedStatusChange(statusChangeEvent);
166 } else {
167 ProposalInfo proposalInfo = getProposalService().getProposalByWorkflowId(statusChangeEvent.getRouteHeaderId().toString());
168
169
170 String proposalState = getProposalStateForRouteStatus(proposalInfo.getState(), statusChangeEvent.getNewRouteStatus());
171 updateProposal(statusChangeEvent, proposalState, proposalInfo);
172 success = processCustomRouteStatusChange(statusChangeEvent, proposalInfo);
173 }
174 return new ProcessDocReport(success);
175 }
176
177 protected boolean processCustomRouteStatusChange(DocumentRouteStatusChange statusChangeEvent, ProposalInfo proposalInfo) throws Exception {
178
179 return true;
180 }
181
182 protected boolean processCustomRouteStatusSavedStatusChange(DocumentRouteStatusChange statusChangeEvent) throws Exception {
183
184 return true;
185 }
186
187 public List<Long> getDocumentIdsToLock(DocumentLockingEvent arg0) throws Exception {
188 return null;
189 }
190
191
192
193
194
195
196 protected String getProposalStateForRouteStatus(String currentProposalState, String newWorkflowStatusCode) {
197 if (StringUtils.equals(ProposalConstants.PROPOSAL_STATE_WITHDRAWN, currentProposalState)) {
198
199 return null;
200 }
201 if (StringUtils.equals(KEWConstants.ROUTE_HEADER_SAVED_CD, newWorkflowStatusCode)) {
202 return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_SAVED);
203 } else if (KEWConstants.ROUTE_HEADER_ENROUTE_CD.equals(newWorkflowStatusCode)) {
204 return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_ENROUTE);
205 } else if (KEWConstants.ROUTE_HEADER_CANCEL_CD .equals(newWorkflowStatusCode)) {
206 return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_CANCELLED);
207 } else if (KEWConstants.ROUTE_HEADER_DISAPPROVED_CD.equals(newWorkflowStatusCode)) {
208 return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_REJECTED);
209 } else if (KEWConstants.ROUTE_HEADER_PROCESSED_CD.equals(newWorkflowStatusCode)) {
210 return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_APPROVED);
211 } else if (KEWConstants.ROUTE_HEADER_EXCEPTION_CD.equals(newWorkflowStatusCode)) {
212 return getProposalStateFromNewState(currentProposalState, ProposalConstants.PROPOSAL_STATE_EXCEPTION);
213 } else {
214
215 return null;
216 }
217 }
218
219
220
221
222
223 protected String getProposalStateFromNewState(String currentProposalState, String newProposalState) {
224 if (LOG.isInfoEnabled()) {
225 LOG.info("current proposal state is '" + currentProposalState + "' and new proposal state will be '" + newProposalState + "'");
226 }
227 return getStateFromNewState(currentProposalState, newProposalState);
228 }
229
230
231
232
233
234 protected String getStateFromNewState(String currentState, String newState) {
235 if (StringUtils.equals(currentState, newState)) {
236 if (LOG.isInfoEnabled()) {
237 LOG.info("returning null as current state and new state are both '" + currentState + "'");
238 }
239 return null;
240 }
241 return newState;
242 }
243
244 protected void removeEditAdhocPermissions(String principalId, WorkflowDocument doc) {
245 AttributeSet qualifications = new AttributeSet();
246 qualifications.put(KualiStudentKimAttributes.DOCUMENT_TYPE_NAME,doc.getDocumentType());
247 qualifications.put(KualiStudentKimAttributes.QUALIFICATION_DATA_ID,doc.getAppDocId());
248 KIMServiceLocator.getRoleManagementService().removePrincipalFromRole(principalId, StudentWorkflowConstants.ROLE_NAME_ADHOC_EDIT_PERMISSIONS_ROLE_NAMESPACE, StudentWorkflowConstants.ROLE_NAME_ADHOC_EDIT_PERMISSIONS_ROLE_NAME, qualifications);
249 }
250
251 protected void removeCommentAdhocPermissions(String roleNamespace, String roleName, String principalId, WorkflowDocument doc) {
252 AttributeSet qualifications = new AttributeSet();
253 qualifications.put(KualiStudentKimAttributes.DOCUMENT_TYPE_NAME,doc.getDocumentType());
254 qualifications.put(KualiStudentKimAttributes.QUALIFICATION_DATA_ID,doc.getAppDocId());
255 KIMServiceLocator.getRoleManagementService().removePrincipalFromRole(principalId, StudentWorkflowConstants.ROLE_NAME_ADHOC_ADD_COMMENT_PERMISSIONS_ROLE_NAMESPACE, StudentWorkflowConstants.ROLE_NAME_ADHOC_ADD_COMMENT_PERMISSIONS_ROLE_NAME, qualifications);
256 }
257
258 protected String getPrincipalIdForSystemUser() {
259 KimPrincipalInfo principal = KIMServiceLocator.getIdentityManagementService().getPrincipalByPrincipalName(StudentIdentityConstants.SYSTEM_USER_PRINCIPAL_NAME);
260 if (principal == null) {
261 throw new RuntimeException("Cannot find Principal for principal name: " + StudentIdentityConstants.SYSTEM_USER_PRINCIPAL_NAME);
262 }
263 return principal.getPrincipalId();
264 }
265
266 protected void updateProposal(IDocumentEvent iDocumentEvent, String proposalState, ProposalInfo proposalInfo) throws Exception {
267 if (LOG.isInfoEnabled()) {
268 LOG.info("Setting state '" + proposalState + "' on Proposal with docId='" + proposalInfo.getWorkflowId() + "' and proposalId='" + proposalInfo.getId() + "'");
269 }
270 boolean requiresSave = false;
271 if (proposalState != null) {
272 proposalInfo.setState(proposalState);
273 requiresSave = true;
274 }
275 requiresSave |= preProcessProposalSave(iDocumentEvent, proposalInfo);
276 if (requiresSave) {
277 getProposalService().updateProposal(proposalInfo.getId(), proposalInfo);
278 }
279 }
280
281 protected boolean preProcessProposalSave(IDocumentEvent iDocumentEvent, ProposalInfo proposalInfo) {
282 return false;
283 }
284
285 protected ProposalService getProposalService() {
286 if (this.proposalService == null) {
287 this.proposalService = (ProposalService) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/proposal","ProposalService"));
288 }
289 return this.proposalService;
290 }
291
292 }