/*
* This file is part of the TimeFinder project.
* Visit http://www.timefinder.de for more information.
*
* Copyright (c) 2009 the original author or authors.
*
* 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 de.timefinder.core.io.xml.bt;
import de.timefinder.data.algo.DataPoolSettings;
import de.timefinder.algo.constraint.RasterConstraint;
import de.timefinder.data.ConstraintObject;
import de.timefinder.data.DBInterface;
import de.timefinder.data.DataPool;
import de.timefinder.data.Event;
import de.timefinder.data.Feature;
import de.timefinder.data.Role;
import de.timefinder.data.Resource;
import de.timefinder.data.access.Dao;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javolution.util.FastMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This class provides an import from the xml offered from University Bayreuth
* All time units are "1 hour". (e.g. for duration)
*
* Created at 16.09.2009 from Mr. Karich - peathal at yah oo dot de
*/
public class ImportBTXml {
private Log logger = LogFactory.getLog(getClass());
private File folder;
private Dao<de.timefinder.data.Event> eDao;
private Dao<de.timefinder.data.Person> pDao;
private Dao<de.timefinder.data.Location> lDao;
private Dao<de.timefinder.data.Feature> fDao;
private DataPool dataPool;
private String rangeName = "SS 2009";
private int hourOffset = 8;
private Map<String, List<Event>> eventsMap = new FastMap<String, List<Event>>();
private Map<String, Course> courseMap = new FastMap<String, Course>();
private int nnCounter = 1;
private DataPoolSettings settings;
public ImportBTXml(DataPool dataPool, File folder) {
if (!folder.isDirectory())
throw new IllegalArgumentException("Specified file isn't a directory:" + folder);
this.folder = folder;
this.dataPool = dataPool;
lDao = dataPool.getDao(de.timefinder.data.Location.class);
pDao = dataPool.getDao(de.timefinder.data.Person.class);
eDao = dataPool.getDao(de.timefinder.data.Event.class);
fDao = dataPool.getDao(de.timefinder.data.Feature.class);
}
public void setDataPoolSettings(DataPoolSettings settings) {
this.settings = settings;
}
public void setRangeName(String rangeName) {
if (rangeName == null)
throw new NullPointerException("Name of scheduling-range cannot be null!");
this.rangeName = rangeName;
}
public <T> T getData(Class<T> clazz, String str) throws Exception {
JAXBContext context = JAXBContext.newInstance(clazz);
Unmarshaller u = context.createUnmarshaller();
return (T) u.unmarshal(new FileReader(new File(folder, str)));
}
private void setFire(boolean b) {
for (Dao dao : dataPool.getDaos()) {
dao.setFirePropertyChange(b);
}
}
private void refresh() {
for (Dao dao : dataPool.getDaos()) {
dao.refresh();
}
}
public void doWork() throws Exception {
setFire(false);
CoursesRoot courseRoot = getData(CoursesRoot.class, "newcourses.xml");
LocationsRoot locationsRoot = getData(LocationsRoot.class, "newlocations.xml");
// IdentitiesRoot identitiesRoot = getData(IdentitiesRoot.class, "newidentities.xml");
RangesRoot rangesRoot = getData(RangesRoot.class, "newranges.xml");
CosesRoot cosesRoot = getData(CosesRoot.class, "newcoses.xml");
for (Course course : courseRoot.getCourses().getCourse()) {
courseMap.put(course.getId().toString(), course);
}
/***** Locations to TF-Locations ****/
for (Location loc : locationsRoot.getLocations().getLocation()) {
if (loc.getName() == null) {
logger.warn("location has null name:" + loc.getCapacity());
continue;
}
de.timefinder.data.Location tfLoc = getOrCreateLocation(loc.getName());
if (loc.getCapacity() == null)
logger.warn("location has no capacity:" + loc.getName());
else
tfLoc.setCapacity(loc.getCapacity().intValue());
Feature building = getOrCreateBuilding(loc.getBuilding());
if (building != null)
tfLoc.addFeature(building);
}
/***** CourseSections into Events (and Persons) ****/
for (SchedulingRange sr : rangesRoot.getSchedulingRanges().getSchedulingRange()) {
if (!rangeName.equals(sr.getName())) {
continue;
}
for (CourseSection cs : sr.getCourseSection()) {
if (cs.getTeacher() == null) {
logger.fatal("Skipped courseSection because teacher was null. CourseRef:" + cs.getCourseRef());
continue;
}
de.timefinder.data.Person teacher = getOrCreatePerson(cs.getTeacher().getRef());
// associated certain events with one course reference (for later usage)
String courseRef = cs.getCourseRef().toString();
Course course = getCourse(courseRef);
if (course == null) {
logger.fatal("Couldn't found course for reference:" + courseRef);
continue;
}
List<Event> events4CoursesInCos = getEvents(courseRef);
for (RepeatingAppointment ra : cs.getRepeatingAppointment()) {
Event event = new Event();
event.setName(course.getName());
event.setStart(ra.getStartHour().intValue() - hourOffset);
if (ra.getDuration().intValue() > 0)
event.setDuration(ra.getDuration().intValue());
else
logger.fatal("Duration is not positive in event of courseSection " + cs.getCourseRef());
if (ra.getLocationRef() != null)
event.setLocation(getOrCreateLocation(ra.getLocationRef()));
events4CoursesInCos.add(event);
teacher.addEvent(event, Role.TEACHER, true);
eDao.attach(event);
}
}
}
Resource resource;
int semester;
for (CourseOfStudy cos : cosesRoot.getCourseOfStudys().getCourseOfStudy()) {
Map<Integer, Resource> resourcePerSemester = new FastMap<Integer, Resource>();
if (cos.getExaminationRegulation() == null) {
logger.warn("No ex reg in " + cos.getName() + " exReg==" + cos.getExaminationRegulation() + " courses:" + cos);
continue;
}
if (cos.getExaminationRegulation().getCoursesInCos() == null) {
logger.warn("No courses in " + cos.getExaminationRegulation().getName());
continue;
}
// get all courses in one courseOfStudy-object
for (CourseInCos cInCos : cos.getExaminationRegulation().getCoursesInCos().getCourseInCos()) {
semester = cInCos.getSemester().intValue();
resource = resourcePerSemester.get(semester);
if (resource == null) {
resource = new de.timefinder.data.Person();
resource.setName(cos.getName() + "-" + semester);
pDao.attach((de.timefinder.data.Person) resource);
resourcePerSemester.put(semester, resource);
}
for (Event event : getEvents(cInCos.getRef().toString())) {
resource.addEvent(event, true);
}
}
}
for (Dao<? extends DBInterface> dao : dataPool.getDaos()) {
logger.info(dao.getType().getSimpleName() + " size: " + dao.getAll().size());
for (DBInterface obj : dao.getAll()) {
ConstraintObject val = ((ConstraintObject) obj);
if (val.getConstraint(RasterConstraint.class) == null) {
val.putConstraint(new RasterConstraint(settings.createWeekRaster()));
}
}
}
setFire(true);
refresh();
}
de.timefinder.data.Person getOrCreatePerson(String name) {
if ("n.n.".equalsIgnoreCase(name) || "n. n.".equalsIgnoreCase(name.toLowerCase()))
name = "N.N." + nnCounter++;
if ("tutoren".equalsIgnoreCase(name))
name = "Tutor" + nnCounter++;
de.timefinder.data.Person person = pDao.findFirstByName(name);
if (person == null) {
person = new de.timefinder.data.Person();
person.setName(name);
pDao.attach(person);
}
return person;
}
de.timefinder.data.Location getOrCreateLocation(String name) {
if (name == null)
throw new NullPointerException("Name of location cannot be null!");
de.timefinder.data.Location loc = lDao.findFirstByName(name);
if (loc == null) {
loc = new de.timefinder.data.Location();
loc.setName(name);
lDao.attach(loc);
}
return loc;
}
/**
* This method returns all events for the specified course reference.
*/
private List<Event> getEvents(String courseRef) {
List<Event> events = eventsMap.get(courseRef);
if (events == null) {
events = new ArrayList<Event>();
eventsMap.put(courseRef, events);
}
return events;
}
/**
* This method returns all events for the specified course reference.
*/
private Course getCourse(String courseRef) {
return courseMap.get(courseRef);
}
private Feature getOrCreateBuilding(String name) {
if (name == null)
return null;
de.timefinder.data.Feature feature = fDao.findFirstByName(name);
if (feature == null) {
feature = new de.timefinder.data.Feature();
feature.setName(name);
fDao.attach(feature);
}
return feature;
}
public static void overwriteSettings(DataPoolSettings settings) {
settings.setNumberOfDays(5);
// 1 hour
settings.setMillisPerTimeslot(60 * 60 * 1000L);
settings.setTimeslotsPerDay(13);
}
}