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 } 325 } 326 } 327 if (!offering.getReservations().isEmpty()) { 328 for (Reservation r: offering.getReservations()) { 329 Element reservationEl = offeringEl.addElement("reservation"); 330 reservationEl.addAttribute("id", getId("reservation", r.getId())); 331 reservationEl.addAttribute("expired", r.isExpired() ? "true" : "false"); 332 if (r instanceof GroupReservation) { 333 GroupReservation gr = (GroupReservation)r; 334 reservationEl.addAttribute("type", "group"); 335 for (Long studentId: gr.getStudentIds()) 336 reservationEl.addElement("student").addAttribute("id", getId("student", studentId)); 337 if (gr.getReservationLimit() >= 0.0) 338 reservationEl.addAttribute("limit", String.valueOf(gr.getReservationLimit())); 339 } else if (r instanceof IndividualReservation) { 340 reservationEl.addAttribute("type", "individual"); 341 for (Long studentId: ((IndividualReservation)r).getStudentIds()) 342 reservationEl.addElement("student").addAttribute("id", getId("student", studentId)); 343 } else if (r instanceof CurriculumReservation) { 344 reservationEl.addAttribute("type", "curriculum"); 345 CurriculumReservation cr = (CurriculumReservation)r; 346 if (cr.getReservationLimit() >= 0.0) 347 reservationEl.addAttribute("limit", String.valueOf(cr.getReservationLimit())); 348 reservationEl.addAttribute("area", cr.getAcademicArea()); 349 for (String clasf: cr.getClassifications()) 350 reservationEl.addElement("classification").addAttribute("code", clasf); 351 for (String major: cr.getMajors()) 352 reservationEl.addElement("major").addAttribute("code", major); 353 } else if (r instanceof CourseReservation) { 354 reservationEl.addAttribute("type", "course"); 355 CourseReservation cr = (CourseReservation)r; 356 reservationEl.addAttribute("course", getId("course",cr.getCourse().getId())); 357 } else if (r instanceof DummyReservation) { 358 reservationEl.addAttribute("type", "dummy"); 359 } 360 for (Config config: r.getConfigs()) 361 reservationEl.addElement("config").addAttribute("id", getId("config", config.getId())); 362 for (Map.Entry<Subpart, Set<Section>> entry: r.getSections().entrySet()) { 363 for (Section section: entry.getValue()) { 364 reservationEl.addElement("section").addAttribute("id", getId("section", section.getId())); 365 } 366 } 367 } 368 } 369 } 370 371 Element studentsEl = root.addElement("students"); 372 for (Student student : getModel().getStudents()) { 373 Element studentEl = studentsEl.addElement("student"); 374 studentEl.addAttribute("id", getId("student", student.getId())); 375 if (iShowNames) { 376 if (student.getExternalId() != null && !student.getExternalId().isEmpty()) 377 studentEl.addAttribute("externalId", student.getExternalId()); 378 if (student.getName() != null && !student.getName().isEmpty()) 379 studentEl.addAttribute("name", student.getName()); 380 if (student.getStatus() != null && !student.getStatus().isEmpty()) 381 studentEl.addAttribute("status", student.getStatus()); 382 } 383 if (student.isDummy()) 384 studentEl.addAttribute("dummy", "true"); 385 if (iSaveStudentInfo) { 386 for (AcademicAreaCode aac : student.getAcademicAreaClasiffications()) { 387 Element aacEl = studentEl.addElement("classification"); 388 if (aac.getArea() != null) 389 aacEl.addAttribute("area", aac.getArea()); 390 if (aac.getCode() != null) 391 aacEl.addAttribute("code", aac.getCode()); 392 } 393 for (AcademicAreaCode aac : student.getMajors()) { 394 Element aacEl = studentEl.addElement("major"); 395 if (aac.getArea() != null) 396 aacEl.addAttribute("area", aac.getArea()); 397 if (aac.getCode() != null) 398 aacEl.addAttribute("code", aac.getCode()); 399 } 400 for (AcademicAreaCode aac : student.getMinors()) { 401 Element aacEl = studentEl.addElement("minor"); 402 if (aac.getArea() != null) 403 aacEl.addAttribute("area", aac.getArea()); 404 if (aac.getCode() != null) 405 aacEl.addAttribute("code", aac.getCode()); 406 } 407 } 408 for (Request request : student.getRequests()) { 409 if (request instanceof FreeTimeRequest) { 410 Element requestEl = studentEl.addElement("freeTime"); 411 FreeTimeRequest ft = (FreeTimeRequest) request; 412 requestEl.addAttribute("id", getId("request", request.getId())); 413 requestEl.addAttribute("priority", String.valueOf(request.getPriority())); 414 if (request.isAlternative()) 415 requestEl.addAttribute("alternative", "true"); 416 if (request.getWeight() != 1.0) 417 requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight())); 418 TimeLocation tl = ft.getTime(); 419 if (tl != null) { 420 requestEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer.toBinaryString(tl 421 .getDayCode())))); 422 requestEl.addAttribute("start", String.valueOf(tl.getStartSlot())); 423 requestEl.addAttribute("length", String.valueOf(tl.getLength())); 424 if (iShowNames && tl.getDatePatternId() != null) 425 requestEl.addAttribute("datePattern", tl.getDatePatternId().toString()); 426 requestEl.addAttribute("dates", bitset2string(tl.getWeekCode())); 427 if (iShowNames) 428 requestEl.setText(tl.getLongName()); 429 } 430 if (iSaveInitial && request.getInitialAssignment() != null) { 431 requestEl.addElement("initial"); 432 } 433 if (iSaveCurrent && request.getAssignment() != null) { 434 requestEl.addElement("current"); 435 } 436 if (iSaveBest && request.getBestAssignment() != null) { 437 requestEl.addElement("best"); 438 } 439 } else if (request instanceof CourseRequest) { 440 CourseRequest cr = (CourseRequest) request; 441 Element requestEl = studentEl.addElement("course"); 442 requestEl.addAttribute("id", getId("request", request.getId())); 443 requestEl.addAttribute("priority", String.valueOf(request.getPriority())); 444 if (request.isAlternative()) 445 requestEl.addAttribute("alternative", "true"); 446 if (request.getWeight() != 1.0) 447 requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight())); 448 requestEl.addAttribute("waitlist", cr.isWaitlist() ? "true" : "false"); 449 if (cr.getTimeStamp() != null) 450 requestEl.addAttribute("timeStamp", cr.getTimeStamp().toString()); 451 boolean first = true; 452 for (Course course : cr.getCourses()) { 453 if (first) 454 requestEl.addAttribute("course", getId("course", course.getId())); 455 else 456 requestEl.addElement("alternative").addAttribute("course", getId("course", course.getId())); 457 first = false; 458 } 459 for (Choice choice : cr.getWaitlistedChoices()) { 460 Element choiceEl = requestEl.addElement("waitlisted"); 461 choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId())); 462 choiceEl.setText(choice.getId()); 463 } 464 for (Choice choice : cr.getSelectedChoices()) { 465 Element choiceEl = requestEl.addElement("selected"); 466 choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId())); 467 choiceEl.setText(choice.getId()); 468 } 469 if (iSaveInitial && request.getInitialAssignment() != null) { 470 Element assignmentEl = requestEl.addElement("initial"); 471 Enrollment enrollment = request.getInitialAssignment(); 472 if (enrollment.getReservation() != null) 473 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId())); 474 for (Section section : enrollment.getSections()) { 475 Element sectionEl = assignmentEl.addElement("section").addAttribute("id", 476 getId("section", section.getId())); 477 if (iShowNames) 478 sectionEl.setText(section.getName() 479 + " " 480 + (section.getTime() == null ? " Arr Hrs" : " " 481 + section.getTime().getLongName()) 482 + (section.getNrRooms() == 0 ? "" : " " 483 + section.getPlacement().getRoomName(",")) 484 + (section.getChoice().getInstructorNames() == null ? "" : " " 485 + section.getChoice().getInstructorNames())); 486 } 487 } 488 if (iSaveCurrent && request.getAssignment() != null) { 489 Element assignmentEl = requestEl.addElement("current"); 490 Enrollment enrollment = request.getAssignment(); 491 if (enrollment.getReservation() != null) 492 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId())); 493 for (Section section : enrollment.getSections()) { 494 Element sectionEl = assignmentEl.addElement("section").addAttribute("id", 495 getId("section", section.getId())); 496 if (iShowNames) 497 sectionEl.setText(section.getName() 498 + " " 499 + (section.getTime() == null ? " Arr Hrs" : " " 500 + section.getTime().getLongName()) 501 + (section.getNrRooms() == 0 ? "" : " " 502 + section.getPlacement().getRoomName(",")) 503 + (section.getChoice().getInstructorNames() == null ? "" : " " 504 + section.getChoice().getInstructorNames())); 505 } 506 } 507 if (iSaveBest && request.getBestAssignment() != null) { 508 Element assignmentEl = requestEl.addElement("best"); 509 Enrollment enrollment = request.getBestAssignment(); 510 if (enrollment.getReservation() != null) 511 assignmentEl.addAttribute("reservation", getId("reservation", enrollment.getReservation().getId())); 512 for (Section section : enrollment.getSections()) { 513 Element sectionEl = assignmentEl.addElement("section").addAttribute("id", 514 getId("section", section.getId())); 515 if (iShowNames) 516 sectionEl.setText(section.getName() 517 + " " 518 + (section.getTime() == null ? " Arr Hrs" : " " 519 + section.getTime().getLongName()) 520 + (section.getNrRooms() == 0 ? "" : " " 521 + section.getPlacement().getRoomName(",")) 522 + (section.getChoice().getInstructorNames() == null ? "" : " " 523 + section.getChoice().getInstructorNames())); 524 } 525 } 526 } 527 } 528 } 529 530 Element constrainstEl = root.addElement("constraints"); 531 for (LinkedSections linkedSections: getModel().getLinkedSections()) { 532 Element linkEl = constrainstEl.addElement("linked-sections"); 533 for (Offering offering: linkedSections.getOfferings()) 534 for (Subpart subpart: linkedSections.getSubparts(offering)) 535 for (Section section: linkedSections.getSections(subpart)) 536 linkEl.addElement("section") 537 .addAttribute("offering", getId("offering", offering.getId())) 538 .addAttribute("id", getId("section", section.getId())); 539 } 540 541 if (getModel().getDistanceConflict() != null) { 542 Map<Long, Map<Long, Integer>> travelTimes = getModel().getDistanceConflict().getDistanceMetric().getTravelTimes(); 543 if (travelTimes != null) { 544 Element travelTimesEl = root.addElement("travel-times"); 545 for (Map.Entry<Long, Map<Long, Integer>> e1: travelTimes.entrySet()) 546 for (Map.Entry<Long, Integer> e2: e1.getValue().entrySet()) 547 travelTimesEl.addElement("travel-time") 548 .addAttribute("id1", getId("room", e1.getKey().toString())) 549 .addAttribute("id2", getId("room", e2.getKey().toString())) 550 .addAttribute("minutes", e2.getValue().toString()); 551 } 552 } 553 554 555 if (iShowNames) { 556 Progress.getInstance(getModel()).save(root); 557 } 558 559 FileOutputStream fos = null; 560 try { 561 fos = new FileOutputStream(outFile); 562 (new XMLWriter(fos, OutputFormat.createPrettyPrint())).write(document); 563 fos.flush(); 564 fos.close(); 565 fos = null; 566 } finally { 567 try { 568 if (fos != null) 569 fos.close(); 570 } catch (IOException e) { 571 } 572 } 573 574 if (iConvertIds) 575 IdConvertor.getInstance().save(); 576 } 577 578 }