net.sf.cpsolver.studentsct.StudentSectioningXMLSaver.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.cpsolver.studentsct.StudentSectioningXMLSaver.java

Source

package net.sf.cpsolver.studentsct;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.BitSet;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import net.sf.cpsolver.coursett.IdConvertor;
import net.sf.cpsolver.coursett.model.RoomLocation;
import net.sf.cpsolver.coursett.model.TimeLocation;
import net.sf.cpsolver.ifs.solver.Solver;
import net.sf.cpsolver.ifs.util.Progress;
import net.sf.cpsolver.studentsct.model.AcademicAreaCode;
import net.sf.cpsolver.studentsct.model.Choice;
import net.sf.cpsolver.studentsct.model.Config;
import net.sf.cpsolver.studentsct.model.Course;
import net.sf.cpsolver.studentsct.model.CourseRequest;
import net.sf.cpsolver.studentsct.model.Enrollment;
import net.sf.cpsolver.studentsct.model.FreeTimeRequest;
import net.sf.cpsolver.studentsct.model.Offering;
import net.sf.cpsolver.studentsct.model.Request;
import net.sf.cpsolver.studentsct.model.Section;
import net.sf.cpsolver.studentsct.model.Student;
import net.sf.cpsolver.studentsct.model.Subpart;
import net.sf.cpsolver.studentsct.reservation.CourseReservation;
import net.sf.cpsolver.studentsct.reservation.CurriculumReservation;
import net.sf.cpsolver.studentsct.reservation.GroupReservation;
import net.sf.cpsolver.studentsct.reservation.IndividualReservation;
import net.sf.cpsolver.studentsct.reservation.Reservation;

/**
 * Save student sectioning solution into an XML file.
 * 
 * <br>
 * <br>
 * Parameters:
 * <table border='1'>
 * <tr>
 * <th>Parameter</th>
 * <th>Type</th>
 * <th>Comment</th>
 * </tr>
 * <tr>
 * <td>General.Output</td>
 * <td>{@link String}</td>
 * <td>Folder with the output solution in XML format (solution.xml)</td>
 * </tr>
 * <tr>
 * <td>Xml.ConvertIds</td>
 * <td>{@link Boolean}</td>
 * <td>If true, ids are converted (to be able to make input data public)</td>
 * </tr>
 * <tr>
 * <td>Xml.ShowNames</td>
 * <td>{@link Boolean}</td>
 * <td>If false, names are not exported (to be able to make input data public)</td>
 * </tr>
 * <tr>
 * <td>Xml.SaveBest</td>
 * <td>{@link Boolean}</td>
 * <td>If true, best solution is saved.</td>
 * </tr>
 * <tr>
 * <td>Xml.SaveInitial</td>
 * <td>{@link Boolean}</td>
 * <td>If true, initial solution is saved.</td>
 * </tr>
 * <tr>
 * <td>Xml.SaveCurrent</td>
 * <td>{@link Boolean}</td>
 * <td>If true, current solution is saved.</td>
 * </tr>
 * <tr>
 * <td>Xml.SaveOnlineSectioningInfo</td>
 * <td>{@link Boolean}</td>
 * <td>If true, save online sectioning info (i.e., expected and held space of
 * each section)</td>
 * </tr>
 * <tr>
 * <td>Xml.SaveStudentInfo</td>
 * <td>{@link Boolean}</td>
 * <td>If true, save student information (i.e., academic area classification,
 * major, minor)</td>
 * </tr>
 * </table>
 * <br>
 * <br>
 * Usage:<br>
 * <code>
 * new StudentSectioningXMLSaver(solver).save(new File("solution.xml"));<br> 
 * </code>
 * 
 * @version StudentSct 1.2 (Student Sectioning)<br>
 *          Copyright (C) 2007 - 2010 Tomas Muller<br>
 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
 * <br>
 *          This library is free software; you can redistribute it and/or modify
 *          it under the terms of the GNU Lesser General Public License as
 *          published by the Free Software Foundation; either version 3 of the
 *          License, or (at your option) any later version. <br>
 * <br>
 *          This library is distributed in the hope that it will be useful, but
 *          WITHOUT ANY WARRANTY; without even the implied warranty of
 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *          Lesser General Public License for more details. <br>
 * <br>
 *          You should have received a copy of the GNU Lesser General Public
 *          License along with this library; if not see
 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
 */

