View Javadoc

1   package org.kuali.student.r2.lum.course.service.assembler;
2   
3   import org.kuali.student.common.util.UUIDHelper;
4   import org.kuali.student.r1.common.assembly.BOAssembler;
5   import org.kuali.student.r1.common.assembly.BaseDTOAssemblyNode;
6   import org.kuali.student.r1.common.assembly.BaseDTOAssemblyNode.NodeOperation;
7   import org.kuali.student.r2.common.dto.DtoConstants;
8   import org.kuali.student.r2.lum.course.dto.LoDisplayInfo;
9   import org.kuali.student.r2.lum.lo.dto.LoCategoryInfo;
10  import org.kuali.student.r2.lum.lo.dto.LoInfo;
11  import org.kuali.student.r2.lum.lo.dto.LoLoRelationInfo;
12  import org.kuali.student.r2.common.assembler.AssemblyException;
13  import org.kuali.student.r2.common.dto.AttributeInfo;
14  import org.kuali.student.r2.common.dto.ContextInfo;
15  import org.kuali.student.r2.common.exceptions.*;
16  import org.kuali.student.r2.lum.lo.service.LearningObjectiveService;
17  
18  import java.util.*;
19  import java.util.Map.Entry;
20  
21  
22  public class LoAssembler implements BOAssembler<LoDisplayInfo, LoInfo> {
23  
24  	private LearningObjectiveService loService;
25  	
26  
27  	@Override
28  	public LoDisplayInfo assemble(LoInfo lo, LoDisplayInfo loDisplayInfo,
29  			boolean shallowBuild, ContextInfo contextInfo) throws AssemblyException {
30  		
31  		LoDisplayInfo loDisplay = (null != loDisplayInfo) ? loDisplayInfo : new LoDisplayInfo();
32  		
33  		loDisplay.setLoInfo(lo);
34  
35  		if (!shallowBuild) {
36  			String loId = lo.getId();
37  			try {
38  				List<LoCategoryInfo> loCategories = null;
39                  loCategories = loService.getLoCategoriesByLo(loId, contextInfo);
40  				loDisplay.setLoCategoryInfoList(loCategories);
41  			} catch (DoesNotExistException e) {
42  			} catch (Exception e) {
43  				throw new AssemblyException("Error getting learning objective categories", e);
44  			}
45  			try {
46  				List<LoInfo> childLos = loService.getRelatedLosByLoId(loId, CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES, contextInfo);
47  				for(LoInfo childLo:childLos){
48  					LoDisplayInfo childLoDisplay = assemble(childLo, null, shallowBuild,contextInfo);
49  					childLoDisplay.setParentLoRelationid(lo.getId());
50  								
51  					childLoDisplay.setParentRelType(CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES);
52  					loDisplay.getLoDisplayInfoList().add(childLoDisplay);
53  				}
54  				if(loDisplay.getLoDisplayInfoList().size()>1){
55  					Collections.sort(loDisplay.getLoDisplayInfoList(), LoDisplayComparator.getInstance());
56  				}
57  			} catch (DoesNotExistException e) {
58  			} catch (Exception e) {
59  				throw new AssemblyException("Error getting learning objective", e);
60  			}
61  
62  		}
63  		return loDisplay;
64  	}
65  
66  
67  	//Creation of categories is done in the LoCategoryRpcGwtServlet
68  	public BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> disassemble(
69  			LoDisplayInfo loDisplay, NodeOperation operation,ContextInfo contextInfo)
70  			throws AssemblyException {
71  		
72  		BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> result = new BaseDTOAssemblyNode<LoDisplayInfo, LoInfo>(this);
73  		
74  		//see if this is a new LuInfo
75  		if (loDisplay == null || loDisplay.getLoInfo() == null) {
76  			throw new AssemblyException("Lo can not be null");
77  		}
78  		if (NodeOperation.CREATE != operation && null == loDisplay.getLoInfo().getId()) {
79  			throw new AssemblyException("Lo id can not be null");
80  		}
81  		
82  		//set the id if it's not there already(important for creating relations)
83  		loDisplay.getLoInfo().setId(UUIDHelper.genStringUUID(loDisplay.getLoInfo().getId()));
84  		
85  		//Default these values
86  				
87  		loDisplay.getLoInfo().setTypeKey(CourseAssemblerConstants.COURSE_LO_TYPE);
88  		 
89  		loDisplay.getLoInfo().setLoRepositoryKey(CourseAssemblerConstants.COURSE_LO_REPOSITORY_KEY);
90  		
91  		
92  		//Populate the node
93  		result.setBusinessDTORef(loDisplay);
94  		result.setNodeData(loDisplay.getLoInfo());
95  		result.setOperation(operation);
96  		
97  		//Process the child los
98  		try {
99  			List<BaseDTOAssemblyNode<?, ?>> childLoNodes = disassembleChildLos(loDisplay, operation,contextInfo);
100 			result.getChildNodes().addAll(childLoNodes);
101 		} catch (DoesNotExistException e) {
102 		} catch (Exception e) {
103 			throw new AssemblyException("Error disassembling child los", e);
104 		} 
105 
106 		//Process the categories
107 		try {
108 			List<BaseDTOAssemblyNode<?, ?>> categoryNodes = disassembleCategories(loDisplay, operation,contextInfo);
109 			result.getChildNodes().addAll(categoryNodes);
110 		} catch (Exception e) {
111 			throw new AssemblyException("Error disassembling categories", e);
112 		} 
113 		
114 		return result;
115 	}
116 
117 	private List<BaseDTOAssemblyNode<?, ?>> disassembleCategories(
118 			LoDisplayInfo loDisplay, NodeOperation operation,ContextInfo contextInfo) throws AssemblyException {
119 		
120 		List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
121 		
122 		//Category relations
123 		Set<String> currentCategoryIds = new HashSet<String>();
124 		//Get current relations
125 		if (!NodeOperation.CREATE.equals(operation)) {
126 			try {
127 				List<LoCategoryInfo> categories = loService.getLoCategoriesByLo(loDisplay.getLoInfo().getId(), contextInfo);
128 				for (LoCategoryInfo category : categories) {
129 					currentCategoryIds.add(category.getId());
130 				}
131 				
132 			} catch (Exception e) {
133 				throw new AssemblyException("Error getting categories",	e);
134 			}
135 		}
136 		//Update
137 		for (LoCategoryInfo category : loDisplay.getLoCategoryInfoList()) {
138 
139 			// If this is a format create/new activity update then all activities will be created
140 		    if (NodeOperation.CREATE == operation
141 		            || (NodeOperation.UPDATE == operation &&  !currentCategoryIds.contains(category.getId()))) {
142 		    	
143 		    	
144 		    	LoCategoryRelationInfo loCategoryRelation = new LoCategoryRelationInfo();
145 		    	loCategoryRelation.setCategoryId(category.getId());
146 		    	loCategoryRelation.setLoId(loDisplay.getLoInfo().getId());
147 		    	
148                 BaseDTOAssemblyNode<LoDisplayInfo, LoCategoryRelationInfo> relationToAddNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoCategoryRelationInfo>(null);
149                 relationToAddNode.setNodeData(loCategoryRelation);
150                 relationToAddNode.setOperation(NodeOperation.CREATE);
151                 results.add(relationToAddNode);
152 
153                 currentCategoryIds.remove(category.getId());
154 		    } else if (NodeOperation.UPDATE == operation
155 					&& currentCategoryIds.contains(category.getId())) {
156                 currentCategoryIds.remove(category.getId());
157 			} 
158 		}
159 		//Delete leftovers
160 		for(String categoryId:currentCategoryIds){
161 			
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, ContextInfo contextInfo) throws DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException, AssemblyException, PermissionDeniedException{
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(), contextInfo);
182 				for (LoLoRelationInfo loRelation : loRelations) {
183 					//getLoLoRelationsByLoId returns if the lo is related or if it is the owner(this seems wrong)
184 					
185 					if(CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES.equals(loRelation.getTypeKey())&&
186 							!loDisplay.getLoInfo().getId().equals(loRelation.getRelatedLoId())){
187 						currentLoRelations.put(loRelation.getRelatedLoId(), loRelation);
188 					}
189 				}
190 				
191 			} catch (Exception e) {
192 				throw new AssemblyException("Error getting categories",	e);
193 			}
194 		}
195 		
196 		// Loop through all the activities in this format
197 		for (LoDisplayInfo childDisplay : loDisplay.getLoDisplayInfoList()) {
198 		    
199 		    // Set the state of the child LO to match the state of the parent
200 		    // LO. This end up propagating the program state to all of the LOs,
201 		    // since we set parent LO state to program state earlier in the code
202 					    
203 			childDisplay.getLoInfo().setStateKey(loDisplay.getLoInfo().getStateKey());
204 		    
205 			// If this is a format create/new activity update then all activities will be created
206 		    if (NodeOperation.CREATE == operation
207 		            || (NodeOperation.UPDATE == operation &&  !currentLoRelations.containsKey(childDisplay.getLoInfo().getId()))) {
208 		        		    
209                 // the lo does not exist, so create
210                 // Assemble and add the lo
211 		    	childDisplay.getLoInfo().setId(null);
212                 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
213                         .disassemble(childDisplay, NodeOperation.CREATE,contextInfo);
214                 results.add(loNode);
215 
216                 // Create the relationship and add it as well
217                 LoLoRelationInfo relation = new LoLoRelationInfo();
218                 relation.setLoId(loDisplay.getLoInfo().getId());
219                 relation.setRelatedLoId(loNode.getNodeData().getId());
220              
221                 relation.setTypeKey(CourseAssemblerConstants.COURSE_LO_RELATION_INCLUDES);
222                 
223                 // Relations can only have states of Active or SUSPENDED
224                 // DO NOT use states like Approve, Draft, etc on relations
225                 // Will default to Active
226                         
227                 relation.setStateKey(DtoConstants.STATE_ACTIVE);
228                 
229 
230                 BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo> relationNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo>(
231                         null);
232                 relationNode.setNodeData(relation);
233                 relationNode.setOperation(NodeOperation.CREATE);
234 
235                 results.add(relationNode);
236             } else if (NodeOperation.UPDATE == operation
237 					&& currentLoRelations.containsKey(childDisplay.getLoInfo().getId())) {
238 				// If the lo already has this child lo, then just update the
239 				// child lo
240 				BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
241 						.disassemble(childDisplay, NodeOperation.UPDATE,contextInfo);
242 				results.add(loNode);
243 
244 				// remove this entry from the map so we can tell what needs to
245 				// be deleted at the end
246 				currentLoRelations.remove(childDisplay.getLoInfo().getId());
247 			} else if (NodeOperation.DELETE == operation
248                     && currentLoRelations.containsKey(childDisplay.getLoInfo().getId())) {
249 			    
250                 // Delete the Format and its relation
251 				LoLoRelationInfo relationToDelete = currentLoRelations.get(childDisplay.getLoInfo().getId());
252                 BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo>(
253                         null);
254                 relationToDeleteNode.setNodeData(relationToDelete);
255                 relationToDeleteNode.setOperation(NodeOperation.DELETE);
256                 results.add(relationToDeleteNode);
257             
258                 BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this
259                 .disassemble(childDisplay, NodeOperation.DELETE,contextInfo);
260                 results.add(loNode);                                
261 
262                 // remove this entry from the map so we can tell what needs to
263                 // be deleted at the end
264                 currentLoRelations.remove(childDisplay.getLoInfo().getId());			    
265 			}
266 		}         
267 
268         // Now any leftover lo ids are no longer needed, so delete
269         // los and relations
270         for (Entry<String, LoLoRelationInfo> entry : currentLoRelations.entrySet()) {
271             // Create a new relation with the id of the relation we want to
272             // delete
273         	LoLoRelationInfo relationToDelete = entry.getValue();
274             BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<LoDisplayInfo, LoLoRelationInfo>(
275                     null);
276             relationToDeleteNode.setNodeData(relationToDelete);
277             relationToDeleteNode.setOperation(NodeOperation.DELETE);
278             results.add(relationToDeleteNode);
279             
280             LoInfo temploTODelete = loService.getLo(entry.getKey(), new ContextInfo());
281             LoDisplayInfo loDisplayToDelete = this.assemble(temploTODelete, null, false,contextInfo);
282             BaseDTOAssemblyNode<LoDisplayInfo, LoInfo> loNode = this.disassemble(loDisplayToDelete, NodeOperation.DELETE,contextInfo);
283             results.add(loNode);                                            
284         }
285 		return results;
286 		
287 	}
288 
289 	public void setLoService(LearningObjectiveService loService) {
290 		this.loService = loService;
291 	}
292 
293 	public static class LoDisplayComparator implements Comparator<LoDisplayInfo>{
294 		private static LoDisplayComparator instance = new LoDisplayComparator();
295 		@Override
296 		public int compare(LoDisplayInfo o1, LoDisplayInfo o2) {
297 			
298 		    String o1Sequence = null;
299 		    for(AttributeInfo attribute : o1.getLoInfo().getAttributes()){
300 		        if (attribute.getKey().equals(CourseAssemblerConstants.COURSE_LO_SEQUENCE)){
301 		            o1Sequence = attribute.getValue(); 
302 		        }
303 		    }
304 		    
305 		    String o2Sequence = null;
306             for(AttributeInfo attribute : o2.getLoInfo().getAttributes()){
307                 if (attribute.getKey().equals(CourseAssemblerConstants.COURSE_LO_SEQUENCE)){
308                     o2Sequence = attribute.getValue(); 
309                 }
310             }
311 			
312 			if(o1Sequence!=null){
313 				return o1Sequence.compareTo(o2Sequence);
314 			}else if(o2Sequence!=null){
315 				return -1;
316 			}
317 			return 0;
318 		}
319 		public static LoDisplayComparator getInstance() {
320 			return instance;
321 		}
322 	}
323 
324 }