View Javadoc
1   package org.kuali.student.lum.lu.ui.course.server.gwt;
2   
3   import java.util.List;
4   
5   import org.apache.commons.beanutils.PropertyUtils;
6   import org.kuali.student.common.ui.client.service.DataSaveResult;
7   import org.kuali.student.common.ui.server.gwt.DataService;
8   import org.kuali.student.r1.common.assembly.data.Data;
9   import org.kuali.student.r1.core.statement.dto.ReqCompFieldInfo;
10  import org.kuali.student.r1.core.statement.dto.ReqComponentInfo;
11  import org.kuali.student.r1.core.statement.dto.StatementTreeViewInfo;
12  import org.kuali.student.r1.core.statement.service.StatementService;
13  import org.kuali.student.r1.lum.statement.typekey.ReqComponentFieldTypes;
14  import org.kuali.student.r2.common.dto.ContextInfo;
15  import org.kuali.student.r2.common.dto.DtoConstants;
16  import org.kuali.student.r2.common.exceptions.AlreadyExistsException;
17  import org.kuali.student.r2.common.exceptions.CircularRelationshipException;
18  import org.kuali.student.r2.common.exceptions.DataValidationErrorException;
19  import org.kuali.student.r2.common.exceptions.DependentObjectsExistException;
20  import org.kuali.student.r2.common.exceptions.DoesNotExistException;
21  import org.kuali.student.r2.common.exceptions.InvalidParameterException;
22  import org.kuali.student.r2.common.exceptions.MissingParameterException;
23  import org.kuali.student.r2.common.exceptions.OperationFailedException;
24  import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
25  import org.kuali.student.r2.common.exceptions.UnsupportedActionException;
26  import org.kuali.student.r2.common.exceptions.VersionMismatchException;
27  import org.kuali.student.common.util.security.ContextUtils;
28  import org.kuali.student.r2.core.proposal.dto.ProposalInfo;
29  import org.kuali.student.r2.core.proposal.service.ProposalService;
30  import org.kuali.student.r2.lum.clu.dto.AffiliatedOrgInfo;
31  import org.kuali.student.r2.lum.clu.dto.CluSetInfo;
32  import org.kuali.student.r2.lum.clu.service.CluService;
33  import org.kuali.student.r2.lum.course.dto.ActivityInfo;
34  import org.kuali.student.r2.lum.course.dto.CourseCrossListingInfo;
35  import org.kuali.student.r2.lum.course.dto.CourseFeeInfo;
36  import org.kuali.student.r2.lum.course.dto.CourseInfo;
37  import org.kuali.student.r2.lum.course.dto.CourseJointInfo;
38  import org.kuali.student.r2.lum.course.dto.CourseRevenueInfo;
39  import org.kuali.student.r2.lum.course.dto.CourseVariationInfo;
40  import org.kuali.student.r2.lum.course.dto.FormatInfo;
41  import org.kuali.student.r2.lum.course.dto.LoDisplayInfo;
42  import org.kuali.student.r2.lum.course.service.CourseService;
43  import org.slf4j.Logger;
44  import org.slf4j.LoggerFactory;
45  import org.springframework.transaction.annotation.Transactional;
46  
47  @Transactional(noRollbackFor = {DoesNotExistException.class}, rollbackFor = {Throwable.class})
48  public class CopyCourseServiceImpl {
49      private static final Logger LOG = LoggerFactory.getLogger(CopyCourseServiceImpl.class);
50  
51      private DataService courseDataService;
52      private DataService courseProposalDataService;
53      private CourseService courseService;
54      private CluService cluService;
55      private StatementService statementService;
56      private ProposalService proposalService;
57  
58      private String defaultState = DtoConstants.STATE_DRAFT;
59  
60      private List<String> ignoreProperties;
61  
62      public DataSaveResult createCopyCourse(String originalCluId, ContextInfo contextInfo) throws Exception {
63          //Copy the course and use the data service to return
64          CourseInfo copiedCourse = copyCourse(originalCluId, contextInfo);
65  
66          DataSaveResult result = new DataSaveResult();
67          result.setValue(courseDataService.getData(copiedCourse.getId(), contextInfo));
68          return result;
69      }
70  
71      public DataSaveResult createCopyCourseProposal(String originalProposalId, String documentType, ContextInfo contextInfo) throws Exception {
72          //Copy the proposal and use the data service to return
73          ProposalInfo copiedProposal = copyProposal(originalProposalId, documentType, contextInfo);
74  
75          //Grab the data object so it is transformed
76          Data data = courseProposalDataService.getData(copiedProposal.getId(), contextInfo);
77  
78          //Save it so that it goes through the filters and creates workflow
79          return courseProposalDataService.saveData(data, contextInfo);
80      }
81  
82      private CourseInfo copyCourse(String originalCluId, ContextInfo contextInfo) throws Exception {
83          //Copy the course
84          return copyCourse(originalCluId, null, defaultState, ignoreProperties, statementService, cluService,
85                  courseService, contextInfo);
86      }
87  
88      private ProposalInfo copyProposal(String originalProposalId, String documentType, ContextInfo contextInfo) throws Exception {
89          try {
90              //Get the original Proposal
91              ProposalInfo originalProposal = proposalService.getProposal(originalProposalId, ContextUtils.getContextInfo());
92  
93              //Copy the course from the original Proposal
94              String originalCluId = originalProposal.getProposalReference().get(0);
95              CourseInfo copiedCourse = copyCourse(originalCluId, contextInfo);
96  
97              //Clear ids and set the reference to the copied course
98              originalProposal.setId(null);
99              originalProposal.setWorkflowId(null);
100             originalProposal.setState(defaultState);
101             originalProposal.setType(documentType);
102             originalProposal.getProposalReference().set(0, copiedCourse.getId());
103             originalProposal.getProposerOrg().clear();
104             originalProposal.getProposerPerson().clear();
105             originalProposal.setName(null);
106 
107             //Create the proposal
108 
109             return proposalService.createProposal(documentType, originalProposal, ContextUtils.getContextInfo());
110 
111         } catch (Exception e) {
112             LOG.error(String.format("Error copying proposal id: %s", originalProposalId), e);
113             throw e;
114         }
115     }
116 
117     protected void resetIds(CourseInfo course) {
118         //Clear/Reset Joint info ids
119         for (CourseJointInfo joint : course.getJoints()) {
120             joint.setRelationId(null);
121         }
122         //Clear Los
123         for (LoDisplayInfo lo : course.getCourseSpecificLOs()) {
124             resetLoRecursively(lo);
125         }
126         //Clear format/activity ids
127         for (FormatInfo format : course.getFormats()) {
128             format.setId(null);
129             for (ActivityInfo activity : format.getActivities()) {
130                 activity.setId(null);
131             }
132         }
133         //Clear credit options
134         course.getCreditOptions().clear();
135         //Clear cross listing ids
136         for (CourseCrossListingInfo crossListing : course.getCrossListings()) {
137             crossListing.setId(null);
138         }
139         //Clear Expenditures
140         for (AffiliatedOrgInfo orgInfo : course.getExpenditure().getAffiliatedOrgs()) {
141             orgInfo.setId(null);
142         }
143         //Clear Fees
144         for (CourseFeeInfo fee : course.getFees()) {
145             fee.setId(null);
146         }
147         //Clear revenue
148         for (CourseRevenueInfo revenue : course.getRevenues()) {
149             revenue.setId(null);
150             for (AffiliatedOrgInfo orgInfo : revenue.getAffiliatedOrgs()) {
151                 orgInfo.setId(null);
152             }
153         }
154         //Clear variation ids
155         for (CourseVariationInfo variation : course.getVariations()) {
156             variation.setId(null);
157         }
158     }
159 
160     private void resetLoRecursively(LoDisplayInfo lo) {
161         //Clear out all the Lo ids recursively
162         lo.getLoInfo().setId(null);
163         for (LoDisplayInfo nestedLo : lo.getLoDisplayInfoList()) {
164             resetLoRecursively(nestedLo);
165         }
166     }
167 
168     private void clearStatementTreeViewIds(
169             List<StatementTreeViewInfo> statementTreeViews, String newState, CluService cluService,
170             ContextInfo contextInfo) throws OperationFailedException {
171         //Clear out all statement ids recursively
172         for (StatementTreeViewInfo statementTreeView : statementTreeViews) {
173             clearStatementTreeViewIdsRecursively(statementTreeView, newState, cluService, contextInfo);
174         }
175     }
176 
177     /**
178      * Clears out ids recursively and also copies adhock clusets
179      * @param statementTreeView
180      * @param cluService
181      * @throws OperationFailedException
182      */
183     private void clearStatementTreeViewIdsRecursively(StatementTreeViewInfo statementTreeView, String newState,
184             CluService cluService, ContextInfo contextInfo) throws OperationFailedException {
185         statementTreeView.setId(null);
186         statementTreeView.setState(newState);
187 
188         //clear out all the nested requirement components
189         for (ReqComponentInfo reqComp : statementTreeView.getReqComponents()) {
190             reqComp.setId(null);
191             reqComp.setState(newState);
192             for (ReqCompFieldInfo field : reqComp.getReqCompFields()) {
193                 field.setId(null);
194                 //copy any clusets that are adhoc'd and set the field value to the new cluset
195                 if (ReqComponentFieldTypes.COURSE_CLUSET_KEY.getId().equals(field.getType()) ||
196                         ReqComponentFieldTypes.PROGRAM_CLUSET_KEY.getId().equals(field.getType()) ||
197                         ReqComponentFieldTypes.CLUSET_KEY.getId().equals(field.getType())) {
198                     try {
199                         CluSetInfo cluSet = cluService.getCluSet(field.getValue(), contextInfo);
200                         cluSet.setId(null);
201                         cluSet.setStateKey(newState);
202                         //Clear clu ids if membership info exists, they will be re-added based on membership info 
203                         if (cluSet.getMembershipQuery() != null) {
204                             cluSet.getCluIds().clear();
205                             cluSet.getCluSetIds().clear();
206                         }
207                         cluSet = cluService.createCluSet(cluSet.getTypeKey(), cluSet, contextInfo);
208                         field.setValue(cluSet.getId());
209                     } catch (Exception e) {
210                         throw new OperationFailedException("Error copying clusets.", e);
211                     }
212                 }
213 
214             }
215         }
216         //recurse through nested statements
217         for (StatementTreeViewInfo child : statementTreeView.getStatements()) {
218             clearStatementTreeViewIdsRecursively(child, newState, cluService, contextInfo);
219         }
220     }
221 
222     protected void copyStatements(String originalCluId, String newCluId, String newState,
223             StatementService statementService, CluService cluService, CourseService courseService,
224             ContextInfo contextInfo) throws OperationFailedException, DoesNotExistException, InvalidParameterException,
225             MissingParameterException, PermissionDeniedException, DataValidationErrorException {
226         //Get the course statements
227         List<StatementTreeViewInfo> statementTreeViews = courseService.getCourseStatements(originalCluId, null, null,
228                 contextInfo);
229 
230         //Clear out the ids and create causing a copy to be made
231         if (statementTreeViews != null) {
232             clearStatementTreeViewIds(statementTreeViews, newState, cluService, contextInfo);
233 
234             for (StatementTreeViewInfo statementTreeView : statementTreeViews) {
235                 courseService.createCourseStatement(newCluId, statementTreeView, contextInfo);
236             }
237         }
238     }
239 
240     protected CourseInfo copyCourse(String originalCluId, String newCluId, String newState,
241             List<String> ignoreProperties, StatementService statementService, CluService cluService,
242             CourseService courseService, ContextInfo contextInfo) throws DoesNotExistException,
243             InvalidParameterException, MissingParameterException, OperationFailedException, PermissionDeniedException,
244             AlreadyExistsException, DataValidationErrorException, VersionMismatchException,
245             CircularRelationshipException, DependentObjectsExistException, UnsupportedActionException {
246         CourseInfo originalCourse = courseService.getCourse(originalCluId, contextInfo);
247         resetIds(originalCourse);
248         originalCourse.setCourseTitle("Copy of " + originalCourse.getCourseTitle());
249         //Default the newState to the existing course state if no state was set.
250         //State should never be null
251         if (newState == null) {
252             newState = originalCourse.getStateKey();
253         }
254 
255         originalCourse.setId(newCluId);
256         originalCourse.setStateKey(newState);
257         originalCourse.setPilotCourse(false);
258 
259         //Loop through the ignore properties and null out the values
260         if (ignoreProperties != null) {
261             for (String property : ignoreProperties) {
262                 try {
263                     PropertyUtils.setProperty(originalCourse, property, null);
264                 } catch (Exception e) {
265                     throw new InvalidParameterException("Ignore property is invalid and is causing an exception.",e);
266                 }
267             }
268         }
269 
270         CourseInfo newCourse = courseService.createCourse(originalCourse, contextInfo);
271         copyStatements(originalCluId, newCourse.getId(), newState, statementService, cluService, courseService,
272                 contextInfo);
273         return newCourse;
274     }
275 
276     public void setCourseService(CourseService courseService) {
277         this.courseService = courseService;
278     }
279 
280     public void setCluService(CluService cluService) {
281         this.cluService = cluService;
282     }
283 
284     public void setStatementService(StatementService statementService) {
285         this.statementService = statementService;
286     }
287 
288     public void setProposalService(ProposalService proposalService) {
289         this.proposalService = proposalService;
290     }
291 
292     public void setCourseDataService(DataService courseDataService) {
293         this.courseDataService = courseDataService;
294     }
295 
296     public void setCourseProposalDataService(DataService courseProposalDataService) {
297         this.courseProposalDataService = courseProposalDataService;
298     }
299 
300     public void setDefaultState(String defaultState) {
301         this.defaultState = defaultState;
302     }
303 
304     public void setIgnoreProperties(List<String> ignoreProperties) {
305         this.ignoreProperties = ignoreProperties;
306     }
307 
308 }