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
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
73 ProposalInfo copiedProposal = copyProposal(originalProposalId, documentType, contextInfo);
74
75
76 Data data = courseProposalDataService.getData(copiedProposal.getId(), contextInfo);
77
78
79 return courseProposalDataService.saveData(data, contextInfo);
80 }
81
82 private CourseInfo copyCourse(String originalCluId, ContextInfo contextInfo) throws Exception {
83
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
91 ProposalInfo originalProposal = proposalService.getProposal(originalProposalId, ContextUtils.getContextInfo());
92
93
94 String originalCluId = originalProposal.getProposalReference().get(0);
95 CourseInfo copiedCourse = copyCourse(originalCluId, contextInfo);
96
97
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
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
119 for (CourseJointInfo joint : course.getJoints()) {
120 joint.setRelationId(null);
121 }
122
123 for (LoDisplayInfo lo : course.getCourseSpecificLOs()) {
124 resetLoRecursively(lo);
125 }
126
127 for (FormatInfo format : course.getFormats()) {
128 format.setId(null);
129 for (ActivityInfo activity : format.getActivities()) {
130 activity.setId(null);
131 }
132 }
133
134 course.getCreditOptions().clear();
135
136 for (CourseCrossListingInfo crossListing : course.getCrossListings()) {
137 crossListing.setId(null);
138 }
139
140 for (AffiliatedOrgInfo orgInfo : course.getExpenditure().getAffiliatedOrgs()) {
141 orgInfo.setId(null);
142 }
143
144 for (CourseFeeInfo fee : course.getFees()) {
145 fee.setId(null);
146 }
147
148 for (CourseRevenueInfo revenue : course.getRevenues()) {
149 revenue.setId(null);
150 for (AffiliatedOrgInfo orgInfo : revenue.getAffiliatedOrgs()) {
151 orgInfo.setId(null);
152 }
153 }
154
155 for (CourseVariationInfo variation : course.getVariations()) {
156 variation.setId(null);
157 }
158 }
159
160 private void resetLoRecursively(LoDisplayInfo lo) {
161
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
172 for (StatementTreeViewInfo statementTreeView : statementTreeViews) {
173 clearStatementTreeViewIdsRecursively(statementTreeView, newState, cluService, contextInfo);
174 }
175 }
176
177
178
179
180
181
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
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
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
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
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
227 List<StatementTreeViewInfo> statementTreeViews = courseService.getCourseStatements(originalCluId, null, null,
228 contextInfo);
229
230
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
250
251 if (newState == null) {
252 newState = originalCourse.getStateKey();
253 }
254
255 originalCourse.setId(newCluId);
256 originalCourse.setStateKey(newState);
257 originalCourse.setPilotCourse(false);
258
259
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 }