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