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