1 package org.kuali.student.lum.course.service.assembler;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.Map.Entry;
12
13 import org.kuali.student.common.assembly.BOAssembler;
14 import org.kuali.student.common.assembly.BaseDTOAssemblyNode;
15 import org.kuali.student.common.assembly.BaseDTOAssemblyNode.NodeOperation;
16 import org.kuali.student.common.assembly.data.AssemblyException;
17 import org.kuali.student.common.dto.DtoConstants;
18 import org.kuali.student.common.exceptions.DoesNotExistException;
19 import org.kuali.student.common.exceptions.InvalidParameterException;
20 import org.kuali.student.common.exceptions.MissingParameterException;
21 import org.kuali.student.common.exceptions.OperationFailedException;
22 import org.kuali.student.common.util.UUIDHelper;
23 import org.kuali.student.lum.course.dto.LoDisplayInfo;
24 import org.kuali.student.lum.lo.dto.LoCategoryInfo;
25 import org.kuali.student.lum.lo.dto.LoInfo;
26 import org.kuali.student.lum.lo.dto.LoLoRelationInfo;
27 import org.kuali.student.lum.lo.service.LearningObjectiveService;
28
29
30 public class LoAssembler implements BOAssembler<LoDisplayInfo, LoInfo> {
31
32 private LearningObjectiveService loService;
33
34 @Override
35 public LoDisplayInfo assemble(LoInfo lo, LoDisplayInfo loDisplayInfo,
36 boolean shallowBuild) throws AssemblyException {
37
38 LoDisplayInfo loDisplay = (null != loDisplayInfo) ? loDisplayInfo : new LoDisplayInfo();
39
40 loDisplay.setLoInfo(lo);
41
42 if (!shallowBuild) {
43 String loId = lo.getId();
44 try {
45 List<LoCategoryInfo> loCategories = loService.getLoCategoriesForLo(loId);
46 loDisplay.setLoCategoryInfoList(loCategories);
47 } catch (DoesNotExistException e) {
48 } catch (Exception e) {
49 throw new AssemblyException("Error getting learning objective categories", e);
50 }
51 try {
52 List<LoInfo> childLos = loService.getRelatedLosByLoId(loId,CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES);
53 for(LoInfo childLo:childLos){
54 LoDisplayInfo childLoDisplay = assemble(childLo, null, shallowBuild);
55 childLoDisplay.setParentLoRelationid(lo.getId());
56 childLoDisplay.setParentRelType(CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES);
57 loDisplay.getLoDisplayInfoList().add(childLoDisplay);
58 }
59 if(loDisplay.getLoDisplayInfoList().size()>1){
60 Collections.sort(loDisplay.getLoDisplayInfoList(), LoDisplayComparator.getInstance());
61 }
62 } catch (DoesNotExistException e) {
63 } catch (Exception e) {
64 throw new AssemblyException("Error getting learning objective", e);
65 }
66
67 }
68 return loDisplay;
69 }
70
71 @Override
72
73 public BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> disassemble(
74 LoDisplayInfo loDisplay, NodeOperation operation)
75 throws AssemblyException {
76
77 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> result = new BaseDTOAssemblyNode<LoDisplayInfo, LoInfo>(this);
78
79
80 if (loDisplay == null || loDisplay.getLoInfo() == null) {
81 throw new AssemblyException("Lo can not be null");
82 }
83 if (NodeOperation.CREATE != operation && null == loDisplay.getLoInfo().getId()) {
84 throw new AssemblyException("Lo id can not be null");
85 }
86
87
88 loDisplay.getLoInfo().setId(UUIDHelper.genStringUUID(loDisplay.getLoInfo().getId()));
89
90
91 loDisplay.getLoInfo().setType(CourseAssemblerConstants.COURSE_LO_TYPE);
92 loDisplay.getLoInfo().setLoRepositoryKey(CourseAssemblerConstants.COURSE_LO_REPOSITORY_KEY);
93
94
95
96 result.setBusinessDTORef(loDisplay);
97 result.setNodeData(loDisplay.getLoInfo());
98 result.setOperation(operation);
99
100
101 try {
102 List<BaseDTOAssemblyNode<?, ?>> childLoNodes = disassembleChildLos(loDisplay, operation);
103 result.getChildNodes().addAll(childLoNodes);
104 } catch (DoesNotExistException e) {
105 } catch (Exception e) {
106 throw new AssemblyException("Error disassembling child los", e);
107 }
108
109
110 try {
111 List<BaseDTOAssemblyNode<?, ?>> categoryNodes = disassembleCategories(loDisplay, operation);
112 result.getChildNodes().addAll(categoryNodes);
113 } catch (Exception e) {
114 throw new AssemblyException("Error disassembling categories", e);
115 }
116
117 return result;
118 }
119
120 private List<BaseDTOAssemblyNode<?, ?>> disassembleCategories(
121 LoDisplayInfo loDisplay, NodeOperation operation) throws AssemblyException {
122
123 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
124
125
126 Set<String> currentCategoryIds = new HashSet<String>();
127
128 if (!NodeOperation.CREATE.equals(operation)) {
129 try {
130 List<LoCategoryInfo> categories = loService.getLoCategoriesForLo(loDisplay.getLoInfo().getId());
131 for (LoCategoryInfo category : categories) {
132 currentCategoryIds.add(category.getId());
133 }
134 } catch (DoesNotExistException e) {
135 } catch (Exception e) {
136 throw new AssemblyException("Error getting categories", e);
137 }
138 }
139
140 for (LoCategoryInfo category : loDisplay.getLoCategoryInfoList()) {
141
142
143 if (NodeOperation.CREATE == operation
144 || (NodeOperation.UPDATE == operation && !currentCategoryIds.contains(category.getId()))) {
145
146 LoCategoryRelationInfo loCategoryRelation = new LoCategoryRelationInfo();
147 loCategoryRelation.setCategoryId(category.getId());
148 loCategoryRelation.setLoId(loDisplay.getLoInfo().getId());
149
150 BaseDTOAssemblyNode<LoDisplayInfo, LoCategoryRelationInfo> relationToAddNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoCategoryRelationInfo>(null);
151 relationToAddNode.setNodeData(loCategoryRelation);
152 relationToAddNode.setOperation(NodeOperation.CREATE);
153 results.add(relationToAddNode);
154
155 currentCategoryIds.remove(category.getId());
156 } else if (NodeOperation.UPDATE == operation
157 && currentCategoryIds.contains(category.getId())) {
158 currentCategoryIds.remove(category.getId());
159 }
160 }
161
162 for(String categoryId:currentCategoryIds){
163 LoCategoryRelationInfo loCategoryRelation = new LoCategoryRelationInfo();
164 loCategoryRelation.setCategoryId(categoryId);
165 loCategoryRelation.setLoId(loDisplay.getLoInfo().getId());
166
167 BaseDTOAssemblyNode<LoDisplayInfo, LoCategoryRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoCategoryRelationInfo>(null);
168 relationToDeleteNode.setNodeData(loCategoryRelation);
169 relationToDeleteNode.setOperation(NodeOperation.DELETE);
170 results.add(relationToDeleteNode);
171 }
172
173 return results;
174 }
175
176 private List<BaseDTOAssemblyNode<?, ?>> disassembleChildLos(LoDisplayInfo loDisplay, NodeOperation operation) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, AssemblyException{
177 List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
178 Map<String,LoLoRelationInfo> currentLoRelations = new HashMap<String,LoLoRelationInfo>();
179
180 if (!NodeOperation.CREATE.equals(operation)) {
181 try {
182 List<LoLoRelationInfo> loRelations = loService.getLoLoRelationsByLoId(loDisplay.getLoInfo().getId());
183 for (LoLoRelationInfo loRelation : loRelations) {
184
185 if(CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES.equals(loRelation.getType())&&
186 !loDisplay.getLoInfo().getId().equals(loRelation.getRelatedLoId())){
187 currentLoRelations.put(loRelation.getRelatedLoId(), loRelation);
188 }
189 }
190 } catch (DoesNotExistException e) {
191 } catch (Exception e) {
192 throw new AssemblyException("Error getting categories", e);
193 }
194 }
195
196
197 for (LoDisplayInfo childDisplay : loDisplay.getLoDisplayInfoList()) {
198
199
200
201
202 childDisplay.getLoInfo().setState(loDisplay.getLoInfo().getState());
203
204
205 if (NodeOperation.CREATE == operation
206 || (NodeOperation.UPDATE == operation && !currentLoRelations.containsKey(childDisplay.getLoInfo().getId()))) {
207
208
209
210 childDisplay.getLoInfo().setId(null);
211 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
212 .disassemble(childDisplay, NodeOperation.CREATE);
213 results.add(loNode);
214
215
216 LoLoRelationInfo relation = new LoLoRelationInfo();
217 relation.setLoId(loDisplay.getLoInfo().getId());
218 relation.setRelatedLoId(loNode.getNodeData().getId());
219 relation.setType(CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES);
220
221
222
223
224 relation.setState(DtoConstants.STATE_ACTIVE);
225
226
227 BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo> relationNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo>(
228 null);
229 relationNode.setNodeData(relation);
230 relationNode.setOperation(NodeOperation.CREATE);
231
232 results.add(relationNode);
233 } else if (NodeOperation.UPDATE == operation
234 && currentLoRelations.containsKey(childDisplay.getLoInfo().getId())) {
235
236
237 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
238 .disassemble(childDisplay, NodeOperation.UPDATE);
239 results.add(loNode);
240
241
242
243 currentLoRelations.remove(childDisplay.getLoInfo().getId());
244 } else if (NodeOperation.DELETE == operation
245 && currentLoRelations.containsKey(childDisplay.getLoInfo().getId())) {
246
247
248 LoLoRelationInfo relationToDelete = currentLoRelations.get(childDisplay.getLoInfo().getId());
249 BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo>(
250 null);
251 relationToDeleteNode.setNodeData(relationToDelete);
252 relationToDeleteNode.setOperation(NodeOperation.DELETE);
253 results.add(relationToDeleteNode);
254
255 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
256 .disassemble(childDisplay, NodeOperation.DELETE);
257 results.add(loNode);
258
259
260
261 currentLoRelations.remove(childDisplay.getLoInfo().getId());
262 }
263 }
264
265
266
267 for (Entry<String, LoLoRelationInfo> entry : currentLoRelations.entrySet()) {
268
269
270 LoLoRelationInfo relationToDelete = entry.getValue();
271 BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo>(
272 null);
273 relationToDeleteNode.setNodeData(relationToDelete);
274 relationToDeleteNode.setOperation(NodeOperation.DELETE);
275 results.add(relationToDeleteNode);
276
277 LoInfo loToDelete = loService.getLo(entry.getKey());
278 LoDisplayInfo loDisplayToDelete = this.assemble(loToDelete, null, false);
279 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this.disassemble(loDisplayToDelete, NodeOperation.DELETE);
280 results.add(loNode);
281 }
282 return results;
283
284 }
285
286 public void setLoService(LearningObjectiveService loService) {
287 this.loService = loService;
288 }
289
290 public static class LoDisplayComparator implements Comparator<LoDisplayInfo>{
291 private static LoDisplayComparator instance = new LoDisplayComparator();
292 @Override
293 public int compare(LoDisplayInfo o1, LoDisplayInfo o2) {
294 String o1Sequence = o1.getLoInfo().getAttributes().get(CourseAssemblerConstants.COURSE_LO_SEQUENCE);
295 String o2Sequence = o1.getLoInfo().getAttributes().get(CourseAssemblerConstants.COURSE_LO_SEQUENCE);
296 if(o1Sequence!=null){
297 return o1Sequence.compareTo(o2Sequence);
298 }else if(o2Sequence!=null){
299 return -1;
300 }
301 return 0;
302 }
303 public static LoDisplayComparator getInstance() {
304 return instance;
305 }
306 }
307 }