1
2
3
4 package org.kuali.student.lum.workflow;
5
6 import java.util.Iterator;
7 import java.util.List;
8
9 import javax.xml.namespace.QName;
10
11 import org.apache.commons.lang.StringUtils;
12 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
13 import org.kuali.rice.kew.api.KewApiConstants;
14 import org.kuali.rice.kew.api.action.ActionTaken;
15 import org.kuali.rice.kew.framework.postprocessor.ActionTakenEvent;
16 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
17 import org.kuali.rice.kew.framework.postprocessor.IDocumentEvent;
18 import org.kuali.student.r1.core.statement.dto.ReqComponentInfo;
19 import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
20
21 import org.kuali.student.r2.common.dto.AttributeInfo;
22 import org.kuali.student.r2.common.dto.DtoConstants;
23 import org.kuali.student.r2.common.exceptions.DoesNotExistException;
24 import org.kuali.student.r2.common.exceptions.OperationFailedException;
25 import org.kuali.student.r2.common.util.AttributeHelper;
26 import org.kuali.student.common.util.security.ContextUtils;
27 import org.kuali.student.r2.core.proposal.dto.ProposalInfo;
28 import org.kuali.student.r2.lum.clu.CLUConstants;
29 import org.kuali.student.r2.lum.course.dto.CourseInfo;
30 import org.kuali.student.r2.lum.course.service.CourseService;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.springframework.transaction.annotation.Transactional;
34
35
36
37
38
39 @Transactional(readOnly=true, rollbackFor={Throwable.class})
40 public class CoursePostProcessorBase extends KualiStudentPostProcessorBase {
41 private static final Logger LOG = LoggerFactory.getLogger(CoursePostProcessorBase.class);
42
43 private CourseService courseService;
44 private CourseStateChangeServiceImpl courseStateChangeService;
45
46
47
48
49
50
51
52
53
54
55
56
57 @Override
58 protected void processWithdrawActionTaken(ActionTakenEvent actionTakenEvent, ProposalInfo proposalInfo) throws Exception {
59
60 if (proposalInfo != null){
61 String proposalDocType=proposalInfo.getType();
62
63
64
65 if ( CLUConstants.PROPOSAL_TYPE_COURSE_CREATE.equals(proposalDocType)
66 || CLUConstants.PROPOSAL_TYPE_COURSE_MODIFY.equals(proposalDocType)) {
67 LOG.info("Will set CLU state to '{}'", DtoConstants.STATE_NOT_APPROVED);
68
69 CourseInfo courseInfo = getCourseService().getCourse(
70 getCourseId(proposalInfo), ContextUtils.getContextInfo());
71
72 updateCourse(actionTakenEvent, DtoConstants.STATE_NOT_APPROVED,
73 courseInfo, proposalInfo);
74 }
75
76
77 else if ( CLUConstants.PROPOSAL_TYPE_COURSE_RETIRE.equals(proposalDocType)) {
78 LOG.info("Withdrawing a retire proposal with ID'{}, will not change any CLU state as there is no new CLU object to set.",
79 proposalInfo.getId());
80 }
81 } else {
82 LOG.info("Proposal Info is null when a withdraw proposal action was taken, doing nothing.");
83 }
84 }
85
86 @Override
87 protected boolean processCustomActionTaken(ActionTakenEvent actionTakenEvent, ActionTaken actionTaken, ProposalInfo proposalInfo) throws Exception {
88 String cluId = getCourseId(proposalInfo);
89 CourseInfo courseInfo = getCourseService().getCourse(cluId, ContextUtils.getContextInfo());
90
91 updateCourse(actionTakenEvent, null, courseInfo, proposalInfo);
92 return true;
93 }
94
95
96
97
98
99
100 @Override
101 protected boolean processCustomRouteStatusChange(DocumentRouteStatusChange statusChangeEvent, ProposalInfo proposalInfo) throws Exception {
102
103 String courseId = getCourseId(proposalInfo);
104 String prevEndTermAtpId = new AttributeHelper (proposalInfo.getAttributes()).get("prevEndTerm");
105
106
107 CourseInfo courseInfo = getCourseService().getCourse(courseId, ContextUtils.getContextInfo());
108
109
110 String newCourseState = getCluStateForRouteStatus(courseInfo.getStateKey(), statusChangeEvent.getNewRouteStatus(), proposalInfo.getType());
111
112
113 if (newCourseState != null){
114 if(DtoConstants.STATE_ACTIVE.equals(newCourseState)){
115
116
117
118 getCourseStateChangeService().changeState(courseId, newCourseState, prevEndTermAtpId, ContextUtils.getContextInfo());
119 } else
120
121
122
123
124 if(DtoConstants.STATE_RETIRED.equals(newCourseState)){
125 retireCourseByProposalCopyAndSave(newCourseState, courseInfo, proposalInfo);
126 getCourseStateChangeService().changeState(courseId, newCourseState, prevEndTermAtpId, ContextUtils.getContextInfo());
127 }
128 else{
129 updateCourse(statusChangeEvent, newCourseState, courseInfo, proposalInfo);
130 }
131 }
132 return true;
133 }
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 protected void retireCourseByProposalCopyAndSave(String courseState, CourseInfo courseInfo, ProposalInfo proposalInfo) throws Exception {
157
158
159
160
161 if (DtoConstants.STATE_RETIRED.equals(courseState)) {
162 if ((proposalInfo != null) && (proposalInfo.getAttributes() != null)) {
163 String rationale = null;
164 if (proposalInfo.getRationale() != null) {
165 rationale = proposalInfo.getRationale().getPlain();
166 }
167 String proposedEndTerm = new AttributeHelper(proposalInfo.getAttributes()).get("proposedEndTerm");
168 String proposedLastTermOffered = new AttributeHelper(proposalInfo.getAttributes()).get("proposedLastTermOffered");
169 String proposedLastCourseCatalogYear = new AttributeHelper(proposalInfo.getAttributes()).get("proposedLastCourseCatalogYear");
170
171 courseInfo.setEndTerm(proposedEndTerm);
172 courseInfo.getAttributes().add(new AttributeInfo("retirementRationale", rationale));
173 courseInfo.getAttributes().add(new AttributeInfo("lastTermOffered", proposedLastTermOffered));
174 courseInfo.getAttributes().add(new AttributeInfo("lastPublicationYear", proposedLastCourseCatalogYear));
175
176
177
178
179
180
181
182
183
184
185
186 if ((proposalInfo != null) && (courseInfo != null)
187 && (courseInfo.getAttributeValue("lastTermOffered") == null)) {
188 courseInfo.getAttributes().add(new AttributeInfo("lastTermOffered", new AttributeHelper(proposalInfo.getAttributes()).get("proposedEndTerm")));
189 }
190 }
191 }
192
193 getCourseService().updateCourse(courseInfo.getId(), courseInfo, ContextUtils.getContextInfo());
194 }
195
196 protected String getCourseId(ProposalInfo proposalInfo) throws OperationFailedException {
197 if (proposalInfo.getProposalReference().size() != 1) {
198 String message = String.format("Found %s CLU objects linked to proposal with docId='%s' and proposalId='%s'. Must have exactly 1 linked.",
199 proposalInfo.getProposalReference().size(), proposalInfo.getWorkflowId(), proposalInfo.getId());
200 LOG.error(message);
201 throw new OperationFailedException(message);
202 }
203 return proposalInfo.getProposalReference().get(0);
204 }
205
206
207
208
209
210
211
212
213
214
215 protected String getCluStateForRouteStatus(String currentCluState, String newWorkflowStatusCode, String docType) {
216 if (CLUConstants.PROPOSAL_TYPE_COURSE_RETIRE.equals(docType)) {
217
218
219 if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(newWorkflowStatusCode)){
220 return DtoConstants.STATE_RETIRED;
221 }
222 return null;
223 } else {
224
225 if (StringUtils.equals(KewApiConstants.ROUTE_HEADER_SAVED_CD, newWorkflowStatusCode)) {
226 return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_DRAFT);
227 } else if (KewApiConstants.ROUTE_HEADER_CANCEL_CD .equals(newWorkflowStatusCode)) {
228 return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_NOT_APPROVED);
229 } else if (KewApiConstants.ROUTE_HEADER_ENROUTE_CD.equals(newWorkflowStatusCode)) {
230 return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_DRAFT);
231 } else if (KewApiConstants.ROUTE_HEADER_DISAPPROVED_CD.equals(newWorkflowStatusCode)) {
232
233
234
235 return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_NOT_APPROVED);
236 } else if (KewApiConstants.ROUTE_HEADER_PROCESSED_CD.equals(newWorkflowStatusCode)) {
237 return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_ACTIVE);
238 } else if (KewApiConstants.ROUTE_HEADER_EXCEPTION_CD.equals(newWorkflowStatusCode)) {
239 return getCourseStateFromNewState(currentCluState, DtoConstants.STATE_DRAFT);
240 } else {
241
242 return null;
243 }
244 }
245 }
246
247
248
249
250
251 protected String getCourseStateFromNewState(String currentCourseState, String newCourseState) {
252 LOG.info("current CLU state is '{}' and new CLU state will be '{}'", currentCourseState, newCourseState);
253 return getStateFromNewState(currentCourseState, newCourseState);
254 }
255
256 protected void updateCourse(IDocumentEvent iDocumentEvent, String courseState, CourseInfo courseInfo, ProposalInfo proposalInfo) throws Exception {
257
258 boolean requiresSave = false;
259 if (courseState != null) {
260 LOG.info("Setting state '{}' on CLU with cluId='{}'", courseState, courseInfo.getId());
261 courseInfo.setStateKey(courseState);
262 requiresSave = true;
263 }
264 LOG.info("Running preProcessCluSave with cluId='{}'", courseInfo.getId());
265 requiresSave |= preProcessCourseSave(iDocumentEvent, courseInfo);
266
267 if (requiresSave) {
268 getCourseService().updateCourse(courseInfo.getId(), courseInfo, ContextUtils.getContextInfo());
269
270
271 if (DtoConstants.STATE_ACTIVE.equals(courseState) && courseInfo.getVersion().getCurrentVersionStart() == null){
272
273
274
275
276 getCourseService().setCurrentCourseVersion(courseInfo.getId(), null, ContextUtils.getContextInfo());
277
278 }
279
280 List<StatementTreeViewInfo> statementTreeViewInfos = courseService.getCourseStatements(courseInfo.getId(), null, null, ContextUtils.getContextInfo());
281 if(statementTreeViewInfos!=null){
282 statementTreeViewInfoStateSetter(courseInfo.getStateKey(), statementTreeViewInfos.iterator());
283
284 for(Iterator<StatementTreeViewInfo> it = statementTreeViewInfos.iterator(); it.hasNext();)
285
286 courseService.updateCourseStatement(courseInfo.getId(), courseState, it.next(), ContextUtils.getContextInfo());
287 }
288 }
289
290 }
291
292 protected boolean preProcessCourseSave(IDocumentEvent iDocumentEvent, CourseInfo courseInfo) {
293 return false;
294 }
295
296 protected CourseService getCourseService() {
297 if (this.courseService == null) {
298 this.courseService = (CourseService) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/course","CourseService"));
299 }
300 return this.courseService;
301 }
302 protected CourseStateChangeServiceImpl getCourseStateChangeService() {
303 if (this.courseStateChangeService == null) {
304 this.courseStateChangeService = new CourseStateChangeServiceImpl();
305 this.courseStateChangeService.setCourseService(getCourseService());
306 }
307 return this.courseStateChangeService;
308 }
309
310
311
312
313 public void statementTreeViewInfoStateSetter(String courseState, Iterator<StatementTreeViewInfo> itr) {
314 while(itr.hasNext()) {
315 StatementTreeViewInfo statementTreeViewInfo = (StatementTreeViewInfo)itr.next();
316 statementTreeViewInfo.setState(courseState);
317 List<ReqComponentInfo> reqComponents = statementTreeViewInfo.getReqComponents();
318 for(Iterator<ReqComponentInfo> it = reqComponents.iterator(); it.hasNext();)
319 it.next().setState(courseState);
320
321 statementTreeViewInfoStateSetter(courseState, statementTreeViewInfo.getStatements().iterator());
322 }
323 }
324 }