public class StudentSectioningXMLSaver extends StudentSectioningSaver {
    private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger
            .getLogger(StudentSectioningXMLSaver.class);
    private static DecimalFormat[] sDF = { new DecimalFormat(""), new DecimalFormat("0"), new DecimalFormat("00"),
            new DecimalFormat("000"), new DecimalFormat("0000"), new DecimalFormat("00000"),
            new DecimalFormat("000000"), new DecimalFormat("0000000") };
    private static DecimalFormat sStudentWeightFormat = new DecimalFormat("0.0000");
    private File iOutputFolder = null;

    private boolean iSaveBest = false;
    private boolean iSaveInitial = false;
    private boolean iSaveCurrent = false;
    private boolean iSaveOnlineSectioningInfo = false;
    private boolean iSaveStudentInfo = true;

    private boolean iConvertIds = false;
    private boolean iShowNames = false;

    static {
        sStudentWeightFormat.setRoundingMode(RoundingMode.DOWN);
    }

    /**
     * Constructor
     * 
     * @param solver
     *            student sectioning solver
     */
    public StudentSectioningXMLSaver(Solver<Request, Enrollment> solver) {
        super(solver);
        iOutputFolder = new File(
                getModel().getProperties().getProperty("General.Output", "." + File.separator + "output"));
        iSaveBest = getModel().getProperties().getPropertyBoolean("Xml.SaveBest", true);
        iSaveInitial = getModel().getProperties().getPropertyBoolean("Xml.SaveInitial", true);
        iSaveCurrent = getModel().getProperties().getPropertyBoolean("Xml.SaveCurrent", false);
        iSaveOnlineSectioningInfo = getModel().getProperties().getPropertyBoolean("Xml.SaveOnlineSectioningInfo",
                true);
        iSaveStudentInfo = getModel().getProperties().getPropertyBoolean("Xml.SaveStudentInfo", true);
        iShowNames = getModel().getProperties().getPropertyBoolean("Xml.ShowNames", true);
        iConvertIds = getModel().getProperties().getPropertyBoolean("Xml.ConvertIds", false);
    }

