1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.lum.lu.assembly;
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.log4j.Logger;
25 import org.kuali.student.lum.common.client.lo.MetaInfoHelper;
26 import org.kuali.student.lum.common.client.widgets.CluSetHelper;
27 import org.kuali.student.lum.common.client.widgets.CluSetRangeHelper;
28 import org.kuali.student.lum.common.client.widgets.CluSetRangeModelUtil;
29 import org.kuali.student.r1.common.assembly.data.AssemblyException;
30 import org.kuali.student.r1.common.assembly.data.Data;
31 import org.kuali.student.r1.common.assembly.data.Data.Property;
32 import org.kuali.student.r1.common.assembly.data.Metadata;
33 import org.kuali.student.r1.common.assembly.dictionary.MetadataServiceImpl;
34 import org.kuali.student.r1.common.assembly.old.BaseAssembler;
35 import org.kuali.student.r1.common.assembly.old.data.SaveResult;
36 import org.kuali.student.r2.common.dto.AttributeInfo;
37 import org.kuali.student.r2.common.dto.MetaInfo;
38 import org.kuali.student.r2.common.dto.RichTextInfo;
39 import org.kuali.student.r2.common.dto.ValidationResultInfo;
40 import org.kuali.student.r2.common.exceptions.DoesNotExistException;
41 import org.kuali.student.r2.common.exceptions.InvalidParameterException;
42 import org.kuali.student.r2.common.exceptions.MissingParameterException;
43 import org.kuali.student.r2.common.exceptions.OperationFailedException;
44 import org.kuali.student.r2.common.exceptions.PermissionDeniedException;
45 import org.kuali.student.r2.common.infc.ValidationResult.ErrorLevel;
46 import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
47 import org.kuali.student.r2.core.search.dto.SearchResultCellInfo;
48 import org.kuali.student.r2.core.search.dto.SearchResultInfo;
49 import org.kuali.student.r2.core.search.dto.SearchResultRowInfo;
50 import org.kuali.student.r2.common.util.ContextUtils;
51 import org.kuali.student.r2.core.versionmanagement.dto.VersionDisplayInfo;
52 import org.kuali.student.r2.lum.clu.dto.CluInfo;
53 import org.kuali.student.r2.lum.clu.dto.CluSetInfo;
54 import org.kuali.student.r2.lum.clu.dto.MembershipQueryInfo;
55 import org.kuali.student.r2.lum.clu.service.CluService;
56 import org.kuali.student.r2.lum.util.constants.CluServiceConstants;
57 import org.springframework.transaction.annotation.Transactional;
58
59 @Transactional(readOnly=true,rollbackFor={Throwable.class})
60 public class CluSetManagementAssembler extends BaseAssembler<Data, Void> {
61
62
63 final Logger LOG = Logger.getLogger(CluSetManagementAssembler.class);
64
65 public static final String JOINT_RELATION_TYPE = "kuali.lu.relation.type.co-located";
66
67 public static final String FORMAT_LU_TYPE = "kuali.lu.type.CreditCourseFormatShell";
68
69 public static final String FORMAT_RELATION_TYPE = "luLuRelationType.hasCourseFormat";
70 public static final String ACTIVITY_RELATION_TYPE = "luLuRelationType.contains";
71
72 public static final String PROPOSAL_REFERENCE_TYPE = "kuali.proposal.referenceType.clu";
73
74 public static final String CLUSET_DATA_TYPE = "cluset";
75
76 private CluService cluService;
77 private MetadataServiceImpl metadataService;
78
79 public MetadataServiceImpl getMetadataService() {
80 return metadataService;
81 }
82
83 public void setMetadataService(MetadataServiceImpl metadataService) {
84 this.metadataService = metadataService;
85 }
86
87 @Override
88 public Data get(String id) throws AssemblyException {
89
90 CluSetHelper resultCluSetHelper = null;
91 Data resultData = null;
92
93 try {
94 CluSetInfo cluSetInfo = getCluSetInfo(id);
95 resultCluSetHelper = toCluSetHelper(cluSetInfo);
96 if (resultCluSetHelper == null) {
97 resultData = null;
98 } else {
99
100
101 resultData = resultCluSetHelper.getData();
102 }
103 } catch (Exception e) {
104 throw new AssemblyException("Could not retrive cluSet with id " + id, e);
105 }
106
107 return resultData;
108 }
109
110 public CluSetInfo getCluSetInfo(String cluSetId) throws Exception {
111 List<String> cluIds = null;
112 CluSetInfo cluSetInfo = null;
113
114
115
116 cluSetInfo = cluService.getCluSet(cluSetId, ContextUtils.getContextInfo());
117 cluSetInfo.setCluIds(null);
118 cluIds = cluService.getCluIdsFromCluSet(cluSetId, ContextUtils.getContextInfo());
119 cluSetInfo.setCluIds(cluIds);
120 upWrap(cluSetInfo);
121 return cluSetInfo;
122 }
123
124 public MetaInfoHelper toMetaInfoHelper(MetaInfo metaInfo) {
125 MetaInfoHelper metaInfoHelper = null;
126 Data metaData = new Data();
127 if (metaInfo == null) return null;
128 metaInfoHelper = MetaInfoHelper.wrap(metaData);
129 metaInfoHelper.setCreateId(metaInfo.getCreateId());
130 metaInfoHelper.setCreateTime(metaInfo.getCreateTime());
131 metaInfoHelper.setUpdateId(metaInfo.getUpdateId());
132 metaInfoHelper.setUpdateTime(metaInfo.getUpdateTime());
133 metaInfoHelper.setVersionInd(metaInfo.getVersionInd());
134 return metaInfoHelper;
135 }
136
137 public MetaInfo toMetaInfo(MetaInfoHelper metaInfoHelper) {
138 MetaInfo metaInfo = null;
139 if (metaInfoHelper == null) return null;
140 metaInfo = new MetaInfo();
141 metaInfo.setCreateId(metaInfoHelper.getCreateId());
142 metaInfo.setCreateTime(metaInfoHelper.getCreateTime());
143 metaInfo.setUpdateId(metaInfoHelper.getUpdateId());
144 metaInfo.setUpdateTime(metaInfoHelper.getUpdateTime());
145 metaInfo.setVersionInd(metaInfoHelper.getVersionInd());
146 return metaInfo;
147 }
148
149 public String richTextToString(RichTextInfo richTextInfo) {
150 String result = null;
151 if (richTextInfo == null) return null;
152 result = richTextInfo.getPlain();
153 return result;
154 }
155
156 @Override
157 @Transactional(readOnly=false,noRollbackFor={DoesNotExistException.class},rollbackFor={Throwable.class})
158 public SaveResult<Data> save(Data input) throws AssemblyException {
159
160 try {
161 SaveResult<Data> result = new SaveResult<Data>();
162 List<ValidationResultInfo> validationResults = validate(input);
163 if (hasValidationErrors(validationResults)) {
164 result.setValidationResults(validationResults);
165 result.setValue(input);
166 return result;
167 }
168
169 SaveResult<Data> clusetResult = saveCluSet(input);
170 result.setValidationResults(clusetResult.getValidationResults());
171 result.setValue(clusetResult.getValue());
172 return result;
173 } catch (Exception e) {
174 throw new AssemblyException("Unable to save ....", e);
175 }
176 }
177
178 private void upWrap(CluSetInfo cluSetInfo) throws AssemblyException {
179 List<String> cluSetIds = (cluSetInfo == null)? null : cluSetInfo.getCluSetIds();
180 List<String> unWrappedCluSetIds = null;
181 List<CluSetInfo> wrappedCluSets = null;
182 List<CluSetInfo> subCluSets = null;
183
184 try {
185 if (cluSetIds != null && !cluSetIds.isEmpty()) {
186 subCluSets = cluService.getCluSetsByIds(cluSetIds, ContextUtils.getContextInfo());
187 }
188 } catch (Exception e) {
189 LOG.error(e.getMessage(), e);
190 throw new AssemblyException("Failed to retrieve the sub clusets of cluset " +
191 cluSetInfo.getId());
192 }
193
194 if (subCluSets != null) {
195 for (CluSetInfo subCluSet : subCluSets) {
196 if (subCluSet.getIsReusable()) {
197 unWrappedCluSetIds = (unWrappedCluSetIds == null)?
198 new ArrayList<String>() : unWrappedCluSetIds;
199 unWrappedCluSetIds.add(subCluSet.getId());
200 } else {
201 wrappedCluSets = (wrappedCluSets == null)?
202 new ArrayList<CluSetInfo>() : wrappedCluSets;
203 wrappedCluSets.add(subCluSet);
204 }
205 }
206 }
207 cluSetInfo.setCluSetIds(unWrappedCluSetIds);
208 if (wrappedCluSets != null) {
209 for (CluSetInfo wrappedCluSet : wrappedCluSets) {
210 MembershipQueryInfo mqInfo = wrappedCluSet.getMembershipQuery();
211 if (wrappedCluSet.getCluIds() != null && !wrappedCluSet.getCluIds().isEmpty()) {
212 cluSetInfo.setCluIds(wrappedCluSet.getCluIds());
213 }
214 if (mqInfo != null && mqInfo.getSearchTypeKey() != null && !mqInfo.getSearchTypeKey().isEmpty()) {
215 cluSetInfo.setMembershipQuery(mqInfo);
216 }
217 }
218 }
219 }
220
221 private void wrap(CluSetInfo cluSetInfo) throws AssemblyException {
222 int numCluSetElementTypes = 0;
223 boolean hasCluIds = false;
224 boolean hasCluSetIds = false;
225 boolean hasMembershipQuery = false;
226 List<String> wrapperCluSetIds = new ArrayList<String>();
227 MembershipQueryInfo mqInfo = null;
228 if (cluSetInfo.getCluIds() != null && !cluSetInfo.getCluIds().isEmpty()) {
229 numCluSetElementTypes++;
230 hasCluIds = true;
231 }
232 if (cluSetInfo.getCluSetIds() != null && !cluSetInfo.getCluSetIds().isEmpty()) {
233 numCluSetElementTypes++;
234 hasCluSetIds = true;
235 }
236 mqInfo = cluSetInfo.getMembershipQuery();
237 if (mqInfo != null && mqInfo.getSearchTypeKey() != null && !mqInfo.getSearchTypeKey().isEmpty()) {
238 numCluSetElementTypes++;
239 hasMembershipQuery = true;
240 }
241
242 if (numCluSetElementTypes > 1) {
243 if (hasCluIds) {
244 CluSetInfo wrapperCluSet = new CluSetInfo();
245 setWrapperCluSetInfoValues(wrapperCluSet, cluSetInfo);
246
247 wrapperCluSet.setCluIds(cluSetInfo.getCluIds());
248 cluSetInfo.setCluIds(null);
249 try {
250 if (wrapperCluSet.getTypeKey() == null) {
251 wrapperCluSet.setTypeKey("kuali.cluSet.type.CreditCourse");
252 }
253 wrapperCluSet = cluService.createCluSet(wrapperCluSet.getTypeKey(), wrapperCluSet, ContextUtils.getContextInfo());
254 } catch (Exception e) {
255 LOG.error("Failed to create wrapper cluset",e);
256 throw new AssemblyException(e);
257 }
258 wrapperCluSetIds.add(wrapperCluSet.getId());
259 }
260 if (hasMembershipQuery) {
261 CluSetInfo wrapperCluSet = new CluSetInfo();
262 setWrapperCluSetInfoValues(wrapperCluSet, cluSetInfo);
263
264 wrapperCluSet.setMembershipQuery(mqInfo);
265 cluSetInfo.setMembershipQuery(null);
266 try {
267 wrapperCluSet = cluService.createCluSet(wrapperCluSet.getTypeKey(), wrapperCluSet, ContextUtils.getContextInfo());
268 } catch (Exception e) {
269 LOG.error("Failed to create wrapper cluset",e);
270 throw new AssemblyException(e);
271 }
272 wrapperCluSetIds.add(wrapperCluSet.getId());
273 }
274 if (hasCluSetIds) {
275 wrapperCluSetIds.addAll(cluSetInfo.getCluSetIds());
276 }
277 cluSetInfo.setCluSetIds(wrapperCluSetIds);
278 }
279 }
280
281 private void setWrapperCluSetInfoValues(CluSetInfo wrapperCluSet, CluSetInfo cluSetInfo) {
282 wrapperCluSet.setAdminOrg(cluSetInfo.getAdminOrg());
283 wrapperCluSet.setEffectiveDate(cluSetInfo.getEffectiveDate());
284 wrapperCluSet.setExpirationDate(cluSetInfo.getExpirationDate());
285 wrapperCluSet.setIsReusable(false);
286 wrapperCluSet.setIsReferenceable(false);
287 wrapperCluSet.setName(cluSetInfo.getName());
288 wrapperCluSet.setStateKey(cluSetInfo.getStateKey());
289 wrapperCluSet.setTypeKey(cluSetInfo.getTypeKey());
290 }
291
292 private SaveResult<Data> saveCluSet(Data input) throws AssemblyException {
293 SaveResult<Data> result = new SaveResult<Data>();
294
295 List<ValidationResultInfo> saveValidationResults = null;
296 CluSetHelper cluSetHelper = new CluSetHelper(input);
297 CluSetInfo cluSetInfo = toCluSetInfo(cluSetHelper);
298 CluSetInfo updatedCluSetInfo = null;
299 CluSetHelper resultCluSetHelper = null;
300 Data resultData = null;
301 wrap(cluSetInfo);
302
303 if ((cluSetInfo.getCluIds() == null || cluSetInfo.getCluIds().isEmpty()) &&
304 (cluSetInfo.getCluSetIds() == null || cluSetInfo.getCluSetIds().isEmpty()) &&
305 (cluSetInfo.getMembershipQuery() == null)){
306 ValidationResultInfo cluSetCannotBeEmpty = new ValidationResultInfo();
307 saveValidationResults = (saveValidationResults == null)? new ArrayList<ValidationResultInfo>() :
308 saveValidationResults;
309 result.setValue(null);
310 cluSetCannotBeEmpty.setElement("");
311 cluSetCannotBeEmpty.setMessage("Clu set cannot be empty");
312 cluSetCannotBeEmpty.setError("Clu set cannot be empty");
313 cluSetCannotBeEmpty.setLevel(ErrorLevel.ERROR);
314 saveValidationResults.add(cluSetCannotBeEmpty);
315 result.setValidationResults(saveValidationResults);
316 return result;
317 }
318
319 if (cluSetInfo.getId() != null && cluSetInfo.getId().trim().length() > 0) {
320 try {
321 updatedCluSetInfo = cluService.updateCluSet(cluSetInfo.getId(), cluSetInfo, ContextUtils.getContextInfo());
322 } catch (Exception e) {
323 LOG.error("Failed to update cluset",e);
324 throw new AssemblyException(e);
325 }
326 } else {
327 try {
328 if (cluSetInfo.getTypeKey() == null) {
329 cluSetInfo.setTypeKey("kuali.cluSet.type.CreditCourse");
330 }
331 updatedCluSetInfo = cluService.createCluSet(cluSetInfo.getTypeKey(), cluSetInfo, ContextUtils.getContextInfo());
332 } catch (Exception e) {
333 LOG.error("Failed to create cluset",e);
334 throw new AssemblyException(e);
335 }
336 }
337 try {
338 resultCluSetHelper = toCluSetHelper(updatedCluSetInfo);
339 } catch (Exception e) {
340 throw new AssemblyException(e);
341 }
342 if (resultCluSetHelper == null) {
343 resultData = null;
344 } else {
345
346
347 resultData = resultCluSetHelper.getData();
348 }
349 result.setValue(resultData);
350 return result;
351 }
352
353 private List<String> getMembershipQuerySearchResult(MembershipQueryInfo query) throws MissingParameterException, PermissionDeniedException, OperationFailedException, InvalidParameterException {
354 if(query == null) {
355 return null;
356 }
357 SearchRequestInfo sr = new SearchRequestInfo();
358 sr.setSearchKey(query.getSearchTypeKey());
359 sr.setParams(query.getQueryParamValues());
360
361 SearchResultInfo result = cluService.search(sr, ContextUtils.getContextInfo());
362
363 List<String> cluIds = new ArrayList<String>();
364 List<SearchResultRowInfo> rows = result.getRows();
365 for(SearchResultRowInfo row : rows) {
366 List<SearchResultCellInfo> cells = row.getCells();
367 for(SearchResultCellInfo cell : cells) {
368 if(cell.getKey().equals("lu.resultColumn.cluId")) {
369 cluIds.add(cell.getValue());
370 }
371 }
372 }
373 return cluIds;
374 }
375
376 private CluSetHelper toCluSetHelper(CluSetInfo cluSetInfo) throws Exception {
377 Data data = new Data();
378 Data cluSetDetailData = new Data();
379 data.set("cluset", cluSetDetailData);
380 CluSetHelper result = CluSetHelper.wrap(cluSetDetailData);
381 if (cluSetInfo != null) {
382 if (cluSetInfo.getCluIds() != null && !cluSetInfo.getCluIds().isEmpty()) {
383 List<CluInfo> cluInfos = new ArrayList<CluInfo>();
384 for(String id:cluSetInfo.getCluIds()){
385 VersionDisplayInfo versionInfo = cluService.getCurrentVersion(CluServiceConstants.CLU_NAMESPACE_URI, id, ContextUtils.getContextInfo());
386 cluInfos.add(cluService.getClu(versionInfo.getId(), ContextUtils.getContextInfo()));
387 }
388 result.setApprovedClus(new Data());
389 for (CluInfo cluInfo : cluInfos) {
390 if (cluInfo.getStateKey().equals("Active")) {
391 result.getApprovedClus().add(cluInfo.getVersion().getVersionIndId());
392 } else {
393 result.getProposedClus().add(cluInfo.getVersion().getVersionIndId());
394 }
395 result.getAllClus().add(cluInfo.getVersion().getVersionIndId());
396 }
397 }
398 if (cluSetInfo.getCluSetIds() != null && !cluSetInfo.getCluSetIds().isEmpty()) {
399 result.setCluSets(new Data());
400 for (String cluSetId : cluSetInfo.getCluSetIds()) {
401 result.getCluSets().add(cluSetId);
402 }
403 }
404 if (cluSetInfo.getMembershipQuery() != null) {
405 MembershipQueryInfo mq = cluSetInfo.getMembershipQuery();
406 List<String> cluRangeCluIds = getMembershipQuerySearchResult(mq);
407 if (cluRangeCluIds != null) {
408 result.setCluRangeViewDetails(new Data());
409 for (String cluRangeCluId : cluRangeCluIds) {
410 result.getCluRangeViewDetails().add(cluRangeCluId);
411 }
412 }
413 }
414 result.setDescription(richTextToString(cluSetInfo.getDescr()));
415 result.setEffectiveDate(cluSetInfo.getEffectiveDate());
416 result.setExpirationDate(cluSetInfo.getExpirationDate());
417 result.setId(cluSetInfo.getId());
418 result.setMetaInfo(toMetaInfoHelper(cluSetInfo.getMeta()));
419 result.setName(cluSetInfo.getName());
420 result.setOrganization(cluSetInfo.getAdminOrg());
421 result.setState(cluSetInfo.getStateKey());
422 result.setType(cluSetInfo.getTypeKey());
423 result.setCluRangeParams(CluSetRangeModelUtil.INSTANCE.toData(
424 cluSetInfo.getMembershipQuery()));
425
426
427 for (AttributeInfo attrInfo : cluSetInfo.getAttributes()) {
428 result.getData().set(attrInfo.getKey(), attrInfo.getValue());
429 }
430 }
431 return result;
432 }
433
434 private void addToCluIds(Data clusData, final List<String> cluIds) {
435 if (clusData != null) {
436 for (Data.Property p : clusData) {
437 if(!"_runtimeData".equals(p.getKey())){
438 String cluId = p.getValue();
439 cluIds.add(cluId);
440 }
441 }
442 }
443 }
444
445 private CluSetInfo toCluSetInfo(CluSetHelper cluSetHelper) {
446 CluSetInfo cluSetInfo = new CluSetInfo();
447 Data approvedClusData = cluSetHelper.getApprovedClus();
448 Data proposedClusData = cluSetHelper.getProposedClus();
449 Data cluSetsData = cluSetHelper.getCluSets();
450 final List<String> cluIds = new ArrayList<String>();
451 List<String> cluSetIds = null;
452
453 cluSetInfo.setId(cluSetHelper.getId());
454 if (approvedClusData != null) {
455 addToCluIds(approvedClusData, cluIds);
456 }
457 if (proposedClusData != null) {
458 addToCluIds(proposedClusData, cluIds);
459 }
460 if (cluIds != null && !cluIds.isEmpty()) {
461 cluSetInfo.setCluIds(cluIds);
462 }
463 if (cluSetsData != null) {
464 for (Data.Property p : cluSetsData) {
465 if(!"_runtimeData".equals(p.getKey())){
466 String cluSetId = p.getValue();
467 cluSetIds = (cluSetIds == null)? new ArrayList<String>(3) :
468 cluSetIds;
469 cluSetIds.add(cluSetId);
470 }
471 }
472 }
473 if (cluSetIds != null) {
474 cluSetInfo.setCluSetIds(cluSetIds);
475 }
476 cluSetInfo.setAdminOrg(cluSetHelper.getOrganization());
477 cluSetInfo.setDescr(toRichTextInfo(cluSetHelper.getDescription()));
478 cluSetInfo.setEffectiveDate(cluSetHelper.getEffectiveDate());
479 cluSetInfo.setExpirationDate(cluSetHelper.getExpirationDate());
480 cluSetInfo.setMembershipQuery(toMembershipQueryInfo(cluSetHelper.getCluRangeParams()));
481
482 cluSetInfo.setMeta(toMetaInfo(cluSetHelper.getMetaInfo()));
483 cluSetInfo.setName(cluSetHelper.getName());
484 cluSetInfo.setStateKey(cluSetHelper.getState());
485 if (cluSetInfo.getStateKey() == null) {
486 cluSetInfo.setStateKey("Active");
487 }
488 cluSetInfo.setTypeKey(cluSetHelper.getType());
489 cluSetInfo.setIsReusable(cluSetHelper.getReusable());
490 cluSetInfo.setIsReferenceable(cluSetHelper.getReferenceable());
491
492
493 for(Iterator<Property> iter=cluSetHelper.getData().realPropertyIterator();iter.hasNext();){
494 Property property = iter.next();
495 if(property.getValue()!=null && !(property.getValue() instanceof Data ) && !CluSetHelper.getProperties().contains((String)property.getKey())){
496
497 cluSetInfo.getAttributes().add(new AttributeInfo((String)property.getKey(), property.getValue().toString()));
498 }
499 }
500
501 return cluSetInfo;
502 }
503
504 private MembershipQueryInfo toMembershipQueryInfo(CluSetRangeHelper cluSetRangeHelper) {
505 return CluSetRangeModelUtil.INSTANCE.toMembershipQueryInfo(cluSetRangeHelper.getData());
506 }
507
508 private RichTextInfo toRichTextInfo(String text) {
509 RichTextInfo result = new RichTextInfo();
510 if (text == null) return null;
511 result.setPlain(text);
512 result.setFormatted(text);
513 return result;
514 }
515
516 @Override
517 public Data assemble(Void input) throws AssemblyException {
518 throw new UnsupportedOperationException("Data assembly not supported");
519 }
520
521 @Override
522 public Void disassemble(Data input) throws AssemblyException {
523 throw new UnsupportedOperationException("Data disassembly not supported");
524 }
525
526 public CluService getCluService() {
527 return cluService;
528 }
529
530 public void setCluService(CluService cluService) {
531 this.cluService = cluService;
532 }
533
534 @Override
535 protected String getDataType() {
536 return CLUSET_DATA_TYPE;
537 }
538
539 @Override
540 public Metadata getDefaultMetadata() {
541
542 return metadataService.getMetadata(getDataType());
543 }
544
545 @Override
546 protected String getDocumentPropertyName() {
547 return "course";
548 }
549
550 @Override
551 protected String getDtoName() {
552 return "kuali.lu.type.CreditCourse";
553 }
554
555 @Override
556 protected Map<String,String> getQualification(String idType, String id) {
557 String DOCUMENT_TYPE_NAME = "documentTypeName";
558 Map<String,String> qualification = new LinkedHashMap<String,String>();
559 qualification.put(DOCUMENT_TYPE_NAME, "CluCreditCourse");
560
561
562
563
564
565
566 qualification.put(idType, id);
567 return qualification;
568 }
569
570 }