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