001package org.cpsolver.studentsct; 002 003import java.io.File; 004import java.util.ArrayList; 005import java.util.BitSet; 006import java.util.HashSet; 007import java.util.HashMap; 008import java.util.Iterator; 009import java.util.List; 010import java.util.Map; 011import java.util.Set; 012 013import org.cpsolver.coursett.model.Placement; 014import org.cpsolver.coursett.model.RoomLocation; 015import org.cpsolver.coursett.model.TimeLocation; 016import org.cpsolver.ifs.assignment.Assignment; 017import org.cpsolver.ifs.model.Constraint; 018import org.cpsolver.ifs.util.Progress; 019import org.cpsolver.studentsct.filter.StudentFilter; 020import org.cpsolver.studentsct.model.AcademicAreaCode; 021import org.cpsolver.studentsct.model.Choice; 022import org.cpsolver.studentsct.model.Config; 023import org.cpsolver.studentsct.model.Course; 024import org.cpsolver.studentsct.model.CourseRequest; 025import org.cpsolver.studentsct.model.Enrollment; 026import org.cpsolver.studentsct.model.FreeTimeRequest; 027import org.cpsolver.studentsct.model.Offering; 028import org.cpsolver.studentsct.model.Request; 029import org.cpsolver.studentsct.model.Section; 030import org.cpsolver.studentsct.model.Student; 031import org.cpsolver.studentsct.model.Subpart; 032import org.cpsolver.studentsct.reservation.CourseReservation; 033import org.cpsolver.studentsct.reservation.CurriculumReservation; 034import org.cpsolver.studentsct.reservation.DummyReservation; 035import org.cpsolver.studentsct.reservation.GroupReservation; 036import org.cpsolver.studentsct.reservation.IndividualReservation; 037import org.cpsolver.studentsct.reservation.Reservation; 038import org.cpsolver.studentsct.reservation.ReservationOverride; 039import org.dom4j.Document; 040import org.dom4j.Element; 041import org.dom4j.io.SAXReader; 042 043/** 044 * Load student sectioning model from an XML file. 045 * 046 * <br> 047 * <br> 048 * Parameters: 049 * <table border='1' summary='Related Solver Parameters'> 050 * <tr> 051 * <th>Parameter</th> 052 * <th>Type</th> 053 * <th>Comment</th> 054 * </tr> 055 * <tr> 056 * <td>General.Input</td> 057 * <td>{@link String}</td> 058 * <td>Path of an XML file to be loaded</td> 059 * </tr> 060 * <tr> 061 * <td>Xml.LoadBest</td> 062 * <td>{@link Boolean}</td> 063 * <td>If true, load best assignments</td> 064 * </tr> 065 * <tr> 066 * <td>Xml.LoadInitial</td> 067 * <td>{@link Boolean}</td> 068 * <td>If false, load initial assignments</td> 069 * </tr> 070 * <tr> 071 * <td>Xml.LoadCurrent</td> 072 * <td>{@link Boolean}</td> 073 * <td>If true, load current assignments</td> 074 * </tr> 075 * <tr> 076 * <td>Xml.LoadOfferings</td> 077 * <td>{@link Boolean}</td> 078 * <td>If true, load offerings (and their stucture, i.e., courses, 079 * configurations, subparts and sections)</td> 080 * </tr> 081 * <tr> 082 * <td>Xml.LoadStudents</td> 083 * <td>{@link Boolean}</td> 084 * <td>If true, load students (and their requests)</td> 085 * </tr> 086 * <tr> 087 * <td>Xml.StudentFilter</td> 088 * <td>{@link StudentFilter}</td> 089 * <td>If provided, students are filtered by the given student filter</td> 090 * </tr> 091 * </table> 092 * 093 * <br> 094 * <br> 095 * Usage: 096 * <pre><code> 097 * StudentSectioningModel model = new StudentSectioningModel(cfg);<br> 098 * new StudentSectioningXMLLoader(model).load();<br> 099 * </code></pre> 100 * 101 * @version StudentSct 1.3 (Student Sectioning)<br> 102 * Copyright (C) 2007 - 2014 Tomas Muller<br> 103 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 104 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 105 * <br> 106 * This library is free software; you can redistribute it and/or modify 107 * it under the terms of the GNU Lesser General Public License as 108 * published by the Free Software Foundation; either version 3 of the 109 * License, or (at your option) any later version. <br> 110 * <br> 111 * This library is distributed in the hope that it will be useful, but 112 * WITHOUT ANY WARRANTY; without even the implied warranty of 113 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 114 * Lesser General Public License for more details. <br> 115 * <br> 116 * You should have received a copy of the GNU Lesser General Public 117 * License along with this library; if not see 118 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 119 */ 120 121public class StudentSectioningXMLLoader extends StudentSectioningLoader { 122 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger 123 .getLogger(StudentSectioningXMLLoader.class); 124 125 private File iInputFile; 126 private File iTimetableFile = null; 127 private boolean iLoadBest = false; 128 private boolean iLoadInitial = false; 129 private boolean iLoadCurrent = false; 130 private boolean iLoadOfferings = true; 131 private boolean iLoadStudents = true; 132 private StudentFilter iStudentFilter = null; 133 134 /** 135 * Constructor 136 * 137 * @param model 138 * student sectioning model 139 * @param assignment current assignment 140 */ 141 public StudentSectioningXMLLoader(StudentSectioningModel model, Assignment<Request, Enrollment> assignment) { 142 super(model, assignment); 143 iInputFile = new File(getModel().getProperties().getProperty("General.Input", 144 "." + File.separator + "solution.xml")); 145 if (getModel().getProperties().getProperty("General.InputTimetable") != null) 146 iTimetableFile = new File(getModel().getProperties().getProperty("General.InputTimetable")); 147 iLoadBest = getModel().getProperties().getPropertyBoolean("Xml.LoadBest", true); 148 iLoadInitial = getModel().getProperties().getPropertyBoolean("Xml.LoadInitial", true); 149 iLoadCurrent = getModel().getProperties().getPropertyBoolean("Xml.LoadCurrent", true); 150 iLoadOfferings = getModel().getProperties().getPropertyBoolean("Xml.LoadOfferings", true); 151 iLoadStudents = getModel().getProperties().getPropertyBoolean("Xml.LoadStudents", true); 152 if (getModel().getProperties().getProperty("Xml.StudentFilter") != null) { 153 try { 154 iStudentFilter = (StudentFilter) Class.forName( 155 getModel().getProperties().getProperty("Xml.StudentFilter")).getConstructor(new Class[] {}) 156 .newInstance(new Object[] {}); 157 } catch (Exception e) { 158 sLogger.error("Unable to create student filter, reason: " + e.getMessage(), e); 159 } 160 } 161 } 162 163 /** Set input file (e.g., if it is not set by General.Input property) 164 * @param inputFile input file 165 **/ 166 public void setInputFile(File inputFile) { 167 iInputFile = inputFile; 168 } 169 170 /** Set student filter 171 * @param filter student filter 172 **/ 173 public void setStudentFilter(StudentFilter filter) { 174 iStudentFilter = filter; 175 } 176 177 /** Set whether to load students 178 * @param loadStudents true if students are to be loaded 179 **/ 180 public void setLoadStudents(boolean loadStudents) { 181 iLoadStudents = loadStudents; 182 } 183 184 /** Set whether to load offerings 185 * @param loadOfferings true if instructional offerings are to be loaded 186 **/ 187 public void setLoadOfferings(boolean loadOfferings) { 188 iLoadOfferings = loadOfferings; 189 } 190 191 /** Create BitSet from a bit string */ 192 private static BitSet createBitSet(String bitString) { 193 BitSet ret = new BitSet(bitString.length()); 194 for (int i = 0; i < bitString.length(); i++) 195 if (bitString.charAt(i) == '1') 196 ret.set(i); 197 return ret; 198 } 199 200 /** Load the file */ 201 @Override 202 public void load() throws Exception { 203 sLogger.debug("Reading XML data from " + iInputFile); 204 205 Document document = (new SAXReader()).read(iInputFile); 206 Element root = document.getRootElement(); 207 sLogger.debug("Root element: " + root.getName()); 208 if (!"sectioning".equals(root.getName())) { 209 sLogger.error("Given XML file is not student sectioning problem."); 210 return; 211 } 212 213 if (iLoadOfferings && getModel().getDistanceConflict() != null && root.element("travel-times") != null) { 214 for (Iterator<?> i = root.element("travel-times").elementIterator("travel-time"); i.hasNext();) { 215 Element travelTimeEl = (Element)i.next(); 216 getModel().getDistanceConflict().getDistanceMetric().addTravelTime( 217 Long.valueOf(travelTimeEl.attributeValue("id1")), 218 Long.valueOf(travelTimeEl.attributeValue("id2")), 219 Integer.valueOf(travelTimeEl.attributeValue("minutes"))); 220 } 221 } 222 223 HashMap<Long, Placement> timetable = null; 224 if (iTimetableFile != null) { 225 sLogger.info("Reading timetable from " + iTimetableFile + " ..."); 226 Document timetableDocument = (new SAXReader()).read(iTimetableFile); 227 Element timetableRoot = timetableDocument.getRootElement(); 228 if (!"timetable".equals(timetableRoot.getName())) { 229 sLogger.error("Given XML file is not course timetabling problem."); 230 return; 231 } 232 timetable = new HashMap<Long, Placement>(); 233 HashMap<Long, RoomLocation> rooms = new HashMap<Long, RoomLocation>(); 234 for (Iterator<?> i = timetableRoot.element("rooms").elementIterator("room"); i.hasNext();) { 235 Element roomEl = (Element)i.next(); 236 Long roomId = Long.valueOf(roomEl.attributeValue("id")); 237 Double posX = null, posY = null; 238 if (roomEl.attributeValue("location") != null) { 239 String loc = roomEl.attributeValue("location"); 240 posX = Double.valueOf(loc.substring(0, loc.indexOf(','))); 241 posY = Double.valueOf(loc.substring(loc.indexOf(',') + 1)); 242 } 243 RoomLocation room = new RoomLocation(Long.valueOf(roomEl.attributeValue("id")), roomEl 244 .attributeValue("name", "R" + roomEl.attributeValue("id")), roomEl 245 .attributeValue("building") == null ? null : Long.valueOf(roomEl 246 .attributeValue("building")), 0, Integer.parseInt(roomEl 247 .attributeValue("capacity")), posX, posY, "true".equals(roomEl 248 .attributeValue("ignoreTooFar")), null); 249 rooms.put(roomId, room); 250 } 251 for (Iterator<?> i = timetableRoot.element("classes").elementIterator("class"); i.hasNext();) { 252 Element classEl = (Element)i.next(); 253 Long classId = Long.valueOf(classEl.attributeValue("id")); 254 TimeLocation time = null; 255 Element timeEl = null; 256 for (Iterator<?> j = classEl.elementIterator("time"); j.hasNext(); ) { 257 Element e = (Element)j.next(); 258 if ("true".equals(e.attributeValue("solution", "false"))) { timeEl = e; break; } 259 } 260 if (timeEl != null) { 261 time = new TimeLocation(Integer.parseInt(timeEl.attributeValue("days"), 2), Integer 262 .parseInt(timeEl.attributeValue("start")), Integer.parseInt(timeEl 263 .attributeValue("length")), 0, 0, 264 classEl.attributeValue("datePattern") == null ? null : Long.valueOf(classEl 265 .attributeValue("datePattern")), classEl.attributeValue( 266 "datePatternName", ""), createBitSet(classEl.attributeValue("dates")), 267 Integer.parseInt(timeEl.attributeValue("breakTime", "0"))); 268 if (timeEl.attributeValue("pattern") != null) 269 time.setTimePatternId(Long.valueOf(timeEl.attributeValue("pattern"))); 270 } 271 List<RoomLocation> room = new ArrayList<RoomLocation>(); 272 for (Iterator<?> j = classEl.elementIterator("room"); j.hasNext();) { 273 Element roomEl = (Element) j.next(); 274 if (!"true".equals(roomEl.attributeValue("solution", "false"))) continue; 275 room.add(rooms.get(Long.valueOf(roomEl.attributeValue("id")))); 276 } 277 Placement placement = (time == null ? null : new Placement(null, time, room)); 278 if (placement != null) 279 timetable.put(classId, placement); 280 } 281 } 282 283 Progress.getInstance(getModel()).load(root, true); 284 Progress.getInstance(getModel()).message(Progress.MSGLEVEL_STAGE, "Restoring from backup ..."); 285 286 if (root.attributeValue("term") != null) 287 getModel().getProperties().setProperty("Data.Term", root.attributeValue("term")); 288 if (root.attributeValue("year") != null) 289 getModel().getProperties().setProperty("Data.Year", root.attributeValue("year")); 290 if (root.attributeValue("initiative") != null) 291 getModel().getProperties().setProperty("Data.Initiative", root.attributeValue("initiative")); 292 293 HashMap<Long, Offering> offeringTable = new HashMap<Long, Offering>(); 294 HashMap<Long, Course> courseTable = new HashMap<Long, Course>(); 295 296 if (iLoadOfferings && root.element("offerings") != null) { 297 HashMap<Long, Config> configTable = new HashMap<Long, Config>(); 298 HashMap<Long, Subpart> subpartTable = new HashMap<Long, Subpart>(); 299 HashMap<Long, Section> sectionTable = new HashMap<Long, Section>(); 300 for (Iterator<?> i = root.element("offerings").elementIterator("offering"); i.hasNext();) { 301 Element offeringEl = (Element) i.next(); 302 Offering offering = new Offering(Long.parseLong(offeringEl.attributeValue("id")), offeringEl 303 .attributeValue("name", "O" + offeringEl.attributeValue("id"))); 304 offeringTable.put(new Long(offering.getId()), offering); 305 getModel().addOffering(offering); 306 for (Iterator<?> j = offeringEl.elementIterator("course"); j.hasNext();) { 307 Element courseEl = (Element) j.next(); 308 Course course = new Course(Long.parseLong(courseEl.attributeValue("id")), courseEl.attributeValue( 309 "subjectArea", ""), courseEl.attributeValue("courseNbr", "C" 310 + courseEl.attributeValue("id")), offering, Integer.parseInt(courseEl.attributeValue( 311 "limit", "-1")), Integer.parseInt(courseEl.attributeValue("projected", "0"))); 312 courseTable.put(new Long(course.getId()), course); 313 } 314 for (Iterator<?> j = offeringEl.elementIterator("config"); j.hasNext();) { 315 Element configEl = (Element) j.next(); 316 Config config = new Config(Long.parseLong(configEl.attributeValue("id")), 317 Integer.parseInt(configEl.attributeValue("limit", "-1")), 318 configEl.attributeValue("name", "G" + configEl.attributeValue("id")), 319 offering); 320 configTable.put(config.getId(), config); 321 for (Iterator<?> k = configEl.elementIterator("subpart"); k.hasNext();) { 322 Element subpartEl = (Element) k.next(); 323 Subpart parentSubpart = null; 324 if (subpartEl.attributeValue("parent") != null) 325 parentSubpart = subpartTable.get(Long.valueOf(subpartEl.attributeValue("parent"))); 326 Subpart subpart = new Subpart(Long.parseLong(subpartEl.attributeValue("id")), subpartEl 327 .attributeValue("itype"), subpartEl.attributeValue("name", "P" 328 + subpartEl.attributeValue("id")), config, parentSubpart); 329 subpart.setAllowOverlap("true".equals(subpartEl.attributeValue("allowOverlap", "false"))); 330 subpartTable.put(new Long(subpart.getId()), subpart); 331 for (Iterator<?> l = subpartEl.elementIterator("section"); l.hasNext();) { 332 Element sectionEl = (Element) l.next(); 333 Section parentSection = null; 334 if (sectionEl.attributeValue("parent") != null) 335 parentSection = sectionTable.get(Long.valueOf(sectionEl.attributeValue("parent"))); 336 Placement placement = null; 337 if (timetable != null) { 338 placement = timetable.get(Long.parseLong(sectionEl.attributeValue("id"))); 339 } else { 340 TimeLocation time = null; 341 Element timeEl = sectionEl.element("time"); 342 if (timeEl != null) { 343 time = new TimeLocation(Integer.parseInt(timeEl.attributeValue("days"), 2), Integer 344 .parseInt(timeEl.attributeValue("start")), Integer.parseInt(timeEl 345 .attributeValue("length")), 0, 0, 346 timeEl.attributeValue("datePattern") == null ? null : Long.valueOf(timeEl 347 .attributeValue("datePattern")), timeEl.attributeValue( 348 "datePatternName", ""), createBitSet(timeEl.attributeValue("dates")), 349 Integer.parseInt(timeEl.attributeValue("breakTime", "0"))); 350 if (timeEl.attributeValue("pattern") != null) 351 time.setTimePatternId(Long.valueOf(timeEl.attributeValue("pattern"))); 352 } 353 List<RoomLocation> rooms = new ArrayList<RoomLocation>(); 354 for (Iterator<?> m = sectionEl.elementIterator("room"); m.hasNext();) { 355 Element roomEl = (Element) m.next(); 356 Double posX = null, posY = null; 357 if (roomEl.attributeValue("location") != null) { 358 String loc = roomEl.attributeValue("location"); 359 posX = Double.valueOf(loc.substring(0, loc.indexOf(','))); 360 posY = Double.valueOf(loc.substring(loc.indexOf(',') + 1)); 361 } 362 RoomLocation room = new RoomLocation(Long.valueOf(roomEl.attributeValue("id")), roomEl 363 .attributeValue("name", "R" + roomEl.attributeValue("id")), roomEl 364 .attributeValue("building") == null ? null : Long.valueOf(roomEl 365 .attributeValue("building")), 0, Integer.parseInt(roomEl 366 .attributeValue("capacity")), posX, posY, "true".equals(roomEl 367 .attributeValue("ignoreTooFar")), null); 368 rooms.add(room); 369 } 370 placement = (time == null ? null : new Placement(null, time, rooms)); 371 } 372 Section section = new Section(Long.parseLong(sectionEl.attributeValue("id")), Integer 373 .parseInt(sectionEl.attributeValue("limit")), sectionEl.attributeValue("name", "S" 374 + sectionEl.attributeValue("id")), subpart, placement, sectionEl 375 .attributeValue("instructorIds"), sectionEl.attributeValue("instructorNames"), 376 parentSection); 377 sectionTable.put(new Long(section.getId()), section); 378 section.setSpaceHeld(Double.parseDouble(sectionEl.attributeValue("hold", "0.0"))); 379 section.setSpaceExpected(Double.parseDouble(sectionEl.attributeValue("expect", "0.0"))); 380 for (Iterator<?> m = sectionEl.elementIterator("cname"); m.hasNext(); ) { 381 Element cNameEl = (Element)m.next(); 382 section.setName(Long.parseLong(cNameEl.attributeValue("id")), cNameEl.getText()); 383 } 384 Element ignoreEl = sectionEl.element("no-conflicts"); 385 if (ignoreEl != null) { 386 for (Iterator<?> m = ignoreEl.elementIterator("section"); m.hasNext(); ) 387 section.addIgnoreConflictWith(Long.parseLong(((Element)m.next()).attributeValue("id"))); 388 } 389 } 390 } 391 } 392 for (Iterator<?> j = offeringEl.elementIterator("reservation"); j.hasNext(); ) { 393 Element reservationEl = (Element)j.next(); 394 Reservation r = null; 395 if ("individual".equals(reservationEl.attributeValue("type"))) { 396 Set<Long> studentIds = new HashSet<Long>(); 397 for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) { 398 Element studentEl = (Element)k.next(); 399 studentIds.add(Long.parseLong(studentEl.attributeValue("id"))); 400 } 401 r = new IndividualReservation(Long.valueOf(reservationEl.attributeValue("id")), offering, studentIds); 402 } else if ("group".equals(reservationEl.attributeValue("type"))) { 403 Set<Long> studentIds = new HashSet<Long>(); 404 for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) { 405 Element studentEl = (Element)k.next(); 406 studentIds.add(Long.parseLong(studentEl.attributeValue("id"))); 407 } 408 r = new GroupReservation(Long.valueOf(reservationEl.attributeValue("id")), 409 Double.parseDouble(reservationEl.attributeValue("limit", "-1")), 410 offering, studentIds); 411 } else if ("curriculum".equals(reservationEl.attributeValue("type"))) { 412 List<String> classifications = new ArrayList<String>(); 413 for (Iterator<?> k = reservationEl.elementIterator("classification"); k.hasNext(); ) { 414 Element clasfEl = (Element)k.next(); 415 classifications.add(clasfEl.attributeValue("code")); 416 } 417 List<String> majors = new ArrayList<String>(); 418 for (Iterator<?> k = reservationEl.elementIterator("major"); k.hasNext(); ) { 419 Element majorEl = (Element)k.next(); 420 majors.add(majorEl.attributeValue("code")); 421 } 422 r = new CurriculumReservation(Long.valueOf(reservationEl.attributeValue("id")), 423 Double.parseDouble(reservationEl.attributeValue("limit", "-1")), 424 offering, 425 reservationEl.attributeValue("area"), 426 classifications, majors); 427 } else if ("course".equals(reservationEl.attributeValue("type"))) { 428 long courseId = Long.parseLong(reservationEl.attributeValue("course")); 429 for (Course course: offering.getCourses()) { 430 if (course.getId() == courseId) 431 r = new CourseReservation(Long.valueOf(reservationEl.attributeValue("id")), course); 432 } 433 } else if ("dummy".equals(reservationEl.attributeValue("type"))) { 434 r = new DummyReservation(offering); 435 } else if ("override".equals(reservationEl.attributeValue("type"))) { 436 Set<Long> studentIds = new HashSet<Long>(); 437 for (Iterator<?> k = reservationEl.elementIterator("student"); k.hasNext(); ) { 438 Element studentEl = (Element)k.next(); 439 studentIds.add(Long.parseLong(studentEl.attributeValue("id"))); 440 } 441 r = new ReservationOverride(Long.valueOf(reservationEl.attributeValue("id")), offering, studentIds); 442 ((ReservationOverride)r).setMustBeUsed("true".equals(reservationEl.attributeValue("mustBeUsed", "false"))); 443 ((ReservationOverride)r).setAllowOverlap("true".equals(reservationEl.attributeValue("allowOverlap", "false"))); 444 ((ReservationOverride)r).setCanAssignOverLimit("true".equals(reservationEl.attributeValue("canAssignOverLimit", "false"))); 445 } 446 if (r == null) { 447 sLogger.error("Unknown reservation type "+ reservationEl.attributeValue("type")); 448 continue; 449 } 450 r.setExpired("true".equals(reservationEl.attributeValue("expired", "false"))); 451 for (Iterator<?> k = reservationEl.elementIterator("config"); k.hasNext(); ) { 452 Element configEl = (Element)k.next(); 453 r.addConfig(configTable.get(Long.parseLong(configEl.attributeValue("id")))); 454 } 455 for (Iterator<?> k = reservationEl.elementIterator("section"); k.hasNext(); ) { 456 Element sectionEl = (Element)k.next(); 457 r.addSection(sectionTable.get(Long.parseLong(sectionEl.attributeValue("id")))); 458 } 459 } 460 } 461 } else { 462 for (Offering offering : getModel().getOfferings()) { 463 offeringTable.put(new Long(offering.getId()), offering); 464 for (Course course : offering.getCourses()) { 465 courseTable.put(new Long(course.getId()), course); 466 } 467 } 468 } 469 470 if (iLoadStudents && root.element("students") != null) { 471 List<Enrollment> bestEnrollments = new ArrayList<Enrollment>(); 472 List<Enrollment> currentEnrollments = new ArrayList<Enrollment>(); 473 for (Iterator<?> i = root.element("students").elementIterator("student"); i.hasNext();) { 474 Element studentEl = (Element) i.next(); 475 Student student = new Student(Long.parseLong(studentEl.attributeValue("id")), "true".equals(studentEl.attributeValue("dummy"))); 476 student.setExternalId(studentEl.attributeValue("externalId")); 477 student.setName(studentEl.attributeValue("name")); 478 student.setStatus(studentEl.attributeValue("status")); 479 for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) { 480 Element requestEl = (Element) j.next(); 481 if ("classification".equals(requestEl.getName())) { 482 student.getAcademicAreaClasiffications() 483 .add( 484 new AcademicAreaCode(requestEl.attributeValue("area"), requestEl 485 .attributeValue("code"))); 486 } else if ("major".equals(requestEl.getName())) { 487 student.getMajors() 488 .add( 489 new AcademicAreaCode(requestEl.attributeValue("area"), requestEl 490 .attributeValue("code"))); 491 } else if ("minor".equals(requestEl.getName())) { 492 student.getMinors() 493 .add( 494 new AcademicAreaCode(requestEl.attributeValue("area"), requestEl 495 .attributeValue("code"))); 496 } 497 } 498 if (iStudentFilter != null && !iStudentFilter.accept(student)) 499 continue; 500 for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) { 501 Element requestEl = (Element) j.next(); 502 if ("freeTime".equals(requestEl.getName())) { 503 TimeLocation time = new TimeLocation(Integer.parseInt(requestEl.attributeValue("days"), 2), 504 Integer.parseInt(requestEl.attributeValue("start")), Integer.parseInt(requestEl 505 .attributeValue("length")), 0, 0, 506 requestEl.attributeValue("datePattern") == null ? null : Long.valueOf(requestEl 507 .attributeValue("datePattern")), "", createBitSet(requestEl 508 .attributeValue("dates")), 0); 509 FreeTimeRequest request = new FreeTimeRequest(Long.parseLong(requestEl.attributeValue("id")), 510 Integer.parseInt(requestEl.attributeValue("priority")), "true".equals(requestEl 511 .attributeValue("alternative")), student, time); 512 if (requestEl.attributeValue("weight") != null) 513 request.setWeight(Double.parseDouble(requestEl.attributeValue("weight"))); 514 if (iLoadBest && requestEl.element("best") != null) 515 bestEnrollments.add(request.createEnrollment()); 516 if (iLoadInitial && requestEl.element("initial") != null) 517 request.setInitialAssignment(request.createEnrollment()); 518 if (iLoadCurrent && requestEl.element("current") != null) 519 currentEnrollments.add(request.createEnrollment()); 520 } else if ("course".equals(requestEl.getName())) { 521 List<Course> courses = new ArrayList<Course>(); 522 courses.add(courseTable.get(Long.valueOf(requestEl.attributeValue("course")))); 523 for (Iterator<?> k = requestEl.elementIterator("alternative"); k.hasNext();) 524 courses.add(courseTable.get(Long.valueOf(((Element) k.next()).attributeValue("course")))); 525 Long timeStamp = null; 526 if (requestEl.attributeValue("timeStamp") != null) 527 timeStamp = Long.valueOf(requestEl.attributeValue("timeStamp")); 528 CourseRequest courseRequest = new CourseRequest( 529 Long.parseLong(requestEl.attributeValue("id")), 530 Integer.parseInt(requestEl.attributeValue("priority")), 531 "true".equals(requestEl.attributeValue("alternative")), 532 student, courses, 533 "true".equals(requestEl.attributeValue("waitlist", "false")), timeStamp); 534 if (requestEl.attributeValue("weight") != null) 535 courseRequest.setWeight(Double.parseDouble(requestEl.attributeValue("weight"))); 536 for (Iterator<?> k = requestEl.elementIterator("waitlisted"); k.hasNext();) { 537 Element choiceEl = (Element) k.next(); 538 courseRequest.getWaitlistedChoices().add( 539 new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), 540 choiceEl.getText())); 541 } 542 for (Iterator<?> k = requestEl.elementIterator("selected"); k.hasNext();) { 543 Element choiceEl = (Element) k.next(); 544 courseRequest.getSelectedChoices().add( 545 new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), 546 choiceEl.getText())); 547 } 548 Element initialEl = requestEl.element("initial"); 549 if (iLoadInitial && initialEl != null) { 550 HashSet<Section> sections = new HashSet<Section>(); 551 for (Iterator<?> k = initialEl.elementIterator("section"); k.hasNext();) { 552 Element sectionEl = (Element) k.next(); 553 Section section = courseRequest.getSection(Long.parseLong(sectionEl 554 .attributeValue("id"))); 555 sections.add(section); 556 } 557 Reservation reservation = null; 558 if (initialEl.attributeValue("reservation", null) != null) { 559 long reservationId = Long.valueOf(initialEl.attributeValue("reservation")); 560 for (Course course: courseRequest.getCourses()) 561 for (Reservation r: course.getOffering().getReservations()) 562 if (r.getId() == reservationId) { reservation = r; break; } 563 } 564 if (!sections.isEmpty()) 565 courseRequest.setInitialAssignment(courseRequest.createEnrollment(sections, reservation)); 566 } 567 Element currentEl = requestEl.element("current"); 568 if (iLoadCurrent && currentEl != null) { 569 HashSet<Section> sections = new HashSet<Section>(); 570 for (Iterator<?> k = currentEl.elementIterator("section"); k.hasNext();) { 571 Element sectionEl = (Element) k.next(); 572 Section section = courseRequest.getSection(Long.parseLong(sectionEl 573 .attributeValue("id"))); 574 sections.add(section); 575 } 576 Reservation reservation = null; 577 if (currentEl.attributeValue("reservation", null) != null) { 578 long reservationId = Long.valueOf(currentEl.attributeValue("reservation")); 579 for (Course course: courseRequest.getCourses()) 580 for (Reservation r: course.getOffering().getReservations()) 581 if (r.getId() == reservationId) { reservation = r; break; } 582 } 583 if (!sections.isEmpty()) 584 currentEnrollments.add(courseRequest.createEnrollment(sections, reservation)); 585 } 586 Element bestEl = requestEl.element("best"); 587 if (iLoadBest && bestEl != null) { 588 HashSet<Section> sections = new HashSet<Section>(); 589 for (Iterator<?> k = bestEl.elementIterator("section"); k.hasNext();) { 590 Element sectionEl = (Element) k.next(); 591 Section section = courseRequest.getSection(Long.parseLong(sectionEl 592 .attributeValue("id"))); 593 sections.add(section); 594 } 595 Reservation reservation = null; 596 if (bestEl.attributeValue("reservation", null) != null) { 597 long reservationId = Long.valueOf(bestEl.attributeValue("reservation")); 598 for (Course course: courseRequest.getCourses()) 599 for (Reservation r: course.getOffering().getReservations()) 600 if (r.getId() == reservationId) { reservation = r; break; } 601 } 602 if (!sections.isEmpty()) 603 bestEnrollments.add(courseRequest.createEnrollment(sections, reservation)); 604 } 605 } 606 } 607 getModel().addStudent(student); 608 } 609 610 if (!bestEnrollments.isEmpty()) { 611 // Enrollments with a reservation must go first 612 for (Enrollment enrollment : bestEnrollments) { 613 if (enrollment.getReservation() == null) continue; 614 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 615 if (conflicts.isEmpty()) 616 getAssignment().assign(0, enrollment); 617 else 618 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 619 } 620 for (Enrollment enrollment : bestEnrollments) { 621 if (enrollment.getReservation() != null) continue; 622 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 623 if (conflicts.isEmpty()) 624 getAssignment().assign(0, enrollment); 625 else 626 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 627 } 628 getModel().saveBest(getAssignment()); 629 } 630 631 if (!currentEnrollments.isEmpty()) { 632 for (Request request : getModel().variables()) 633 getAssignment().unassign(0, request); 634 // Enrollments with a reservation must go first 635 for (Enrollment enrollment : currentEnrollments) { 636 if (enrollment.getReservation() == null) continue; 637 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 638 if (conflicts.isEmpty()) 639 getAssignment().assign(0, enrollment); 640 else 641 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 642 } 643 for (Enrollment enrollment : currentEnrollments) { 644 if (enrollment.getReservation() != null) continue; 645 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 646 if (conflicts.isEmpty()) 647 getAssignment().assign(0, enrollment); 648 else 649 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 650 } 651 } 652 } 653 654 if (iLoadOfferings && root.element("constraints") != null) { 655 for (Iterator<?> i = root.element("constraints").elementIterator("linked-sections"); i.hasNext();) { 656 Element linkedEl = (Element) i.next(); 657 List<Section> sections = new ArrayList<Section>(); 658 for (Iterator<?> j = linkedEl.elementIterator("section"); j.hasNext();) { 659 Element sectionEl = (Element) j.next(); 660 Offering offering = offeringTable.get(Long.valueOf(sectionEl.attributeValue("offering"))); 661 sections.add(offering.getSection(Long.valueOf(sectionEl.attributeValue("id")))); 662 } 663 getModel().addLinkedSections(sections); 664 } 665 } 666 667 sLogger.debug("Model successfully loaded."); 668 } 669 670}