View Javadoc

1   package org.kuali.student.lum.program.server;
2   
3   import java.util.List;
4   
5   import org.kuali.student.lum.common.server.StatementUtil;
6   import org.kuali.student.r2.core.versionmanagement.dto.VersionDisplayInfo;
7   import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
8   import org.kuali.student.r2.common.dto.DtoConstants;
9   import org.kuali.student.r2.common.exceptions.DoesNotExistException;
10  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
11  import org.kuali.student.r2.common.util.ContextUtils;
12  import org.kuali.student.r2.common.util.constants.ProgramServiceConstants;
13  import org.kuali.student.r2.lum.program.dto.CredentialProgramInfo;
14  import org.kuali.student.r2.lum.program.dto.ProgramRequirementInfo;
15  import org.kuali.student.r2.lum.program.service.ProgramService;
16  import org.springframework.transaction.annotation.Transactional;
17  
18  /**
19   * This class is called whenever the state of a major discipline changes.
20   * <p>
21   * We have a separate class because the operations need to be marked with the @Transactional annotation.
22   * <p>
23   * THIS CLASS IS DUPLICATED FOR MAJOR DISCIPLINE, CORE, AND CREDENTIAL PROGRAMS SINCE THERE ARE DIFFERENT SERVICE METHODS FOR
24   * EACH OF THESE TYPES (THOUGH THEY ARE SIMILAR)
25   * <P>
26   * 
27   * @author Kuali Rice Team (kuali-rice@googlegroups.com)
28   */
29  @Transactional(noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
30  public class CredentialProgramStateChangeServiceImpl implements StateChangeService {
31  
32      /**
33       * The program service - injected by spring.
34       */
35      private ProgramService programService;
36  
37      /**
38       * This method is called by workflow when the state changes.
39       * 
40       * @param majorDisciplineId
41       * @param state
42       * @return
43       * @throws Exception
44       */
45      public void changeState(String credentialProgramId, String newState) throws Exception {
46          // This method will be called from workflow.
47          // Since we cannot activate a program from the workflow we do not need to add endEntryTerm and endEnrollTerm
48          changeState(null, null, null, credentialProgramId, newState);
49      }
50  
51      /**
52       * This method is called from the UI (servlet) when state changes.
53       * 
54       * @param endEntryTerm
55       * @param endEnrollTerm
56       * @param programType
57       * @param majorDisciplineId
58       * @param newState
59       * @return
60       * @throws Exception
61       */
62      public void changeState(String endEntryTerm, String endEnrollTerm, String endInstAdmitTerm, String credentialProgramId, String newState) throws Exception {
63  
64          // New state must not be null
65          if (newState == null)
66              throw new InvalidParameterException("new state cannot be null");
67  
68          // The version selected in the UI
69          CredentialProgramInfo selectedVersion = programService.getCredentialProgram(credentialProgramId,ContextUtils.getContextInfo());
70  
71          // If we are activating this version we need to mark the previous version superseded,
72          // update the previous version end terms, and make the selected version current.
73          if (newState.equals(DtoConstants.STATE_ACTIVE)) {
74  
75              // Update previous versions to superseded and set end terms on previous current version.
76          	updatePreviousVersions(selectedVersion, endEntryTerm, endEnrollTerm, endInstAdmitTerm);
77          	
78              // Update state of all associated objects for current version
79              // NOTE: we must update state BEFORE making the version current
80              updateCredentialProgramInfoState(selectedVersion, newState);
81  
82              // Make this the current version
83              makeCurrent(selectedVersion);
84          } else {
85  
86              // Update state of all associated objects for current version
87              updateCredentialProgramInfoState(selectedVersion, newState);
88          }
89  
90      }
91  
92      /**
93       * This method finds all previous versions of program and sets all previous ACTIVE,APPROVED,DRAFT versions to SUPERSEDED and
94       * sets new end terms for previous current version.
95   
96       * @param selectedVersion The version of credential  program being activated
97       * @param endEntryTerm The new end entry term to set on previous active version
98       * @param endEnrollTerm The new end enroll term to set on previous active version
99       * @throws Exception
100      */
101     private void updatePreviousVersions (CredentialProgramInfo selectedVersion, String endEntryTerm, String endEnrollTerm, String endInstAdmitTerm) throws Exception {
102     	// Get the current version of major discipline given the selected version
103     	CredentialProgramInfo currentVersion = getCurrentVersion(selectedVersion);
104     	
105     	boolean isSelectedVersionCurrent = selectedVersion.getId().equals(currentVersion.getId());
106     	
107     	//Set the end terms on the current version of major discipline and update it's state to superseded
108     	setEndTerms(currentVersion, endEntryTerm, endEnrollTerm);
109     	updateCredentialProgramInfoState(currentVersion, DtoConstants.STATE_SUPERSEDED);
110 
111 		// Loop through all previous active or approved programs and set the state to superseded.
112 		// We should only need to evaluated versions with sequence number
113 		// higher than previous active program
114 
115 		List<VersionDisplayInfo> versions = programService.getVersions(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI,
116 		selectedVersion.getVersionInfo(ContextUtils.getContextInfo()).getVersionIndId(),ContextUtils.getContextInfo());
117 		Long startSeq = new Long(1);
118 
119 		if (!isSelectedVersionCurrent) {
120 			startSeq = currentVersion.getVersionInfo(ContextUtils.getContextInfo()).getSequenceNumber() + 1;
121 		}
122 
123 		for (VersionDisplayInfo versionInfo : versions) {
124 			boolean isVersionNewerThanCurrentVersion = versionInfo.getSequenceNumber() >= startSeq;
125 			boolean isVersionSelectedVersion = versionInfo.getSequenceNumber().equals(selectedVersion.getVersionInfo(ContextUtils.getContextInfo()).getSequenceNumber());  
126 			boolean updateState = isVersionNewerThanCurrentVersion && !isVersionSelectedVersion;
127 			if (updateState) {
128 				CredentialProgramInfo otherProgram = programService.getCredentialProgram(versionInfo.getId(),ContextUtils.getContextInfo());
129 				if (otherProgram.getStateKey().equals(DtoConstants.STATE_APPROVED) ||
130 					otherProgram.getStateKey().equals(DtoConstants.STATE_ACTIVE)){
131 			        updateCredentialProgramInfoState(otherProgram, DtoConstants.STATE_SUPERSEDED);
132 				}		
133 			}
134 		}    	
135 
136     }
137     
138 	/**
139 	 * Get the current version of program given the selected version of program
140 	 * 
141 	 * @param verIndId
142 	 */
143 	protected CredentialProgramInfo getCurrentVersion(CredentialProgramInfo credentialProgramInfo)
144 			throws Exception {
145 		// Get version independent id of program
146 		String verIndId = credentialProgramInfo.getVersionInfo(ContextUtils.getContextInfo()).getVersionIndId();
147 
148 		// Get id of current version of program given the version independent id
149 		VersionDisplayInfo curVerDisplayInfo = programService.getCurrentVersion( ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI, verIndId,ContextUtils.getContextInfo());
150 		String curVerId = curVerDisplayInfo.getId();
151 
152 		// Return the current version of the course
153 		CredentialProgramInfo currentVersion = programService.getCredentialProgram(curVerId,ContextUtils.getContextInfo());
154 
155 		return currentVersion;
156 	}
157     
158     /**
159      * This method updates the end terms for the major discipline passed into it.
160      * <p>
161      * You must still call updateState() to save the object using the web service.
162      * 
163      * @param credentialProgramInfo
164      * @param endEntryTerm
165      * @param endEnrollTerm
166      */
167     private void setEndTerms(CredentialProgramInfo credentialProgramInfo, String endEntryTerm, String endEnrollTerm) {
168         credentialProgramInfo.setEndProgramEntryTerm(endEntryTerm);
169         credentialProgramInfo.setEndTerm(endEnrollTerm);
170     }
171 
172     /**
173      * This method will update the state of this object and all associated objects.
174      * <p>
175      * It is needed because we need to make separate web service calls to update the state of these objects.
176      * 
177      * @param credentialProgramInfo
178      * @param newState
179      */
180     private void updateCredentialProgramInfoState(CredentialProgramInfo credentialProgramInfo, String newState) throws Exception {
181         // Update the statement tree
182         List<String> programRequirementIds = credentialProgramInfo.getProgramRequirements();
183         updateRequirementsState(programRequirementIds, newState);
184  
185         // Credential and core programs do not have variations
186         
187         // Update program
188         credentialProgramInfo.setStateKey(newState);
189         programService.updateCredentialProgram(credentialProgramInfo.getId(), credentialProgramInfo, ContextUtils.getContextInfo());
190     }
191 
192     /**
193      * This method will make this version of the major discipline the current one.
194      * 
195      * @param credentialProgramInfo
196      */
197     private void makeCurrent(CredentialProgramInfo credentialProgramInfo) throws Exception {
198 
199         // Check if this is the current version before trying to make it current
200         // (the web service will error if you try to make a version current that is already current)
201         VersionDisplayInfo currentVersion = programService.getCurrentVersion(ProgramServiceConstants.PROGRAM_NAMESPACE_MAJOR_DISCIPLINE_URI, credentialProgramInfo.getVersionInfo(ContextUtils.getContextInfo()).getVersionIndId(),ContextUtils.getContextInfo());
202 
203         // If this is not the current version, then make it current
204         if (!currentVersion.getSequenceNumber().equals(credentialProgramInfo.getVersionInfo(ContextUtils.getContextInfo()).getSequenceNumber())) {
205             programService.setCurrentCredentialProgramVersion(credentialProgramInfo.getId(), null,ContextUtils.getContextInfo());
206         }
207     }
208 
209     /**
210      * This method will update the requirement state.
211      * <p>
212      * Note that it uses StatementUtil to update the statement tree.
213      * 
214      * @param credentialProgramInfo
215      * @param newState
216      * @throws Exception
217      */
218     public void updateRequirementsState(List<String> programRequirementIds, String newState) throws Exception {
219         
220         for (String programRequirementId : programRequirementIds) {
221 
222             // Get program requirement from the program service
223             ProgramRequirementInfo programRequirementInfo = null;
224             programRequirementInfo = programService.getProgramRequirement(programRequirementId, ContextUtils.getContextInfo());
225 
226             // Look in the requirement for the statement tree
227             StatementTreeViewInfo statementTree = programRequirementInfo.getStatement();
228 
229             // And recursively update the entire tree with the new state
230             StatementUtil.updateStatementTreeViewInfoState(newState, statementTree);
231 
232             // Update the state of the requirement object
233             programRequirementInfo.setStateKey(newState);
234 
235             // The write the requirement back to the program service
236             programService.updateProgramRequirement(programRequirementInfo.getId(), programRequirementInfo.getTypeKey(), programRequirementInfo, ContextUtils.getContextInfo());
237 
238         }
239     }
240 
241     /**
242      * This method is used by Spring to inject the program service into this bean.
243      * 
244      * @param programService
245      */
246     public void setProgramService(ProgramService programService) {
247         this.programService = programService;
248     }
249 
250 }