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 } 443 if (r == null) { 444 sLogger.error("Unknown reservation type "+ reservationEl.attributeValue("type")); 445 continue; 446 } 447 r.setExpired("true".equals(reservationEl.attributeValue("expired", "false"))); 448 for (Iterator<?> k = reservationEl.elementIterator("config"); k.hasNext(); ) { 449 Element configEl = (Element)k.next(); 450 r.addConfig(configTable.get(Long.parseLong(configEl.attributeValue("id")))); 451 } 452 for (Iterator<?> k = reservationEl.elementIterator("section"); k.hasNext(); ) { 453 Element sectionEl = (Element)k.next(); 454 r.addSection(sectionTable.get(Long.parseLong(sectionEl.attributeValue("id")))); 455 } 456 r.setPriority(Integer.parseInt(reservationEl.attributeValue("priority", String.valueOf(r.getPriority())))); 457 r.setMustBeUsed("true".equals(reservationEl.attributeValue("mustBeUsed", r.mustBeUsed() ? "true" : "false"))); 458 r.setAllowOverlap("true".equals(reservationEl.attributeValue("allowOverlap", r.isAllowOverlap() ? "true" : "false"))); 459 r.setCanAssignOverLimit("true".equals(reservationEl.attributeValue("canAssignOverLimit", r.canAssignOverLimit() ? "true" : "false"))); 460 } 461 } 462 } else { 463 for (Offering offering : getModel().getOfferings()) { 464 offeringTable.put(new Long(offering.getId()), offering); 465 for (Course course : offering.getCourses()) { 466 courseTable.put(new Long(course.getId()), course); 467 } 468 } 469 } 470 471 if (iLoadStudents && root.element("students") != null) { 472 List<Enrollment> bestEnrollments = new ArrayList<Enrollment>(); 473 List<Enrollment> currentEnrollments = new ArrayList<Enrollment>(); 474 for (Iterator<?> i = root.element("students").elementIterator("student"); i.hasNext();) { 475 Element studentEl = (Element) i.next(); 476 Student student = new Student(Long.parseLong(studentEl.attributeValue("id")), "true".equals(studentEl.attributeValue("dummy"))); 477 student.setExternalId(studentEl.attributeValue("externalId")); 478 student.setName(studentEl.attributeValue("name")); 479 student.setStatus(studentEl.attributeValue("status")); 480 for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) { 481 Element requestEl = (Element) j.next(); 482 if ("classification".equals(requestEl.getName())) { 483 student.getAcademicAreaClasiffications() 484 .add( 485 new AcademicAreaCode(requestEl.attributeValue("area"), requestEl 486 .attributeValue("code"))); 487 } else if ("major".equals(requestEl.getName())) { 488 student.getMajors() 489 .add( 490 new AcademicAreaCode(requestEl.attributeValue("area"), requestEl 491 .attributeValue("code"))); 492 } else if ("minor".equals(requestEl.getName())) { 493 student.getMinors() 494 .add( 495 new AcademicAreaCode(requestEl.attributeValue("area"), requestEl 496 .attributeValue("code"))); 497 } 498 } 499 if (iStudentFilter != null && !iStudentFilter.accept(student)) 500 continue; 501 for (Iterator<?> j = studentEl.elementIterator(); j.hasNext();) { 502 Element requestEl = (Element) j.next(); 503 if ("freeTime".equals(requestEl.getName())) { 504 TimeLocation time = new TimeLocation(Integer.parseInt(requestEl.attributeValue("days"), 2), 505 Integer.parseInt(requestEl.attributeValue("start")), Integer.parseInt(requestEl 506 .attributeValue("length")), 0, 0, 507 requestEl.attributeValue("datePattern") == null ? null : Long.valueOf(requestEl 508 .attributeValue("datePattern")), "", createBitSet(requestEl 509 .attributeValue("dates")), 0); 510 FreeTimeRequest request = new FreeTimeRequest(Long.parseLong(requestEl.attributeValue("id")), 511 Integer.parseInt(requestEl.attributeValue("priority")), "true".equals(requestEl 512 .attributeValue("alternative")), student, time); 513 if (requestEl.attributeValue("weight") != null) 514 request.setWeight(Double.parseDouble(requestEl.attributeValue("weight"))); 515 if (iLoadBest && requestEl.element("best") != null) 516 bestEnrollments.add(request.createEnrollment()); 517 if (iLoadInitial && requestEl.element("initial") != null) 518 request.setInitialAssignment(request.createEnrollment()); 519 if (iLoadCurrent && requestEl.element("current") != null) 520 currentEnrollments.add(request.createEnrollment()); 521 } else if ("course".equals(requestEl.getName())) { 522 List<Course> courses = new ArrayList<Course>(); 523 courses.add(courseTable.get(Long.valueOf(requestEl.attributeValue("course")))); 524 for (Iterator<?> k = requestEl.elementIterator("alternative"); k.hasNext();) 525 courses.add(courseTable.get(Long.valueOf(((Element) k.next()).attributeValue("course")))); 526 Long timeStamp = null; 527 if (requestEl.attributeValue("timeStamp") != null) 528 timeStamp = Long.valueOf(requestEl.attributeValue("timeStamp")); 529 CourseRequest courseRequest = new CourseRequest( 530 Long.parseLong(requestEl.attributeValue("id")), 531 Integer.parseInt(requestEl.attributeValue("priority")), 532 "true".equals(requestEl.attributeValue("alternative")), 533 student, courses, 534 "true".equals(requestEl.attributeValue("waitlist", "false")), timeStamp); 535 if (requestEl.attributeValue("weight") != null) 536 courseRequest.setWeight(Double.parseDouble(requestEl.attributeValue("weight"))); 537 for (Iterator<?> k = requestEl.elementIterator("waitlisted"); k.hasNext();) { 538 Element choiceEl = (Element) k.next(); 539 courseRequest.getWaitlistedChoices().add( 540 new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), 541 choiceEl.getText())); 542 } 543 for (Iterator<?> k = requestEl.elementIterator("selected"); k.hasNext();) { 544 Element choiceEl = (Element) k.next(); 545 courseRequest.getSelectedChoices().add( 546 new Choice(offeringTable.get(Long.valueOf(choiceEl.attributeValue("offering"))), 547 choiceEl.getText())); 548 } 549 Element initialEl = requestEl.element("initial"); 550 if (iLoadInitial && initialEl != null) { 551 HashSet<Section> sections = new HashSet<Section>(); 552 for (Iterator<?> k = initialEl.elementIterator("section"); k.hasNext();) { 553 Element sectionEl = (Element) k.next(); 554 Section section = courseRequest.getSection(Long.parseLong(sectionEl 555 .attributeValue("id"))); 556 sections.add(section); 557 } 558 Reservation reservation = null; 559 if (initialEl.attributeValue("reservation", null) != null) { 560 long reservationId = Long.valueOf(initialEl.attributeValue("reservation")); 561 for (Course course: courseRequest.getCourses()) 562 for (Reservation r: course.getOffering().getReservations()) 563 if (r.getId() == reservationId) { reservation = r; break; } 564 } 565 if (!sections.isEmpty()) 566 courseRequest.setInitialAssignment(courseRequest.createEnrollment(sections, reservation)); 567 } 568 Element currentEl = requestEl.element("current"); 569 if (iLoadCurrent && currentEl != null) { 570 HashSet<Section> sections = new HashSet<Section>(); 571 for (Iterator<?> k = currentEl.elementIterator("section"); k.hasNext();) { 572 Element sectionEl = (Element) k.next(); 573 Section section = courseRequest.getSection(Long.parseLong(sectionEl 574 .attributeValue("id"))); 575 sections.add(section); 576 } 577 Reservation reservation = null; 578 if (currentEl.attributeValue("reservation", null) != null) { 579 long reservationId = Long.valueOf(currentEl.attributeValue("reservation")); 580 for (Course course: courseRequest.getCourses()) 581 for (Reservation r: course.getOffering().getReservations()) 582 if (r.getId() == reservationId) { reservation = r; break; } 583 } 584 if (!sections.isEmpty()) 585 currentEnrollments.add(courseRequest.createEnrollment(sections, reservation)); 586 } 587 Element bestEl = requestEl.element("best"); 588 if (iLoadBest && bestEl != null) { 589 HashSet<Section> sections = new HashSet<Section>(); 590 for (Iterator<?> k = bestEl.elementIterator("section"); k.hasNext();) { 591 Element sectionEl = (Element) k.next(); 592 Section section = courseRequest.getSection(Long.parseLong(sectionEl 593 .attributeValue("id"))); 594 sections.add(section); 595 } 596 Reservation reservation = null; 597 if (bestEl.attributeValue("reservation", null) != null) { 598 long reservationId = Long.valueOf(bestEl.attributeValue("reservation")); 599 for (Course course: courseRequest.getCourses()) 600 for (Reservation r: course.getOffering().getReservations()) 601 if (r.getId() == reservationId) { reservation = r; break; } 602 } 603 if (!sections.isEmpty()) 604 bestEnrollments.add(courseRequest.createEnrollment(sections, reservation)); 605 } 606 } 607 } 608 getModel().addStudent(student); 609 } 610 611 if (!bestEnrollments.isEmpty()) { 612 // Enrollments with a reservation must go first 613 for (Enrollment enrollment : bestEnrollments) { 614 if (enrollment.getReservation() == null) continue; 615 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 616 if (conflicts.isEmpty()) 617 getAssignment().assign(0, enrollment); 618 else 619 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 620 } 621 for (Enrollment enrollment : bestEnrollments) { 622 if (enrollment.getReservation() != null) continue; 623 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 624 if (conflicts.isEmpty()) 625 getAssignment().assign(0, enrollment); 626 else 627 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 628 } 629 getModel().saveBest(getAssignment()); 630 } 631 632 if (!currentEnrollments.isEmpty()) { 633 for (Request request : getModel().variables()) 634 getAssignment().unassign(0, request); 635 // Enrollments with a reservation must go first 636 for (Enrollment enrollment : currentEnrollments) { 637 if (enrollment.getReservation() == null) continue; 638 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 639 if (conflicts.isEmpty()) 640 getAssignment().assign(0, enrollment); 641 else 642 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 643 } 644 for (Enrollment enrollment : currentEnrollments) { 645 if (enrollment.getReservation() != null) continue; 646 Map<Constraint<Request, Enrollment>, Set<Enrollment>> conflicts = getModel().conflictConstraints(getAssignment(), enrollment); 647 if (conflicts.isEmpty()) 648 getAssignment().assign(0, enrollment); 649 else 650 sLogger.warn("Enrollment " + enrollment + " conflicts with " + conflicts); 651 } 652 } 653 } 654 655 if (iLoadOfferings && root.element("constraints") != null) { 656 for (Iterator<?> i = root.element("constraints").elementIterator("linked-sections"); i.hasNext();) { 657 Element linkedEl = (Element) i.next(); 658 List<Section> sections = new ArrayList<Section>(); 659 for (Iterator<?> j = linkedEl.elementIterator("section"); j.hasNext();) { 660 Element sectionEl = (Element) j.next(); 661 Offering offering = offeringTable.get(Long.valueOf(sectionEl.attributeValue("offering"))); 662 sections.add(offering.getSection(Long.valueOf(sectionEl.attributeValue("id")))); 663 } 664 getModel().addLinkedSections(sections); 665 } 666 } 667 668 sLogger.debug("Model successfully loaded."); 669 } 670 671}