View Javadoc

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  	//Creation of categories is done in the LoCategoryRpcGwtServlet
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  		//see if this is a new LuInfo
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  		//set the id if it's not there already(important for creating relations)
87  		loDisplay.getLoInfo().setId(UUIDHelper.genStringUUID(loDisplay.getLoInfo().getId()));
88  		
89  		//Default these values
90  		loDisplay.getLoInfo().setType(CourseAssemblerConstants.COURSE_LO_TYPE);
91  		loDisplay.getLoInfo().setLoRepositoryKey(CourseAssemblerConstants.COURSE_LO_REPOSITORY_KEY);
92  		
93  		
94  		//Populate the node
95  		result.setBusinessDTORef(loDisplay);
96  		result.setNodeData(loDisplay.getLoInfo());
97  		result.setOperation(operation);
98  		
99  		//Process the child los
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 		//Process the categories
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 		//Category relations
125 		Set<String> currentCategoryIds = new HashSet<String>();
126 		//Get current relations
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 		//Update
139 		for (LoCategoryInfo category : loDisplay.getLoCategoryInfoList()) {
140 
141 			// If this is a format create/new activity update then all activities will be created
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 		//Delete leftovers
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 		//Make lu lu relations
179 		if (!NodeOperation.CREATE.equals(operation)) {
180 			try {
181 				List<LoLoRelationInfo> loRelations = loService.getLoLoRelationsByLoId(loDisplay.getLoInfo().getId());
182 				for (LoLoRelationInfo loRelation : loRelations) {
183 					//getLoLoRelationsByLoId returns if the lo is related or if it is the owner(this seems wrong)
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 		// Loop through all the activities in this format
196 		for (LoDisplayInfo childDisplay : loDisplay.getLoDisplayInfoList()) {
197 
198 			// If this is a format create/new activity update then all activities will be created
199 		    if (NodeOperation.CREATE == operation
200 		            || (NodeOperation.UPDATE == operation &&  !currentLoRelations.containsKey(childDisplay.getLoInfo().getId()))) {
201 		        		    
202                 // the lo does not exist, so create
203                 // Assemble and add the lo
204 		    	childDisplay.getLoInfo().setId(null);
205                 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
206                         .disassemble(childDisplay, NodeOperation.CREATE);
207                 results.add(loNode);
208 
209                 // Create the relationship and add it as well
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 				// If the lo already has this child lo, then just update the
226 				// child lo
227 				BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
228 						.disassemble(childDisplay, NodeOperation.UPDATE);
229 				results.add(loNode);
230 
231 				// remove this entry from the map so we can tell what needs to
232 				// be deleted at the end
233 				currentLoRelations.remove(childDisplay.getLoInfo().getId());
234 			} else if (NodeOperation.DELETE == operation
235                     && currentLoRelations.containsKey(childDisplay.getLoInfo().getId())) {
236 			    
237                 // Delete the Format and its relation
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                 // remove this entry from the map so we can tell what needs to
250                 // be deleted at the end
251                 currentLoRelations.remove(childDisplay.getLoInfo().getId());			    
252 			}
253 		}         
254 
255         // Now any leftover lo ids are no longer needed, so delete
256         // los and relations
257         for (Entry<String, LoLoRelationInfo> entry : currentLoRelations.entrySet()) {
258             // Create a new relation with the id of the relation we want to
259             // delete
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 }