/** * Copyright 2010 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.planner.examples.curriculumcourse.persistence; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.drools.planner.examples.common.persistence.AbstractTxtSolutionImporter; import org.drools.planner.examples.curriculumcourse.domain.Course; import org.drools.planner.examples.curriculumcourse.domain.Curriculum; import org.drools.planner.examples.curriculumcourse.domain.CurriculumCourseSchedule; import org.drools.planner.examples.curriculumcourse.domain.Day; import org.drools.planner.examples.curriculumcourse.domain.Period; import org.drools.planner.examples.curriculumcourse.domain.Room; import org.drools.planner.examples.curriculumcourse.domain.Teacher; import org.drools.planner.examples.curriculumcourse.domain.Timeslot; import org.drools.planner.examples.curriculumcourse.domain.UnavailablePeriodConstraint; import org.drools.planner.core.solution.Solution; /** * @author Geoffrey De Smet */ public class CurriculumCourseSolutionImporter extends AbstractTxtSolutionImporter { private static final String INPUT_FILE_SUFFIX = ".ctt"; private static final String SPLIT_REGEX = "[\\ \\t]+"; public static void main(String[] args) { new CurriculumCourseSolutionImporter().convertAll(); } public CurriculumCourseSolutionImporter() { super(new CurriculumCourseDaoImpl()); } @Override protected String getInputFileSuffix() { return INPUT_FILE_SUFFIX; } public TxtInputBuilder createTxtInputBuilder() { return new CurriculumCourseInputBuilder(); } public class CurriculumCourseInputBuilder extends TxtInputBuilder { public Solution readSolution() throws IOException { CurriculumCourseSchedule schedule = new CurriculumCourseSchedule(); schedule.setId(0L); // Name: ToyExample schedule.setName(readParam("Name:")); // Courses: 4 int courseListSize = Integer.parseInt(readParam("Courses:")); // Rooms: 2 int roomListSize = Integer.parseInt(readParam("Rooms:")); // Days: 5 int dayListSize = Integer.parseInt(readParam("Days:")); // Periods_per_day: 4 int timeslotListSize = Integer.parseInt(readParam("Periods_per_day:")); // Curricula: 2 int curriculumListSize = Integer.parseInt(readParam("Curricula:")); // Constraints: 8 int unavailablePeriodConstraintListSize = Integer.parseInt(readParam("Constraints:")); Map<String, Course> courseMap = readCourseListAndTeacherList( schedule, courseListSize); readRoomList( schedule, roomListSize); Map<List<Integer>, Period> periodMap = createPeriodListAndDayListAndTimeslotList( schedule, dayListSize, timeslotListSize); readCurriculumList( schedule, courseMap, curriculumListSize); readUnavailablePeriodConstraintList( schedule, courseMap, periodMap, unavailablePeriodConstraintListSize); readHeader("END."); logger.info("CurriculumCourseSchedule with {} teachers, {} curricula, {} courses, {} periods, {} rooms" + " and {} unavailable period constraints.", new Object[]{schedule.getTeacherList().size(), schedule.getCurriculumList().size(), schedule.getCourseList().size(), schedule.getPeriodList().size(), schedule.getRoomList().size(), schedule.getUnavailablePeriodConstraintList().size()}); // Note: lectureList stays null, that's work for the StartingSolutionInitializer return schedule; } private Map<String, Course> readCourseListAndTeacherList( CurriculumCourseSchedule schedule, int courseListSize) throws IOException { Map<String, Course> courseMap = new HashMap<String, Course>(courseListSize); Map<String, Teacher> teacherMap = new HashMap<String, Teacher>(); List<Course> courseList = new ArrayList<Course>(courseListSize); readHeader("COURSES:"); for (int i = 0; i < courseListSize; i++) { Course course = new Course(); course.setId((long) i); // Courses: <CourseID> <Teacher> <# Lectures> <MinWorkingDays> <# Students> String line = bufferedReader.readLine(); String[] lineTokens = line.split(SPLIT_REGEX); if (lineTokens.length != 5) { throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 4 tokens."); } course.setCode(lineTokens[0]); course.setTeacher(findOrCreateTeacher(teacherMap, lineTokens[1])); course.setLectureSize(Integer.parseInt(lineTokens[2])); course.setMinWorkingDaySize(Integer.parseInt(lineTokens[3])); course.setCurriculumList(new ArrayList<Curriculum>()); course.setStudentSize(Integer.parseInt(lineTokens[4])); courseList.add(course); courseMap.put(course.getCode(), course); } schedule.setCourseList(courseList); List<Teacher> teacherList = new ArrayList<Teacher>(teacherMap.values()); schedule.setTeacherList(teacherList); return courseMap; } private Teacher findOrCreateTeacher(Map<String, Teacher> teacherMap, String code) { Teacher teacher = teacherMap.get(code); if (teacher == null) { teacher = new Teacher(); int id = teacherMap.size(); teacher.setId((long) id); teacher.setCode(code); teacherMap.put(code, teacher); } return teacher; } private void readRoomList(CurriculumCourseSchedule schedule, int roomListSize) throws IOException { readHeader("ROOMS:"); List<Room> roomList = new ArrayList<Room>(roomListSize); for (int i = 0; i < roomListSize; i++) { Room room = new Room(); room.setId((long) i); // Rooms: <RoomID> <Capacity> String line = bufferedReader.readLine(); String[] lineTokens = line.split(SPLIT_REGEX); if (lineTokens.length != 2) { throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 2 tokens."); } room.setCode(lineTokens[0]); room.setCapacity(Integer.parseInt(lineTokens[1])); roomList.add(room); } schedule.setRoomList(roomList); } private Map<List<Integer>, Period> createPeriodListAndDayListAndTimeslotList( CurriculumCourseSchedule schedule, int dayListSize, int timeslotListSize) throws IOException { int periodListSize = dayListSize * timeslotListSize; Map<List<Integer>, Period> periodMap = new HashMap<List<Integer>, Period>(periodListSize); List<Day> dayList = new ArrayList<Day>(dayListSize); for (int i = 0; i < dayListSize; i++) { Day day = new Day(); day.setId((long) i); day.setDayIndex(i); dayList.add(day); } schedule.setDayList(dayList); List<Timeslot> timeslotList = new ArrayList<Timeslot>(timeslotListSize); for (int i = 0; i < timeslotListSize; i++) { Timeslot timeslot = new Timeslot(); timeslot.setId((long) i); timeslot.setTimeslotIndex(i); timeslotList.add(timeslot); } schedule.setTimeslotList(timeslotList); List<Period> periodList = new ArrayList<Period>(periodListSize); for (int i = 0; i < dayListSize; i++) { for (int j = 0; j < timeslotListSize; j++) { Period period = new Period(); period.setId((long) (i * timeslotListSize + j)); period.setDay(dayList.get(i)); period.setTimeslot(timeslotList.get(j)); periodList.add(period); periodMap.put(Arrays.asList(i, j), period); } } schedule.setPeriodList(periodList); return periodMap; } private void readCurriculumList(CurriculumCourseSchedule schedule, Map<String, Course> courseMap, int curriculumListSize) throws IOException { readHeader("CURRICULA:"); List<Curriculum> curriculumList = new ArrayList<Curriculum>(curriculumListSize); for (int i = 0; i < curriculumListSize; i++) { Curriculum curriculum = new Curriculum(); curriculum.setId((long) i); // Curricula: <CurriculumID> <# Courses> <MemberID> ... <MemberID> String line = bufferedReader.readLine(); String[] lineTokens = line.split(SPLIT_REGEX); if (lineTokens.length < 2) { throw new IllegalArgumentException("Read line (" + line + ") is expected to contain at least 2 tokens."); } curriculum.setCode(lineTokens[0]); int coursesInCurriculum = Integer.parseInt(lineTokens[1]); if (lineTokens.length != (coursesInCurriculum + 2)) { throw new IllegalArgumentException("Read line (" + line + ") is expected to contain " + (coursesInCurriculum + 2) + " tokens."); } for (int j = 2; j < lineTokens.length; j++) { Course course = courseMap.get(lineTokens[j]); if (course == null) { throw new IllegalArgumentException("Read line (" + line + ") uses an unexisting course(" + lineTokens[j] + ")."); } course.getCurriculumList().add(curriculum); } curriculumList.add(curriculum); } schedule.setCurriculumList(curriculumList); } private void readUnavailablePeriodConstraintList(CurriculumCourseSchedule schedule, Map<String, Course> courseMap, Map<List<Integer>, Period> periodMap, int unavailablePeriodConstraintListSize) throws IOException { readHeader("UNAVAILABILITY_CONSTRAINTS:"); List<UnavailablePeriodConstraint> constraintList = new ArrayList<UnavailablePeriodConstraint>( unavailablePeriodConstraintListSize); for (int i = 0; i < unavailablePeriodConstraintListSize; i++) { UnavailablePeriodConstraint constraint = new UnavailablePeriodConstraint(); constraint.setId((long) i); // Unavailability_Constraints: <CourseID> <Day> <Day_Period> String line = bufferedReader.readLine(); String[] lineTokens = line.split(SPLIT_REGEX); if (lineTokens.length != 3) { throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 3 tokens."); } constraint.setCourse(courseMap.get(lineTokens[0])); int dayIndex = Integer.parseInt(lineTokens[1]); int timeslotIndex = Integer.parseInt(lineTokens[2]); Period period = periodMap.get(Arrays.asList(dayIndex, timeslotIndex)); if (period == null) { throw new IllegalArgumentException("Read line (" + line + ") uses an unexisting period(" + dayIndex + " " + timeslotIndex + ")."); } constraint.setPeriod(period); constraintList.add(constraint); } schedule.setUnavailablePeriodConstraintList(constraintList); } private String readParam(String key) throws IOException { String line = bufferedReader.readLine(); String[] lineTokens = line.split(SPLIT_REGEX); if (lineTokens.length != 2 || !lineTokens[0].equals(key)) { throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 2 tokens" + " and start with \"" + key + "\"."); } return lineTokens[1]; } private void readHeader(String header) throws IOException { String line = bufferedReader.readLine(); if (line.length() != 0) { throw new IllegalArgumentException("Read line (" + line + ") is expected to be empty" + " and be followed with a line \"" + header + "\"."); } line = bufferedReader.readLine(); if (!line.equals(header)) { throw new IllegalArgumentException("Read line (" + line + ") is expected to be \"" + header + "\"."); } } } }