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