001 package net.sf.cpsolver.studentsct;
002
003 import java.io.File;
004 import java.io.FileOutputStream;
005 import java.io.IOException;
006 import java.math.RoundingMode;
007 import java.text.DecimalFormat;
008 import java.util.BitSet;
009 import java.util.Date;
010 import java.util.Map;
011 import java.util.Set;
012 import java.util.TreeSet;
013
014 import org.dom4j.Document;
015 import org.dom4j.DocumentHelper;
016 import org.dom4j.Element;
017 import org.dom4j.io.OutputFormat;
018 import org.dom4j.io.XMLWriter;
019
020 import net.sf.cpsolver.coursett.IdConvertor;
021 import net.sf.cpsolver.coursett.model.RoomLocation;
022 import net.sf.cpsolver.coursett.model.TimeLocation;
023 import net.sf.cpsolver.ifs.solver.Solver;
024 import net.sf.cpsolver.ifs.util.Progress;
025 import net.sf.cpsolver.studentsct.constraint.LinkedSections;
026 import net.sf.cpsolver.studentsct.model.AcademicAreaCode;
027 import net.sf.cpsolver.studentsct.model.Choice;
028 import net.sf.cpsolver.studentsct.model.Config;
029 import net.sf.cpsolver.studentsct.model.Course;
030 import net.sf.cpsolver.studentsct.model.CourseRequest;
031 import net.sf.cpsolver.studentsct.model.Enrollment;
032 import net.sf.cpsolver.studentsct.model.FreeTimeRequest;
033 import net.sf.cpsolver.studentsct.model.Offering;
034 import net.sf.cpsolver.studentsct.model.Request;
035 import net.sf.cpsolver.studentsct.model.Section;
036 import net.sf.cpsolver.studentsct.model.Student;
037 import net.sf.cpsolver.studentsct.model.Subpart;
038 import net.sf.cpsolver.studentsct.reservation.CourseReservation;
039 import net.sf.cpsolver.studentsct.reservation.CurriculumReservation;
040 import net.sf.cpsolver.studentsct.reservation.DummyReservation;
041 import net.sf.cpsolver.studentsct.reservation.GroupReservation;
042 import net.sf.cpsolver.studentsct.reservation.IndividualReservation;
043 import net.sf.cpsolver.studentsct.reservation.Reservation;
044
045 /**
046 * Save student sectioning solution into an XML file.
047 *
048 * <br>
049 * <br>
050 * Parameters:
051 * <table border='1'>
052 * <tr>
053 * <th>Parameter</th>
054 * <th>Type</th>
055 * <th>Comment</th>
056 * </tr>
057 * <tr>
058 * <td>General.Output</td>
059 * <td>{@link String}</td>
060 * <td>Folder with the output solution in XML format (solution.xml)</td>
061 * </tr>
062 * <tr>
063 * <td>Xml.ConvertIds</td>
064 * <td>{@link Boolean}</td>
065 * <td>If true, ids are converted (to be able to make input data public)</td>
066 * </tr>
067 * <tr>
068 * <td>Xml.ShowNames</td>
069 * <td>{@link Boolean}</td>
070 * <td>If false, names are not exported (to be able to make input data public)</td>
071 * </tr>
072 * <tr>
073 * <td>Xml.SaveBest</td>
074 * <td>{@link Boolean}</td>
075 * <td>If true, best solution is saved.</td>
076 * </tr>
077 * <tr>
078 * <td>Xml.SaveInitial</td>
079 * <td>{@link Boolean}</td>
080 * <td>If true, initial solution is saved.</td>
081 * </tr>
082 * <tr>
083 * <td>Xml.SaveCurrent</td>
084 * <td>{@link Boolean}</td>
085 * <td>If true, current solution is saved.</td>
086 * </tr>
087 * <tr>
088 * <td>Xml.SaveOnlineSectioningInfo</td>
089 * <td>{@link Boolean}</td>
090 * <td>If true, save online sectioning info (i.e., expected and held space of
091 * each section)</td>
092 * </tr>
093 * <tr>
094 * <td>Xml.SaveStudentInfo</td>
095 * <td>{@link Boolean}</td>
096 * <td>If true, save student information (i.e., academic area classification,
097 * major, minor)</td>
098 * </tr>
099 * </table>
100 * <br>
101 * <br>
102 * Usage:<br>
103 * <code>
104 * new StudentSectioningXMLSaver(solver).save(new File("solution.xml"));<br>
105 * </code>
106 *
107 * @version StudentSct 1.2 (Student Sectioning)<br>
108 * Copyright (C) 2007 - 2010 Tomas Muller<br>
109 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
110 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
111 * <br>
112 * This library is free software; you can redistribute it and/or modify
113 * it under the terms of the GNU Lesser General Public License as
114 * published by the Free Software Foundation; either version 3 of the
115 * License, or (at your option) any later version. <br>
116 * <br>
117 * This library is distributed in the hope that it will be useful, but
118 * WITHOUT ANY WARRANTY; without even the implied warranty of
119 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
120 * Lesser General Public License for more details. <br>
121 * <br>
122 * You should have received a copy of the GNU Lesser General Public
123 * License along with this library; if not see
124 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
125 */
126
127 public class StudentSectioningXMLSaver extends StudentSectioningSaver {
128 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(StudentSectioningXMLSaver.class);
129 private static DecimalFormat[] sDF = { new DecimalFormat(""), new DecimalFormat("0"), new DecimalFormat("00"),
130 new DecimalFormat("000"), new DecimalFormat("0000"), new DecimalFormat("00000"),
131 new DecimalFormat("000000"), new DecimalFormat("0000000") };
132 private static DecimalFormat sStudentWeightFormat = new DecimalFormat("0.0000");
133 private File iOutputFolder = null;
134
135 private boolean iSaveBest = false;
136 private boolean iSaveInitial = false;
137 private boolean iSaveCurrent = false;
138 private boolean iSaveOnlineSectioningInfo = false;
139 private boolean iSaveStudentInfo = true;
140
141 private boolean iConvertIds = false;
142 private boolean iShowNames = false;
143
144 static {
145 sStudentWeightFormat.setRoundingMode(RoundingMode.DOWN);
146 }
147
148 /**
149 * Constructor
150 *
151 * @param solver
152 * student sectioning solver
153 */
154 public StudentSectioningXMLSaver(Solver<Request, Enrollment> solver) {
155 super(solver);
156 iOutputFolder = new File(getModel().getProperties().getProperty("General.Output",
157 "." + File.separator + "output"));
158 iSaveBest = getModel().getProperties().getPropertyBoolean("Xml.SaveBest", true);
159 iSaveInitial = getModel().getProperties().getPropertyBoolean("Xml.SaveInitial", true);
160 iSaveCurrent = getModel().getProperties().getPropertyBoolean("Xml.SaveCurrent", false);
161 iSaveOnlineSectioningInfo = getModel().getProperties().getPropertyBoolean("Xml.SaveOnlineSectioningInfo", true);
162 iSaveStudentInfo = getModel().getProperties().getPropertyBoolean("Xml.SaveStudentInfo", true);
163 iShowNames = getModel().getProperties().getPropertyBoolean("Xml.ShowNames", true);
164 iConvertIds = getModel().getProperties().getPropertyBoolean("Xml.ConvertIds", false);
165 }
166
167 /** Convert bitset to a bit string */
168 private static String bitset2string(BitSet b) {
169 StringBuffer sb = new StringBuffer();
170 for (int i = 0; i < b.length(); i++)
171 sb.append(b.get(i) ? "1" : "0");
172 return sb.toString();
173 }
174
175 /** Generate id for given object with the given id */
176 private String getId(String type, String id) {
177 if (!iConvertIds)
178 return id.toString();
179 return IdConvertor.getInstance().convert(type, id);
180 }
181
182 /** Generate id for given object with the given id */
183 private String getId(String type, Number id) {
184 return getId(type, id.toString());
185 }
186
187 /** Generate id for given object with the given id */
188 private String getId(String type, long id) {
189 return getId(type, String.valueOf(id));
190 }
191
192 /** Save an XML file */
193 @Override
194 public void save() throws Exception {
195 save(null);
196 }
197
198 /**
199 * Save an XML file
200 *
201 * @param outFile
202 * output file
203 */
204 public void save(File outFile) throws Exception {
205 if (outFile == null)
206 outFile = new File(iOutputFolder, "solution.xml");
207 outFile.getParentFile().mkdirs();
208 sLogger.debug("Writting XML data to:" + outFile);
209
210 Document document = DocumentHelper.createDocument();
211 document.addComment("Student Sectioning");
212
213 if ((iSaveCurrent || iSaveBest)) { // &&
214 // !getModel().assignedVariables().isEmpty()
215 StringBuffer comments = new StringBuffer("Solution Info:\n");
216 Map<String, String> solutionInfo = (getSolution() == null ? getModel().getExtendedInfo() : getSolution()
217 .getExtendedInfo());
218 for (String key : new TreeSet<String>(solutionInfo.keySet())) {
219 String value = solutionInfo.get(key);
220 comments.append(" " + key + ": " + value + "\n");
221 }
222 document.addComment(comments.toString());
223 }
224
225 Element root = document.addElement("sectioning");
226 root.addAttribute("version", "1.0");
227 root.addAttribute("initiative", getModel().getProperties().getProperty("Data.Initiative"));
228 root.addAttribute("term", getModel().getProperties().getProperty("Data.Term"));
229 root.addAttribute("year", getModel().getProperties().getProperty("Data.Year"));
230 root.addAttribute("created", String.valueOf(new Date()));
231
232 Element offeringsEl = root.addElement("offerings");
233 for (Offering offering : getModel().getOfferings()) {
234 Element offeringEl = offeringsEl.addElement("offering");
235 offeringEl.addAttribute("id", getId("offering", offering.getId()));
236 if (iShowNames)
237 offeringEl.addAttribute("name", offering.getName());
238 for (Course course : offering.getCourses()) {
239 Element courseEl = offeringEl.addElement("course");
240 courseEl.addAttribute("id", getId("course", course.getId()));
241 if (iShowNames)
242 courseEl.addAttribute("subjectArea", course.getSubjectArea());
243 if (iShowNames)
244 courseEl.addAttribute("courseNbr", course.getCourseNumber());
245 if (iShowNames && course.getLimit() >= 0)
246 courseEl.addAttribute("limit", String.valueOf(course.getLimit()));
247 if (iShowNames && course.getProjected() != 0)
248 courseEl.addAttribute("projected", String.valueOf(course.getProjected()));
249 }
250 for (Config config : offering.getConfigs()) {
251 Element configEl = offeringEl.addElement("config");
252 configEl.addAttribute("id", getId("config", config.getId()));
253 if (config.getLimit() >= 0)
254 configEl.addAttribute("limit", String.valueOf(config.getLimit()));
255 if (iShowNames)
256 configEl.addAttribute("name", config.getName());
257 for (Subpart subpart : config.getSubparts()) {
258 Element subpartEl = configEl.addElement("subpart");
259 subpartEl.addAttribute("id", getId("subpart", subpart.getId()));
260 subpartEl.addAttribute("itype", subpart.getInstructionalType());
261 if (subpart.getParent() != null)
262 subpartEl.addAttribute("parent", getId("subpart", subpart.getParent().getId()));
263 if (iShowNames)
264 subpartEl.addAttribute("name", subpart.getName());
265 if (subpart.isAllowOverlap())
266 subpartEl.addAttribute("allowOverlap", "true");
267 for (Section section : subpart.getSections()) {
268 Element sectionEl = subpartEl.addElement("section");
269 sectionEl.addAttribute("id", getId("section", section.getId()));
270 sectionEl.addAttribute("limit", String.valueOf(section.getLimit()));
271 if (section.getNameByCourse() != null)
272 for (Map.Entry<Long, String> entry: section.getNameByCourse().entrySet())
273 sectionEl.addElement("cname").addAttribute("id", entry.getKey().toString()).setText(entry.getValue());
274 if (section.getParent() != null)
275 sectionEl.addAttribute("parent", getId("section", section.getParent().getId()));
276 if (iShowNames && section.getChoice().getInstructorIds() != null)
277 sectionEl.addAttribute("instructorIds", section.getChoice().getInstructorIds());
278 if (iShowNames && section.getChoice().getInstructorNames() != null)
279 sectionEl.addAttribute("instructorNames", section.getChoice().getInstructorNames());
280 if (iShowNames)
281 sectionEl.addAttribute("name", section.getName());
282 if (section.getPlacement() != null) {
283 TimeLocation tl = section.getPlacement().getTimeLocation();
284 if (tl != null) {
285 Element timeLocationEl = sectionEl.addElement("time");
286 timeLocationEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer
287 .toBinaryString(tl.getDayCode()))));
288 timeLocationEl.addAttribute("start", String.valueOf(tl.getStartSlot()));
289 timeLocationEl.addAttribute("length", String.valueOf(tl.getLength()));
290 if (tl.getBreakTime() != 0)
291 timeLocationEl.addAttribute("breakTime", String.valueOf(tl.getBreakTime()));
292 if (iShowNames && tl.getTimePatternId() != null)
293 timeLocationEl.addAttribute("pattern", getId("timePattern", tl.getTimePatternId()));
294 if (iShowNames && tl.getDatePatternId() != null)
295 timeLocationEl.addAttribute("datePattern", tl.getDatePatternId().toString());
296 if (iShowNames && tl.getDatePatternName() != null
297 && tl.getDatePatternName().length() > 0)
298 timeLocationEl.addAttribute("datePatternName", tl.getDatePatternName());
299 timeLocationEl.addAttribute("dates", bitset2string(tl.getWeekCode()));
300 if (iShowNames)
301 timeLocationEl.setText(tl.getLongName());
302 }
303 for (RoomLocation rl : section.getRooms()) {
304 Element roomLocationEl = sectionEl.addElement("room");
305 roomLocationEl.addAttribute("id", getId("room", rl.getId()));
306 if (iShowNames && rl.getBuildingId() != null)
307 roomLocationEl.addAttribute("building", getId("building", rl.getBuildingId()));
308 if (iShowNames && rl.getName() != null)
309 roomLocationEl.addAttribute("name", rl.getName());
310 roomLocationEl.addAttribute("capacity", String.valueOf(rl.getRoomSize()));
311 if (rl.getPosX() != null && rl.getPosY() != null)
312 roomLocationEl.addAttribute("location", rl.getPosX() + "," + rl.getPosY());
313 if (rl.getIgnoreTooFar())
314 roomLocationEl.addAttribute("ignoreTooFar", "true");
315 }
316 }
317 if (iSaveOnlineSectioningInfo) {
318 if (section.getSpaceHeld() != 0.0)
319 sectionEl.addAttribute("hold", sStudentWeightFormat.format(section.getSpaceHeld()));
320 if (section.getSpaceExpected() != 0.0)
321 sectionEl.addAttribute("expect", sStudentWeightFormat
322 .format(section.getSpaceExpected()));
323 }
324 if (section.getIgnoreConflictWithSectionIds() != null && !section.getIgnoreConflictWithSectionIds().isEmpty()) {
325 Element ignoreEl = sectionEl.addElement("no-conflicts");
326 for (Long sectionId: section.getIgnoreConflictWithSectionIds())
327 ignoreEl.addElement("section").addAttribute("id", getId("section", sectionId));
328 }
329 }
330 }
331 }
332 if (!offering.getReservations().isEmpty()) {
333 for (Reservation r: offering.getReservations()) {
334 Element reservationEl = offeringEl.addElement("reservation");
335 reservationEl.addAttribute("id", getId("reservation", r.getId()));
336 reservationEl.addAttribute("expired", r.isExpired() ? "true" : "false");
337 if (r instanceof GroupReservation) {
338 GroupReservation gr = (GroupReservation)r;
339 reservationEl.addAttribute("type", "group");
340 for (Long studentId: gr.getStudentIds())
341 reservationEl.addElement("student").addAttribute("id", getId("student", studentId));
342 if (gr.getReservationLimit() >= 0.0)
343 reservationEl.addAttribute("limit", String.valueOf(gr.getReservationLimit()));
344 } else if (r instanceof IndividualReservation) {
345 reservationEl.addAttribute("type", "individual");
346 for (Long studentId: ((IndividualReservation)r).getStudentIds())
347 reservationEl.addElement("student").addAttribute("id", getId("student", studentId));
348 } else if (r instanceof CurriculumReservation) {
349 reservationEl.addAttribute("type", "curriculum");
350 CurriculumReservation cr = (CurriculumReservation)r;
351 if (cr.getReservationLimit() >= 0.0)
352 reservationEl.addAttribute("limit", String.valueOf(cr.getReservationLimit()));
353 reservationEl.addAttribute("area", cr.getAcademicArea());
354 for (String clasf: cr.getClassifications())
355 reservationEl.addElement("classification").addAttribute("code", clasf);
356 for (String major: cr.getMajors())
357 reservationEl.addElement("major").addAttribute("code", major);
358 } else if (r instanceof CourseReservation) {
359 reservationEl.addAttribute("type", "course");
360 CourseReservation cr = (CourseReservation)r;
361 reservationEl.addAttribute("course", getId("course",cr.getCourse().getId()));
362 } else if (r instanceof DummyReservation) {
363 reservationEl.addAttribute("type", "dummy");
364 }
365 for (Config config: r.getConfigs())
366 reservationEl.addElement("config").addAttribute("id", getId("config", config.getId()));
367 for (Map.Entry<Subpart, Set<Section>> entry: r.getSections().entrySet()) {
368 for (Section section: entry.getValue()) {
369 reservationEl.addElement("section").addAttribute("id", getId("section", section.getId()));
370 }
371 }
372 }
373 }
374 }
375
376 Element studentsEl = root.addElement("students");
377 for (Student student : getModel().getStudents()) {
378 Element studentEl = studentsEl.addElement("student");
379 studentEl.addAttribute("id", getId("student", student.getId()));
380 if (iShowNames) {
381 if (student.getExternalId() != null && !student.getExternalId().isEmpty())
382 studentEl.addAttribute("externalId", student.getExternalId());
383 if (student.getName() != null && !student.getName().isEmpty())
384 studentEl.addAttribute("name", student.getName());
385 if (student.getStatus() != null && !student.getStatus().isEmpty())
386 studentEl.addAttribute("status", student.getStatus());
387 }
388 if (student.isDummy())
389 studentEl.addAttribute("dummy", "true");
390 if (iSaveStudentInfo) {
391 for (AcademicAreaCode aac : student.getAcademicAreaClasiffications()) {
392 Element aacEl = studentEl.addElement("classification");
393 if (aac.getArea() != null)
394 aacEl.addAttribute("area", aac.getArea());
395 if (aac.getCode() != null)
396 aacEl.addAttribute("code", aac.getCode());
397 }
398 for (AcademicAreaCode aac : student.getMajors()) {
399 Element aacEl = studentEl.addElement("major");
400 if (aac.getArea() != null)
401 aacEl.addAttribute("area", aac.getArea());
402 if (aac.getCode() != null)
403 aacEl.addAttribute("code", aac.getCode());
404 }
405 for (AcademicAreaCode aac : student.getMinors()) {
406 Element aacEl = studentEl.addElement("minor");
407 if (aac.getArea() != null)
408 aacEl.addAttribute("area", aac.getArea());
409 if (aac.getCode() != null)
410 aacEl.addAttribute("code", aac.getCode());
411 }
412 }
413 for (Request request : student.getRequests()) {
414 if (request instanceof FreeTimeRequest) {
415 Element requestEl = studentEl.addElement("freeTime");
416 FreeTimeRequest ft = (FreeTimeRequest) request;
417 requestEl.addAttribute("id", getId("request", request.getId()));
418 requestEl.addAttribute("priority", String.valueOf(request.getPriority()));
419 if (request.isAlternative())
420 requestEl.addAttribute("alternative", "true");
421 if (request.getWeight() != 1.0)
422 requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight()));
423 TimeLocation tl = ft.getTime();
424 if (tl != null) {
425 requestEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer.toBinaryString(tl
426 .getDayCode()))));
427 requestEl.addAttribute("start", String.valueOf(tl.getStartSlot()));
428 requestEl.addAttribute("length", String.valueOf(tl.getLength()));
429 if (iShowNames && tl.getDatePatternId() != null)
430 requestEl.addAttribute("datePattern", tl.getDatePatternId().toString());
431 requestEl.addAttribute("dates", bitset2string(tl.getWeekCode()));
432 if (iShowNames)
433 requestEl.setText(tl.getLongName());
434 }
435 if (iSaveInitial && request.getInitialAssignment() != null) {
436 requestEl.addElement("initial");
437 }
438 if (iSaveCurrent && request.getAssignment() != null) {
439 requestEl.addElement("current");
440 }
441 if (iSaveBest && request.getBestAssignment() != null) {
442 requestEl.addElement("best");
443 }
444 } else if (request instanceof CourseRequest) {
445 CourseRequest cr = (CourseRequest) request;
446 Element requestEl = studentEl.addElement("course");
447 requestEl.addAttribute("id", getId("request", request.getId()));
448 requestEl.addAttribute("priority", String.valueOf(request.getPriority()));
449 if (request.isAlternative())
450 requestEl.addAttribute("alternative", "true");
451 if (request.getWeight() != 1.0)
452 requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight()));
453 requestEl.addAttribute("waitlist", cr.isWaitlist() ? "true" : "false");
454 if (cr.getTimeStamp() != null)
455 requestEl.addAttribute("timeStamp", cr.getTimeStamp().toString());
456 boolean first = true;
457 for (Course course : cr.getCourses()) {
458 if (first)
459 requestEl.addAttribute("course", getId("course", course.getId()));
460 else
461 requestEl.addElement("alternative").addAttribute("course", getId("course", course.getId()));
462 first = false;
463 }
464 for (Choice choice : cr.getWaitlistedChoices()) {
465 Element choiceEl = requestEl.addElement("waitlisted");
466 choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId()));
467 choiceEl.setText(choice.getId());
468 }
469 for (Choice choice : cr.getSelectedChoices()) {
470 Element choiceEl = requestEl.addElement("selected");
471 choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId()));
472 choiceEl.setText(choice.getId());
473 }
474 if (iSaveInitial && request.getInitialAssignment() != null) {
475 Element assignmentEl = requestEl.addElement("initial");
476 Enrollment enrollment = request.getInitialAssignment();
477 if (enrollment.getReservation() != null)
478 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId()));
479 for (Section section : enrollment.getSections()) {
480 Element sectionEl = assignmentEl.addElement("section").addAttribute("id",
481 getId("section", section.getId()));
482 if (iShowNames)
483 sectionEl.setText(section.getName()
484 + " "
485 + (section.getTime() == null ? " Arr Hrs" : " "
486 + section.getTime().getLongName())
487 + (section.getNrRooms() == 0 ? "" : " "
488 + section.getPlacement().getRoomName(","))
489 + (section.getChoice().getInstructorNames() == null ? "" : " "
490 + section.getChoice().getInstructorNames()));
491 }
492 }
493 if (iSaveCurrent && request.getAssignment() != null) {
494 Element assignmentEl = requestEl.addElement("current");
495 Enrollment enrollment = request.getAssignment();
496 if (enrollment.getReservation() != null)
497 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId()));
498 for (Section section : enrollment.getSections()) {
499 Element sectionEl = assignmentEl.addElement("section").addAttribute("id",
500 getId("section", section.getId()));
501 if (iShowNames)
502 sectionEl.setText(section.getName()
503 + " "
504 + (section.getTime() == null ? " Arr Hrs" : " "
505 + section.getTime().getLongName())
506 + (section.getNrRooms() == 0 ? "" : " "
507 + section.getPlacement().getRoomName(","))
508 + (section.getChoice().getInstructorNames() == null ? "" : " "
509 + section.getChoice().getInstructorNames()));
510 }
511 }
512 if (iSaveBest && request.getBestAssignment() != null) {
513 Element assignmentEl = requestEl.addElement("best");
514 Enrollment enrollment = request.getBestAssignment();
515 if (enrollment.getReservation() != null)
516 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId()));
517 for (Section section : enrollment.getSections()) {
518 Element sectionEl = assignmentEl.addElement("section").addAttribute("id",
519 getId("section", section.getId()));
520 if (iShowNames)
521 sectionEl.setText(section.getName()
522 + " "
523 + (section.getTime() == null ? " Arr Hrs" : " "
524 + section.getTime().getLongName())
525 + (section.getNrRooms() == 0 ? "" : " "
526 + section.getPlacement().getRoomName(","))
527 + (section.getChoice().getInstructorNames() == null ? "" : " "
528 + section.getChoice().getInstructorNames()));
529 }
530 }
531 }
532 }
533 }
534
535 Element constrainstEl = root.addElement("constraints");
536 for (LinkedSections linkedSections: getModel().getLinkedSections()) {
537 Element linkEl = constrainstEl.addElement("linked-sections");
538 for (Offering offering: linkedSections.getOfferings())
539 for (Subpart subpart: linkedSections.getSubparts(offering))
540 for (Section section: linkedSections.getSections(subpart))
541 linkEl.addElement("section")
542 .addAttribute("offering", getId("offering", offering.getId()))
543 .addAttribute("id", getId("section", section.getId()));
544 }
545
546 if (getModel().getDistanceConflict() != null) {
547 Map<Long, Map<Long, Integer>> travelTimes = getModel().getDistanceConflict().getDistanceMetric().getTravelTimes();
548 if (travelTimes != null) {
549 Element travelTimesEl = root.addElement("travel-times");
550 for (Map.Entry<Long, Map<Long, Integer>> e1: travelTimes.entrySet())
551 for (Map.Entry<Long, Integer> e2: e1.getValue().entrySet())
552 travelTimesEl.addElement("travel-time")
553 .addAttribute("id1", getId("room", e1.getKey().toString()))
554 .addAttribute("id2", getId("room", e2.getKey().toString()))
555 .addAttribute("minutes", e2.getValue().toString());
556 }
557 }
558
559
560 if (iShowNames) {
561 Progress.getInstance(getModel()).save(root);
562 }
563
564 FileOutputStream fos = null;
565 try {
566 fos = new FileOutputStream(outFile);
567 (new XMLWriter(fos, OutputFormat.createPrettyPrint())).write(document);
568 fos.flush();
569 fos.close();
570 fos = null;
571 } finally {
572 try {
573 if (fos != null)
574 fos.close();
575 } catch (IOException e) {
576 }
577 }
578
579 if (iConvertIds)
580 IdConvertor.getInstance().save();
581 }
582
583 }