View Javadoc

1   /*
2    * Copyright 2008 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 1.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl1.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.lum.course.service.assembler;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.Map.Entry;
23  
24  import org.apache.log4j.Logger;
25  import org.kuali.student.common.assembly.BOAssembler;
26  import org.kuali.student.common.assembly.BaseDTOAssemblyNode;
27  import org.kuali.student.common.assembly.BaseDTOAssemblyNode.NodeOperation;
28  import org.kuali.student.common.assembly.data.AssemblyException;
29  import org.kuali.student.common.exceptions.DoesNotExistException;
30  import org.kuali.student.common.exceptions.InvalidParameterException;
31  import org.kuali.student.common.exceptions.MissingParameterException;
32  import org.kuali.student.common.exceptions.OperationFailedException;
33  import org.kuali.student.common.util.UUIDHelper;
34  import org.kuali.student.lum.course.dto.ActivityInfo;
35  import org.kuali.student.lum.course.dto.CourseInfo;
36  import org.kuali.student.lum.course.dto.FormatInfo;
37  import org.kuali.student.lum.lu.dto.CluCluRelationInfo;
38  import org.kuali.student.lum.lu.dto.CluInfo;
39  import org.kuali.student.lum.lu.service.LuService;
40  
41  /**
42   * Assembler for FormatInfo. Assembles/Disassemble FormatInfo from CluInfo and
43   * other structures.
44   * 
45   * @author Kuali Student Team
46   * 
47   */
48  public class FormatAssembler implements BOAssembler<FormatInfo, CluInfo> {
49  	final static Logger LOG = Logger.getLogger(FormatAssembler.class);
50  
51  	private BOAssembler<ActivityInfo, CluInfo> activityAssembler;
52  	private LuService luService;
53  
54  	@Override
55  	public FormatInfo assemble(CluInfo clu, FormatInfo formatInfo,
56  			boolean shallowBuild) throws AssemblyException {
57  
58  		if (clu == null) {
59  			return null;
60  		}
61  
62  		FormatInfo format = (null != formatInfo) ? formatInfo
63  				: new FormatInfo();
64  
65  		// Copy base properties
66  		format.setId(clu.getId());
67  		format.setType(clu.getType());
68  		format.setState(clu.getState());
69  		format.setMetaInfo(clu.getMetaInfo());
70  		format.setAttributes(clu.getAttributes());
71  	    format.setDuration(clu.getStdDuration());
72  	    format.setTermsOffered(clu.getOfferedAtpTypes());
73  		
74  		// Don't make any changes to nested datastructures if this is
75  		if (!shallowBuild) {
76  			// Use the luService to find activities, then convert and add to the
77  			// format
78  			try {
79  				List<CluInfo> activities = luService.getRelatedClusByCluId(
80  						format.getId(),
81  						CourseAssemblerConstants.COURSE_ACTIVITY_RELATION_TYPE);
82  				for (CluInfo activity : activities) {
83  					ActivityInfo activityInfo = activityAssembler.assemble(
84  							activity, null, false);
85  					format.getActivities().add(activityInfo);
86  				}
87  			} catch (DoesNotExistException e) {
88  			} catch (Exception e) {
89  				throw new AssemblyException("Error getting related activities", e);
90  			} 
91  		}
92  		return format;
93  	}
94  
95  	@Override
96  	public BaseDTOAssemblyNode<FormatInfo, CluInfo> disassemble(
97  			FormatInfo format, NodeOperation operation)
98  			throws AssemblyException {
99  		BaseDTOAssemblyNode<FormatInfo, CluInfo> result = new BaseDTOAssemblyNode<FormatInfo, CluInfo>(
100 				this);
101 		if (format == null) {
102 			// FIXME Unsure now if this is an exception or just return null or
103 			// empty assemblyNode
104 			throw new AssemblyException("Format can not be null");
105 		}
106 		if (NodeOperation.CREATE != operation && null == format.getId()) {
107 			throw new AssemblyException("Course Format Shell's id can not be null");
108 		}
109 
110 		CluInfo clu;
111         try {
112             clu = (NodeOperation.UPDATE == operation) ? clu = luService.getClu(format.getId()) : new CluInfo();
113         } catch (Exception e) {
114             throw new AssemblyException("Error retrieving course format shell during update", e);
115         } 
116 
117 		// Copy all fields
118 		clu.setId(UUIDHelper.genStringUUID(format.getId()));// Create the id if
119 															// it's not there
120 															// already(important
121 															// for creating
122 															// relations)
123 		clu.setType(CourseAssemblerConstants.COURSE_FORMAT_TYPE);
124 		clu.setState(format.getState());
125 		clu.setMetaInfo(format.getMetaInfo());
126 		clu.setAttributes(format.getAttributes());
127 		clu.setStdDuration(format.getDuration());
128 		clu.setOfferedAtpTypes(format.getTermsOffered());
129 		
130 		// Add the Clu to the result
131 		result.setNodeData(clu);
132 		result.setOperation(operation);
133 		result.setBusinessDTORef(format);
134 
135 		// Use the Activity assembler to disassemble the activities and
136 		// relations
137 		List<BaseDTOAssemblyNode<?, ?>> activityResults;
138         try {
139             activityResults = disassembleActivities(clu.getId(),
140             		format, operation);
141             result.getChildNodes().addAll(activityResults);
142             
143         } catch (Exception e) {
144             throw new AssemblyException("Error while disassembling format", e);
145         }
146         
147 		return result;
148 	}
149 
150 	/**
151 	 * This method will return assembly nodes representing activities and
152 	 * activity->format relations for a format based on the operation CREATE:
153 	 * all activities and format-> activity relations will be created UPDATE:
154 	 * activities will be taken from the luService and compared with the
155 	 * incomming format's activities. Any new activites will be created with a
156 	 * corresponding CluCluRelation Any existing activities will be Updated All
157 	 * leftover activities and their CluCluRelations will be deleted DELETE: all
158 	 * activities and their CluCluRelations will be deleted
159 	 * 
160 	 * If the Operation
161 	 * 
162 	 * @param format
163 	 * @param result
164 	 * @param operation
165 	 * @return List of Assembly nodes
166 	 * @throws AssemblyException
167 	 * @throws OperationFailedException 
168 	 * @throws MissingParameterException 
169 	 * @throws InvalidParameterException 
170 	 * @throws DoesNotExistException 
171 	 */
172 	private List<BaseDTOAssemblyNode<?, ?>> disassembleActivities(String nodeId,
173 			FormatInfo format, NodeOperation operation)
174 			throws AssemblyException, DoesNotExistException, InvalidParameterException, MissingParameterException, OperationFailedException {
175 		List<BaseDTOAssemblyNode<?, ?>> results = new ArrayList<BaseDTOAssemblyNode<?, ?>>();
176 
177 		// Get the current activities and put them in a map of activity
178 		// id/relation id
179 		Map<String, String> currentActivityIds = new HashMap<String, String>();
180 
181 		if (!NodeOperation.CREATE.equals(operation)) {
182 			try {
183 				List<CluCluRelationInfo> activityRelationships = luService
184 						.getCluCluRelationsByClu(format.getId());
185 				
186 				for (CluCluRelationInfo activityRelation : activityRelationships) {
187 					if (CourseAssemblerConstants.COURSE_ACTIVITY_RELATION_TYPE
188 							.equals(activityRelation.getType())) {
189 						currentActivityIds.put(activityRelation
190 								.getRelatedCluId(), activityRelation.getId());
191 					}
192 				}
193 			} catch (DoesNotExistException e) {
194 			} catch (Exception e) {
195 				throw new AssemblyException("Error getting related activities",	e);
196 			}
197 		}
198 
199 		// Loop through all the activities in this format
200 		for (ActivityInfo activity : format.getActivities()) {
201 
202 			// If this is a format create/new activity update then all activities will be created
203 		    if (NodeOperation.CREATE == operation
204 		            || (NodeOperation.UPDATE == operation &&  !currentActivityIds.containsKey(activity.getId()))) {
205 		    	activity.setState(format.getState());
206                 // the activity does not exist, so create
207                 // Assemble and add the activity
208                 BaseDTOAssemblyNode<ActivityInfo, CluInfo> activityNode = activityAssembler
209                         .disassemble(activity, NodeOperation.CREATE);
210                 results.add(activityNode);
211 
212                 // Create the relationship and add it as well
213                 CluCluRelationInfo relation = new CluCluRelationInfo();
214                 relation.setCluId(nodeId);
215                 relation.setRelatedCluId(activityNode.getNodeData().getId());// this should
216                                                             // already be set
217                                                             // even if it's a
218                                                             // create
219                 relation
220                         .setType(CourseAssemblerConstants.COURSE_ACTIVITY_RELATION_TYPE);
221                 relation.setState(format.getState());
222 
223                 BaseDTOAssemblyNode<FormatInfo, CluCluRelationInfo> relationNode = new BaseDTOAssemblyNode<FormatInfo, CluCluRelationInfo>(
224                         null);
225                 relationNode.setNodeData(relation);
226                 relationNode.setOperation(NodeOperation.CREATE);
227 
228                 results.add(relationNode);
229             } else if (NodeOperation.UPDATE == operation
230 					&& currentActivityIds.containsKey(activity.getId())) {
231 				// If the format already has this activity, then just update the
232 				// activity
233             	activity.setState(format.getState());
234 				BaseDTOAssemblyNode<ActivityInfo, CluInfo> activityNode = activityAssembler
235 						.disassemble(activity, NodeOperation.UPDATE);
236 				results.add(activityNode);
237 
238 				// remove this entry from the map so we can tell what needs to
239 				// be deleted at the end
240 				currentActivityIds.remove(activity.getId());
241 			} else if (NodeOperation.DELETE == operation
242                     && currentActivityIds.containsKey(activity.getId())) {
243 			    
244                 // Delete the Format and its relation
245                 CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
246                 relationToDelete.setId( currentActivityIds.get(activity.getId()) );
247                 BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<CourseInfo, CluCluRelationInfo>(
248                         null);
249                 relationToDeleteNode.setNodeData(relationToDelete);
250                 relationToDeleteNode.setOperation(NodeOperation.DELETE);
251                 results.add(relationToDeleteNode);
252             
253                 BaseDTOAssemblyNode<ActivityInfo, CluInfo> formatNode = activityAssembler
254                 .disassemble(activity, NodeOperation.DELETE);
255                 results.add(formatNode);                                
256 
257                 // remove this entry from the map so we can tell what needs to
258                 // be deleted at the end
259                 currentActivityIds.remove(activity.getId());			    
260 			}
261 		}         
262 
263         // Now any leftover activity ids are no longer needed, so delete
264         // activities and relations
265         for (Entry<String, String> entry : currentActivityIds.entrySet()) {
266             // Create a new relation with the id of the relation we want to
267             // delete
268             CluCluRelationInfo relationToDelete = new CluCluRelationInfo();
269             relationToDelete.setId(entry.getValue());
270             BaseDTOAssemblyNode<FormatInfo, CluCluRelationInfo> relationToDeleteNode = new BaseDTOAssemblyNode<FormatInfo, CluCluRelationInfo>(
271                     null);
272             relationToDeleteNode.setNodeData(relationToDelete);
273             relationToDeleteNode.setOperation(NodeOperation.DELETE);
274             results.add(relationToDeleteNode);
275 
276             CluInfo activityCluToDelete = luService.getClu(entry.getKey());
277             ActivityInfo activityToDelete = activityAssembler.assemble(activityCluToDelete, null, false);
278             BaseDTOAssemblyNode<ActivityInfo, CluInfo> activityNode = activityAssembler
279             .disassemble(activityToDelete, NodeOperation.DELETE);
280             results.add(activityNode);                                            
281         }
282        
283 		
284 		return results;
285 	}
286 
287 	public BOAssembler<ActivityInfo, CluInfo> getActivityAssembler() {
288 		return activityAssembler;
289 	}
290 
291 	public void setActivityAssembler(
292 			BOAssembler<ActivityInfo, CluInfo> activityAssembler) {
293 		this.activityAssembler = activityAssembler;
294 	}
295 
296 	public LuService getLuService() {
297 		return luService;
298 	}
299 
300 	public void setLuService(LuService luService) {
301 		this.luService = luService;
302 	}
303 }