    /** Convert bitset to a bit string */
    private static String bitset2string(BitSet b) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < b.length(); i++)
            sb.append(b.get(i) ? "1" : "0");
        return sb.toString();
    }

    /** Generate id for given object with the given id */
    private String getId(String type, String id) {
        if (!iConvertIds)
            return id.toString();
        return IdConvertor.getInstance().convert(type, id);
    }

    /** Generate id for given object with the given id */
    private String getId(String type, Number id) {
        return getId(type, id.toString());
    }

    /** Generate id for given object with the given id */
    private String getId(String type, long id) {
        return getId(type, String.valueOf(id));
    }

    /** Save an XML file */
    @Override
    public void save() throws Exception {
        save(null);
    }

    /**
     * Save an XML file
     * 
     * @param outFile
     *            output file
     */
    public void save(File outFile) throws Exception {
        if (outFile == null)
            outFile = new File(iOutputFolder, "solution.xml");
        outFile.getParentFile().mkdirs();
        sLogger.debug("Writting XML data to:" + outFile);

        Document document = DocumentHelper.createDocument();
        document.addComment("Student Sectioning");

        if ((iSaveCurrent || iSaveBest)) { // &&
                                           // !getModel().assignedVariables().isEmpty()
            StringBuffer comments = new StringBuffer("Solution Info:\n");
            Map<String, String> solutionInfo = (getSolution() == null ? getModel().getExtendedInfo()
                    : getSolution().getExtendedInfo());
            for (String key : new TreeSet<String>(solutionInfo.keySet())) {
                String value = solutionInfo.get(key);
                comments.append("    " + key + ": " + value + "\n");
            }
            document.addComment(comments.toString());
        }

        Element root = document.addElement("sectioning");
        root.addAttribute("version", "1.0");
        root.addAttribute("initiative", getModel().getProperties().getProperty("Data.Initiative"));
        root.addAttribute("term", getModel().getProperties().getProperty("Data.Term"));
        root.addAttribute("year", getModel().getProperties().getProperty("Data.Year"));
        root.addAttribute("created", String.valueOf(new Date()));

        Element offeringsEl = root.addElement("offerings");
        for (Offering offering : getModel().getOfferings()) {
            Element offeringEl = offeringsEl.addElement("offering");
            offeringEl.addAttribute("id", getId("offering", offering.getId()));
            if (iShowNames)
                offeringEl.addAttribute("name", offering.getName());
            for (Course course : offering.getCourses()) {
                Element courseEl = offeringEl.addElement("course");
                courseEl.addAttribute("id", getId("course", course.getId()));
                if (iShowNames)
                    courseEl.addAttribute("subjectArea", course.getSubjectArea());
                if (iShowNames)
                    courseEl.addAttribute("courseNbr", course.getCourseNumber());
                if (iShowNames && course.getLimit() >= 0)
                    courseEl.addAttribute("limit", String.valueOf(course.getLimit()));
                if (iShowNames && course.getProjected() != 0)
                    courseEl.addAttribute("projected", String.valueOf(course.getProjected()));
            }
            for (Config config : offering.getConfigs()) {
                Element configEl = offeringEl.addElement("config");
                configEl.addAttribute("id", getId("config", config.getId()));
                if (config.getLimit() >= 0)
                    configEl.addAttribute("limit", String.valueOf(config.getLimit()));
                if (iShowNames)
                    configEl.addAttribute("name", config.getName());
                for (Subpart subpart : config.getSubparts()) {
                    Element subpartEl = configEl.addElement("subpart");
                    subpartEl.addAttribute("id", getId("subpart", subpart.getId()));
                    subpartEl.addAttribute("itype", subpart.getInstructionalType());
                    if (subpart.getParent() != null)
                        subpartEl.addAttribute("parent", getId("subpart", subpart.getParent().getId()));
                    if (iShowNames)
                        subpartEl.addAttribute("name", subpart.getName());
                    if (subpart.isAllowOverlap())
                        subpartEl.addAttribute("allowOverlap", "true");
                    for (Section section : subpart.getSections()) {
                        Element sectionEl = subpartEl.addElement("section");
                        sectionEl.addAttribute("id", getId("section", section.getId()));
                        sectionEl.addAttribute("limit", String.valueOf(section.getLimit()));
                        if (section.getNameByCourse() != null)
                            for (Map.Entry<Long, String> entry : section.getNameByCourse().entrySet())
                                sectionEl.addElement("cname").addAttribute("id", entry.getKey().toString())
                                        .setText(entry.getValue());
                        if (section.getParent() != null)
                            sectionEl.addAttribute("parent", getId("section", section.getParent().getId()));
                        if (iShowNames && section.getChoice().getInstructorIds() != null)
                            sectionEl.addAttribute("instructorIds", section.getChoice().getInstructorIds());
                        if (iShowNames && section.getChoice().getInstructorNames() != null)
                            sectionEl.addAttribute("instructorNames", section.getChoice().getInstructorNames());
                        if (iShowNames)
                            sectionEl.addAttribute("name", section.getName());
                        if (section.getPlacement() != null) {
                            TimeLocation tl = section.getPlacement().getTimeLocation();
                            if (tl != null) {
                                Element timeLocationEl = sectionEl.addElement("time");
                                timeLocationEl.addAttribute("days",
                                        sDF[7].format(Long.parseLong(Integer.toBinaryString(tl.getDayCode()))));
                                timeLocationEl.addAttribute("start", String.valueOf(tl.getStartSlot()));
                                timeLocationEl.addAttribute("length", String.valueOf(tl.getLength()));
                                if (tl.getBreakTime() != 0)
                                    timeLocationEl.addAttribute("breakTime", String.valueOf(tl.getBreakTime()));
                                if (iShowNames && tl.getTimePatternId() != null)
                                    timeLocationEl.addAttribute("pattern",
                                            getId("timePattern", tl.getTimePatternId()));
                                if (iShowNames && tl.getDatePatternId() != null)
                                    timeLocationEl.addAttribute("datePattern", tl.getDatePatternId().toString());
                                if (iShowNames && tl.getDatePatternName() != null
                                        && tl.getDatePatternName().length() > 0)
                                    timeLocationEl.addAttribute("datePatternName", tl.getDatePatternName());
                                timeLocationEl.addAttribute("dates", bitset2string(tl.getWeekCode()));
                                if (iShowNames)
                                    timeLocationEl.setText(tl.getLongName());
                            }
                            for (RoomLocation rl : section.getRooms()) {
                                Element roomLocationEl = sectionEl.addElement("room");
                                roomLocationEl.addAttribute("id", getId("room", rl.getId()));
                                if (iShowNames && rl.getBuildingId() != null)
                                    roomLocationEl.addAttribute("building", getId("building", rl.getBuildingId()));
                                if (iShowNames && rl.getName() != null)
                                    roomLocationEl.addAttribute("name", rl.getName());
                                roomLocationEl.addAttribute("capacity", String.valueOf(rl.getRoomSize()));
                                if (rl.getPosX() != null && rl.getPosY() != null)
                                    roomLocationEl.addAttribute("location", rl.getPosX() + "," + rl.getPosY());
                                if (rl.getIgnoreTooFar())
                                    roomLocationEl.addAttribute("ignoreTooFar", "true");
                            }
                        }
                        if (iSaveOnlineSectioningInfo) {
                            if (section.getSpaceHeld() != 0.0)
                                sectionEl.addAttribute("hold", sStudentWeightFormat.format(section.getSpaceHeld()));
                            if (section.getSpaceExpected() != 0.0)
                                sectionEl.addAttribute("expect",
                                        sStudentWeightFormat.format(section.getSpaceExpected()));
                        }
                    }
                }
            }
            if (!offering.getReservations().isEmpty()) {
                for (Reservation r : offering.getReservations()) {
                    Element reservationEl = offeringEl.addElement("reservation");
                    reservationEl.addAttribute("id", getId("reservation", r.getId()));
                    if (r instanceof GroupReservation) {
                        GroupReservation gr = (GroupReservation) r;
                        reservationEl.addAttribute("type", "group");
                        for (Long studentId : gr.getStudentIds())
                            reservationEl.addElement("student").addAttribute("id", getId("student", studentId));
                        if (gr.getLimit() >= 0.0)
                            reservationEl.addAttribute("limit", String.valueOf(gr.getLimit()));
                    } else if (r instanceof IndividualReservation) {
                        reservationEl.addAttribute("type", "individual");
                        for (Long studentId : ((IndividualReservation) r).getStudentIds())
                            reservationEl.addElement("student").addAttribute("id", getId("student", studentId));
                    } else if (r instanceof CurriculumReservation) {
                        reservationEl.addAttribute("type", "curriculum");
                        CurriculumReservation cr = (CurriculumReservation) r;
                        if (cr.getLimit() >= 0.0)
                            reservationEl.addAttribute("limit", String.valueOf(cr.getLimit()));
                        reservationEl.addAttribute("area", cr.getAcademicArea());
                        for (String clasf : cr.getClassifications())
                            reservationEl.addElement("classification").addAttribute("code", clasf);
                        for (String major : cr.getMajors())
                            reservationEl.addElement("major").addAttribute("code", major);
                    } else if (r instanceof CourseReservation) {
                        reservationEl.addAttribute("type", "course");
                        CourseReservation cr = (CourseReservation) r;
                        reservationEl.addAttribute("course", getId("course", cr.getCourse().getId()));
                    }
                    for (Config config : r.getConfigs())
                        reservationEl.addElement("config").addAttribute("id", getId("config", config.getId()));
                    for (Map.Entry<Subpart, Set<Section>> entry : r.getSections().entrySet()) {
                        for (Section section : entry.getValue()) {
                            reservationEl.addElement("section").addAttribute("id",
                                    getId("section", section.getId()));
                        }
                    }
                }
            }
        }

        Element studentsEl = root.addElement("students");
        for (Student student : getModel().getStudents()) {
            Element studentEl = studentsEl.addElement("student");
            studentEl.addAttribute("id", getId("student", student.getId()));
            if (student.isDummy())
                studentEl.addAttribute("dummy", "true");
            if (iSaveStudentInfo) {
                for (AcademicAreaCode aac : student.getAcademicAreaClasiffications()) {
                    Element aacEl = studentEl.addElement("classification");
                    if (aac.getArea() != null)
                        aacEl.addAttribute("area", aac.getArea());
                    if (aac.getCode() != null)
                        aacEl.addAttribute("code", aac.getCode());
                }
                for (AcademicAreaCode aac : student.getMajors()) {
                    Element aacEl = studentEl.addElement("major");
                    if (aac.getArea() != null)
                        aacEl.addAttribute("area", aac.getArea());
                    if (aac.getCode() != null)
                        aacEl.addAttribute("code", aac.getCode());
                }
                for (AcademicAreaCode aac : student.getMinors()) {
                    Element aacEl = studentEl.addElement("minor");
                    if (aac.getArea() != null)
                        aacEl.addAttribute("area", aac.getArea());
                    if (aac.getCode() != null)
                        aacEl.addAttribute("code", aac.getCode());
                }
            }
            for (Request request : student.getRequests()) {
                if (request instanceof FreeTimeRequest) {
                    Element requestEl = studentEl.addElement("freeTime");
                    FreeTimeRequest ft = (FreeTimeRequest) request;
                    requestEl.addAttribute("id", getId("request", request.getId()));
                    requestEl.addAttribute("priority", String.valueOf(request.getPriority()));
                    if (request.isAlternative())
                        requestEl.addAttribute("alternative", "true");
                    if (request.getWeight() != 1.0)
                        requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight()));
                    TimeLocation tl = ft.getTime();
                    if (tl != null) {
                        requestEl.addAttribute("days",
                                sDF[7].format(Long.parseLong(Integer.toBinaryString(tl.getDayCode()))));
                        requestEl.addAttribute("start", String.valueOf(tl.getStartSlot()));
                        requestEl.addAttribute("length", String.valueOf(tl.getLength()));
                        if (iShowNames && tl.getDatePatternId() != null)
                            requestEl.addAttribute("datePattern", tl.getDatePatternId().toString());
                        requestEl.addAttribute("dates", bitset2string(tl.getWeekCode()));
                        if (iShowNames)
                            requestEl.setText(tl.getLongName());
                    }
                    if (iSaveInitial && request.getInitialAssignment() != null) {
                        requestEl.addElement("initial");
                    }
                    if (iSaveCurrent && request.getAssignment() != null) {
                        requestEl.addElement("current");
                    }
                    if (iSaveBest && request.getBestAssignment() != null) {
                        requestEl.addElement("best");
                    }
                } else if (request instanceof CourseRequest) {
                    CourseRequest cr = (CourseRequest) request;
                    Element requestEl = studentEl.addElement("course");
                    requestEl.addAttribute("id", getId("request", request.getId()));
                    requestEl.addAttribute("priority", String.valueOf(request.getPriority()));
                    if (request.isAlternative())
                        requestEl.addAttribute("alternative", "true");
                    if (request.getWeight() != 1.0)
                        requestEl.addAttribute("weight", sStudentWeightFormat.format(request.getWeight()));
                    requestEl.addAttribute("waitlist", cr.isWaitlist() ? "true" : "false");
                    if (cr.getTimeStamp() != null)
                        requestEl.addAttribute("timeStamp", cr.getTimeStamp().toString());
                    boolean first = true;
                    for (Course course : cr.getCourses()) {
                        if (first)
                            requestEl.addAttribute("course", getId("course", course.getId()));
                        else
                            requestEl.addElement("alternative").addAttribute("course",
                                    getId("course", course.getId()));
                        first = false;
                    }
                    for (Choice choice : cr.getWaitlistedChoices()) {
                        Element choiceEl = requestEl.addElement("waitlisted");
                        choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId()));
                        choiceEl.setText(choice.getId());
                    }
                    for (Choice choice : cr.getSelectedChoices()) {
                        Element choiceEl = requestEl.addElement("selected");
                        choiceEl.addAttribute("offering", getId("offering", choice.getOffering().getId()));
                        choiceEl.setText(choice.getId());
                    }
                    if (iSaveInitial && request.getInitialAssignment() != null) {
                        Element assignmentEl = requestEl.addElement("initial");
                        Enrollment enrollment = request.getInitialAssignment();
                        if (enrollment.getReservation() != null)
                            assignmentEl.addAttribute("reservation",
                                    getId("reservation", enrollment.getReservation().getId()));
                        for (Section section : enrollment.getSections()) {
                            Element sectionEl = assignmentEl.addElement("section").addAttribute("id",
                                    getId("section", section.getId()));
                            if (iShowNames)
                                sectionEl.setText(section.getName() + " "
                                        + (section.getTime() == null ? " Arr Hrs"
                                                : " " + section.getTime().getLongName())
                                        + (section.getNrRooms() == 0 ? ""
                                                : " " + section.getPlacement().getRoomName(","))
                                        + (section.getChoice().getInstructorNames() == null ? ""
                                                : " " + section.getChoice().getInstructorNames()));
                        }
                    }
                    if (iSaveCurrent && request.getAssignment() != null) {
                        Element assignmentEl = requestEl.addElement("current");
                        Enrollment enrollment = request.getAssignment();
                        if (enrollment.getReservation() != null)
                            assignmentEl.addAttribute("reservation",
                                    getId("reservation", enrollment.getReservation().getId()));
                        for (Section section : enrollment.getSections()) {
                            Element sectionEl = assignmentEl.addElement("section").addAttribute("id",
                                    getId("section", section.getId()));
                            if (iShowNames)
                                sectionEl.setText(section.getName() + " "
                                        + (section.getTime() == null ? " Arr Hrs"
                                                : " " + section.getTime().getLongName())
                                        + (section.getNrRooms() == 0 ? ""
                                                : " " + section.getPlacement().getRoomName(","))
                                        + (section.getChoice().getInstructorNames() == null ? ""
                                                : " " + section.getChoice().getInstructorNames()));
                        }
                    }
                    if (iSaveBest && request.getBestAssignment() != null) {
                        Element assignmentEl = requestEl.addElement("best");
                        Enrollment enrollment = request.getBestAssignment();
                        if (enrollment.getReservation() != null)
                            assignmentEl.addAttribute("reservation",
                                    getId("reservation", enrollment.getReservation().getId()));
                        for (Section section : enrollment.getSections()) {
                            Element sectionEl = assignmentEl.addElement("section").addAttribute("id",
                                    getId("section", section.getId()));
                            if (iShowNames)
                                sectionEl.setText(section.getName() + " "
                                        + (section.getTime() == null ? " Arr Hrs"
                                                : " " + section.getTime().getLongName())
                                        + (section.getNrRooms() == 0 ? ""
                                                : " " + section.getPlacement().getRoomName(","))
                                        + (section.getChoice().getInstructorNames() == null ? ""
                                                : " " + section.getChoice().getInstructorNames()));
                        }
                    }
                }
            }
        }

        if (iShowNames) {
            Progress.getInstance(getModel()).save(root);
        }

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(outFile);
            (new XMLWriter(fos, OutputFormat.createPrettyPrint())).write(document);
            fos.flush();
            fos.close();
            fos = null;
        } finally {
            try {
                if (fos != null)
                    fos.close();
            } catch (IOException e) {
            }
        }

        if (iConvertIds)
            IdConvertor.getInstance().save();
    }

}