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