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