View Javadoc

1   package org.kuali.student.lum.lu.ui.course.server.gwt;
2   
3   import java.util.Iterator;
4   import java.util.List;
5   
6   import org.kuali.student.r2.common.dto.ContextInfo;
7   import org.kuali.student.r2.common.dto.DtoConstants;
8   import org.kuali.student.r2.common.dto.StatusInfo;
9   import org.kuali.student.r2.common.exceptions.CircularReferenceException;
10  import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
11  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
12  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
13  import org.kuali.student.r2.common.exceptions.MissingParameterException;
14  import org.kuali.student.r2.common.exceptions.OperationFailedException;
15  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
16  import org.kuali.student.r2.common.exceptions.VersionMismatchException;
17  import org.kuali.student.r2.core.versionmanagement.dto.VersionDisplayInfo;
18  import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
19  import org.kuali.student.lum.common.server.StatementUtil;
20  import org.kuali.student.r2.lum.course.dto.CourseInfo;
21  import org.kuali.student.r2.lum.course.service.CourseService;
22  import org.kuali.student.r2.lum.util.constants.CourseServiceConstants;
23  import org.springframework.transaction.annotation.Transactional;
24  
25  @Transactional(noRollbackFor = { DoesNotExistException.class }, rollbackFor = { Throwable.class })
26  public class CourseStateChangeServiceImpl {
27  	private CourseService courseService;
28  
29  	/**
30  	 * Change the state of a course to a new state
31  	 * 
32  	 * @param courseId id of course
33  	 * @param newState the new state for the course
34  	 * @param prevEndTermAtpId the current version end date of course
35  	 * @return
36  	 * @throws Exception
37  	 */
38  	public StatusInfo changeState(String courseId, String newState,	String prevEndTermAtpId,ContextInfo contextInfo) throws Exception {
39  
40  		CourseInfo courseInfo = courseService.getCourse(courseId,contextInfo);
41  
42  		StatusInfo ret = new StatusInfo();
43  		try {
44  			if (newState.equals(DtoConstants.STATE_ACTIVE)) {
45  				activateCourse(courseInfo, prevEndTermAtpId,contextInfo);
46  			} else if (newState.equals(DtoConstants.STATE_RETIRED)) {
47  				retireCourse(courseInfo,contextInfo);
48  			}
49  
50  			ret.setSuccess(new Boolean(true));
51  		} catch (Exception e) {
52  			ret.setSuccess(new Boolean(false));
53  			ret.setMessage(e.getMessage());
54  		}
55  
56  		return ret;
57  	}
58  
59  	/**
60  	 * Activate a course version. Only course with a state of "Approved" can be activated.
61  	 * 
62  	 * @param courseToActivate
63  	 * @param prevEndTermAtpId the end term we set on the current version
64  	 */
65  	protected void activateCourse(CourseInfo courseToActivate, String prevEndTermAtpId,ContextInfo contextInfo) throws Exception{
66      	CourseInfo currVerCourse = getCurrentVersionOfCourse(courseToActivate,contextInfo);
67      	String existingState = courseToActivate.getStateKey();
68  		String currVerState = currVerCourse.getStateKey();
69  		boolean isCurrVer = (courseToActivate.getId().equals(currVerCourse.getId()));
70  		
71  		if (existingState.equals(DtoConstants.STATE_DRAFT)) {
72  			// since this is approved if isCurrVer we can assume there are no previously active versions to deal with
73  			if (isCurrVer) {
74  				// setstate for thisVerCourse and setCurrentVersion(courseId)
75  				updateCourseVersionStates(courseToActivate, DtoConstants.STATE_ACTIVE, currVerCourse, null, true, prevEndTermAtpId,contextInfo);
76  			} else if (currVerState.equals(DtoConstants.STATE_ACTIVE) ||
77  					currVerState.equals(DtoConstants.STATE_SUSPENDED)) {
78  				updateCourseVersionStates(courseToActivate, DtoConstants.STATE_ACTIVE, currVerCourse, DtoConstants.STATE_SUPERSEDED, true, prevEndTermAtpId,contextInfo);
79  			}
80  		}
81  	}
82  	
83  	/**
84  	 * Retire a course version. Only course with a state of "Active" or "Suspended" can be retired
85  	 * 
86  	 * @param courseToRetire the course to retire
87  	 */
88  	protected void retireCourse(CourseInfo courseToRetire,ContextInfo contextInfo) throws Exception{
89      	String existingState = courseToRetire.getStateKey();		
90  		
91      	if (existingState.equals(DtoConstants.STATE_ACTIVE) || existingState.equals(DtoConstants.STATE_SUSPENDED)){
92      		courseToRetire.setStateKey(DtoConstants.STATE_RETIRED);
93  
94      		courseService.updateCourse(courseToRetire.getId(),courseToRetire, contextInfo);
95  			updateStatementTreeViewInfoState(courseToRetire,contextInfo);
96      	}
97  	}
98  	
99  	/**
100 	 * Get the current version of course from another version of course
101 	 * 
102 	 *
103 	 */
104 	protected CourseInfo getCurrentVersionOfCourse(CourseInfo course,ContextInfo contextInfo)
105 			throws Exception {
106 		// Get version independent id of course
107 		String verIndId = course.getVersionInfo().getVersionIndId();
108 
109 		// Get id of current version of course given the versionindependen id
110 		VersionDisplayInfo curVerDisplayInfo = courseService.getCurrentVersion(
111 			CourseServiceConstants.COURSE_NAMESPACE_URI, verIndId, contextInfo);
112 		String curVerId = curVerDisplayInfo.getId();
113 
114 		// Return the current version of the course
115 		CourseInfo currVerCourse = courseService.getCourse(curVerId,contextInfo);
116 
117 		return currVerCourse;
118 	}
119 
120 	/**
121 	 * Based on null values, updates states of thisVerCourse and currVerCourse
122 	 * and sets thisVerCourse as the current version. Attempts to rollback
123 	 * transaction on exception.
124 	 * 
125 	 * @param thisVerCourse
126 	 *            this is the version that the user selected to change the state
127 	 * @param thisVerNewState
128 	 *            this is state that the user selected to change thisVerCourse
129 	 *            to
130 	 * @param currVerCourse
131 	 *            this is the current version of the course
132 	 *            (currentVersionStartDt <= now && currentVersionEndDt > now)
133 	 * @param currVerNewState
134 	 *            this is the state that we need to set the current version to.
135 	 *            Set to null to not update the currVerCourse state.
136 	 * @param makeCurrent
137 	 *            if true we'll set thisVerCourse as the current version.
138 	 * @param prevEndTermAtpId
139 	 *            the end term for the previous version to end on
140 	 * @throws Exception
141 	 */
142 	@Transactional(readOnly = false)
143 	private void updateCourseVersionStates(CourseInfo thisVerCourse,
144 			String thisVerNewState, CourseInfo currVerCourse,
145 			String currVerNewState, boolean makeCurrent,
146 			String prevEndTermAtpId,ContextInfo contextInfo) throws Exception {
147 		String thisVerPrevState = thisVerCourse.getStateKey();
148 
149 		// if already current, will throw error if you try to make the current
150 		// version the current version.
151 		boolean isCurrent = thisVerCourse.getId().equals(currVerCourse.getId());
152 		if(!makeCurrent || !isCurrent || !thisVerCourse.getVersionInfo().getSequenceNumber().equals(1)){
153 			makeCurrent &= !isCurrent;
154 		}
155 
156 		if (thisVerNewState == null) {
157 			throw new InvalidParameterException("new state cannot be null");
158 		} else {
159 			thisVerCourse.setStateKey(thisVerNewState);
160 			courseService.updateCourse(thisVerCourse.getId(),thisVerCourse,contextInfo);
161 			updateStatementTreeViewInfoState(thisVerCourse,contextInfo);
162 		}
163 
164 		// won't get called if previous exception was thrown
165 		if (currVerNewState != null) {
166 			currVerCourse.setStateKey(currVerNewState);
167 			if(currVerCourse.getEndTerm()==null){
168 				currVerCourse.setEndTerm(prevEndTermAtpId);
169 			}
170 			courseService.updateCourse(currVerCourse.getId(),currVerCourse,contextInfo);
171 			updateStatementTreeViewInfoState(currVerCourse,contextInfo);
172 		}
173 
174 		if (makeCurrent == true) {
175 			courseService.setCurrentCourseVersion(thisVerCourse.getId(),
176 					null,contextInfo);
177 		}
178 
179 		// for all draft and approved courses set the state to superseded.
180 		// we should only need to evaluated versions with sequence number
181 		// higher than previous active course. If the course you're
182 		// activating is the current course check all versions.
183 		if (thisVerPrevState.equals(DtoConstants.STATE_APPROVED)
184 				&& thisVerNewState.equals(DtoConstants.STATE_ACTIVE)) {
185 
186 			List<VersionDisplayInfo> versions =  courseService.getVersions(
187 				CourseServiceConstants.COURSE_NAMESPACE_URI, thisVerCourse
188 						.getVersionInfo().getVersionIndId(), contextInfo);
189 			Long startSeq = new Long(1);
190 
191 			if (!isCurrent && (currVerCourse.getId() != thisVerCourse.getId())) {
192 				startSeq = currVerCourse.getVersionInfo().getSequenceNumber() + 1;
193 			}
194 
195 			for (VersionDisplayInfo versionInfo : versions) {
196 				if (versionInfo.getSequenceNumber() >= startSeq) {
197 					CourseInfo otherCourse = courseService
198 							.getCourse(""+versionInfo.getId(),contextInfo);
199 					if (otherCourse.getStateKey().equals(
200 							DtoConstants.STATE_APPROVED)
201 							|| otherCourse.getStateKey().equals(
202 									DtoConstants.STATE_SUBMITTED)
203 							|| otherCourse.getStateKey().equals(
204 									DtoConstants.STATE_DRAFT)) {
205 						otherCourse.setStateKey(DtoConstants.STATE_SUPERSEDED);
206 						courseService.updateCourse(otherCourse.getId(),otherCourse,contextInfo);
207 						updateStatementTreeViewInfoState(otherCourse,contextInfo);
208 					}
209 				}
210 			}
211 		}
212 
213 	}
214 
215 	public void setCourseService(CourseService courseService) {
216 		this.courseService = courseService;
217 	}
218 
219 	/**
220 	 * This method will load all the statements in a course from the course web
221 	 * service, recursively update the state of each statement in the statement
222 	 * tree, and save the update statements back to the web service.
223 	 * 
224 	 * 
225 	 * @param courseInfo
226 	 *            The course to update (call setState() in this object to set
227 	 *            the state)
228 	 * @throws DoesNotExistException
229 	 * @throws InvalidParameterException
230 	 * @throws MissingParameterException
231 	 * @throws OperationFailedException
232 	 * @throws PermissionDeniedException
233 	 * @throws DataValidationErrorException
234 	 * @throws CircularReferenceException
235 	 * @throws VersionMismatchException
236 	 */
237 	public void updateStatementTreeViewInfoState(CourseInfo courseInfo,ContextInfo contextInfo)
238 			throws DoesNotExistException, InvalidParameterException,
239 			MissingParameterException, OperationFailedException,
240 			PermissionDeniedException, DataValidationErrorException,
241 			CircularReferenceException, VersionMismatchException {
242 
243 		// Call course web service to get all requirements/statements for this
244 		// course
245 		List<StatementTreeViewInfo> statementTreeViewInfos = courseService
246 				.getCourseStatements(courseInfo.getId(), null, null,contextInfo);
247 
248 		if (statementTreeViewInfos != null){
249 			// Recursively update state on all requirements/statements in the tree
250 			for (Iterator<StatementTreeViewInfo> it = statementTreeViewInfos
251 					.iterator(); it.hasNext();)
252 				StatementUtil.updateStatementTreeViewInfoState(courseInfo
253 						.getStateKey(), it.next());
254 	
255 			// Call the course web service and update the requirement/statement tree
256 			// with the new state
257 			for (Iterator<StatementTreeViewInfo> it = statementTreeViewInfos
258 					.iterator(); it.hasNext();)
259 				courseService.updateCourseStatement(courseInfo.getId(),null, it.next(),contextInfo);
260 		}
261 	}
262 
263 }