[jboss-svn-commits] JBL Code SVN: r32372 - in labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples: common/business and 20 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Apr 2 15:37:08 EDT 2010


Author: ge0ffrey
Date: 2010-04-02 15:37:03 -0400 (Fri, 02 Apr 2010)
New Revision: 32372

Added:
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009SolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentSolutionImporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionExporter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionImporter.java
Removed:
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009InputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleOutputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentInputConverter.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentOutputConverter.java
Modified:
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/app/CommonApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/business/SolutionBusiness.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/swingui/WorkflowFrame.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/app/CurriculumCourseApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/app/ExaminationApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/lessonschedule/app/LessonScheduleApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/app/Manners2009App.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nqueens/app/NQueensApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/app/NurseRosteringApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/app/PatientAdmissionScheduleApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/AbstractTravelingTournamentApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/simple/SimpleTravelingTournamentApp.java
   labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/smart/SmartTravelingTournamentApp.java
Log:
export and import button on examples where applicable + rename input/output converter to solution importer/exporter

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/app/CommonApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/app/CommonApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/app/CommonApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -4,6 +4,8 @@
 
 import org.drools.planner.core.Solver;
 import org.drools.planner.examples.common.business.SolutionBusiness;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.common.persistence.XstreamSolutionDaoImpl;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
@@ -32,15 +34,25 @@
     protected SolutionBusiness createSolutionBusiness() {
         SolutionBusiness solutionBusiness = new SolutionBusiness();
         solutionBusiness.setSolutionDao(solutionDao);
+        solutionBusiness.setImporter(createSolutionImporter());
+        solutionBusiness.setExporter(createSolutionExporter());
         solutionBusiness.setDataDir(solutionDao.getDataDir());
         solutionBusiness.setSolver(createSolver());
         return solutionBusiness;
     }
 
-    protected abstract SolutionDao createSolutionDao();
-
     protected abstract Solver createSolver();
 
     protected abstract SolutionPanel createSolutionPanel();
 
+    protected abstract SolutionDao createSolutionDao();
+
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return null;
+    }
+
+    protected AbstractSolutionExporter createSolutionExporter() {
+        return null;
+    }
+
 }

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/business/SolutionBusiness.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/business/SolutionBusiness.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/business/SolutionBusiness.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -23,6 +23,8 @@
 import org.drools.planner.core.score.constraint.UnweightedConstraintOccurrence;
 import org.drools.planner.core.score.Score;
 import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,8 +38,13 @@
 
     private SolutionDao solutionDao;
 
+    private AbstractSolutionImporter importer;
+    private AbstractSolutionExporter exporter;
+
+    private File importDataDir;
     private File unsolvedDataDir;
     private File solvedDataDir;
+    private File exportDataDir;
 
     // volatile because the solve method doesn't come from the event thread (like every other method call)
     private volatile Solver solver;
@@ -47,7 +54,30 @@
         this.solutionDao = solutionDao;
     }
 
+    public void setImporter(AbstractSolutionImporter importer) {
+        this.importer = importer;
+    }
+
+    public void setExporter(AbstractSolutionExporter exporter) {
+        this.exporter = exporter;
+    }
+
+    public boolean hasImporter() {
+        return importer != null;
+    }
+
+    public boolean hasExporter() {
+        return exporter != null;
+    }
+
     public void setDataDir(File dataDir) {
+        if (hasImporter()) {
+            importDataDir = new File(dataDir, "input");
+            if (!importDataDir.exists()) {
+                throw new IllegalStateException("The directory importDataDir (" + importDataDir.getAbsolutePath()
+                        + ") does not exist. The working directory should be set to drools-planner-examples.");
+            }
+        }
         unsolvedDataDir = new File(dataDir, "unsolved");
         if (!unsolvedDataDir.exists()) {
             throw new IllegalStateException("The directory unsolvedDataDir (" + unsolvedDataDir.getAbsolutePath()
@@ -58,8 +88,19 @@
             throw new IllegalStateException("The directory solvedDataDir (" + solvedDataDir.getAbsolutePath()
                     + ") does not exist. The working directory should be set to drools-planner-examples.");
         }
+        if (hasExporter()) {
+            exportDataDir = new File(dataDir, "output");
+            if (!exportDataDir.exists()) {
+                throw new IllegalStateException("The directory exportDataDir (" + exportDataDir.getAbsolutePath()
+                        + ") does not exist. The working directory should be set to drools-planner-examples.");
+            }
+        }
     }
 
+    public File getImportDataDir() {
+        return importDataDir;
+    }
+
     public File getUnsolvedDataDir() {
         return unsolvedDataDir;
     }
@@ -68,6 +109,10 @@
         return solvedDataDir;
     }
 
+    public File getExportDataDir() {
+        return exportDataDir;
+    }
+
     public void setSolver(Solver solver) {
         this.solver = solver;
         this.localSearchSolverScope = ((DefaultLocalSearchSolver) solver).getLocalSearchSolverScope();
@@ -131,16 +176,26 @@
         return scoreDetailList;
     }
 
-    public void load(File file) {
+    public void importSolution(File file) {
+        Solution solution = importer.readSolution(file);
+        solver.setStartingSolution(solution);
+    }
+
+    public void loadSolution(File file) {
         Solution solution = solutionDao.readSolution(file);
         solver.setStartingSolution(solution);
     }
 
-    public void save(File file) {
+    public void saveSolution(File file) {
         Solution solution = localSearchSolverScope.getWorkingSolution();
         solutionDao.writeSolution(solution, file);
     }
 
+    public void exportSolution(File file) {
+        Solution solution = localSearchSolverScope.getWorkingSolution();
+        exporter.writeSolution(solution, file);
+    }
+
     public void doMove(Move move) {
         if (!move.isMoveDoable(localSearchSolverScope.getWorkingMemory())) {
             logger.info("Not doing user move ({}) because it is not doable.", move);

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,60 +0,0 @@
-package org.drools.planner.examples.common.persistence;
-
-import java.io.File;
-import java.util.Arrays;
-
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.app.LoggingMain;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class AbstractInputConverter extends LoggingMain {
-
-    protected static final String DEFAULT_OUTPUT_FILE_SUFFIX = ".xml";
-    
-    protected SolutionDao solutionDao;
-
-    public AbstractInputConverter(SolutionDao solutionDao) {
-        this.solutionDao = solutionDao;
-    }
-
-    protected File getInputDir() {
-        return new File(solutionDao.getDataDir(), "input");
-    }
-
-    protected abstract String getInputFileSuffix();
-
-    protected File getOutputDir() {
-        return new File(solutionDao.getDataDir(), "unsolved");
-    }
-
-    protected String getOutputFileSuffix() {
-        return DEFAULT_OUTPUT_FILE_SUFFIX;
-    }
-
-    public void convertAll() {
-        File inputDir = getInputDir();
-        File outputDir = getOutputDir();
-        File[] inputFiles = inputDir.listFiles();
-        if (inputFiles == null) {
-            throw new IllegalArgumentException(
-                    "Your working dir should be drools-planner-examples and contain: " + inputDir);
-        }
-        Arrays.sort(inputFiles);
-        for (File inputFile : inputFiles) {
-            String inputFileName = inputFile.getName();
-            if (inputFileName.endsWith(getInputFileSuffix())) {
-                Solution solution = readSolution(inputFile);
-                String outputFileName = inputFileName.substring(0,
-                        inputFileName.length() - getInputFileSuffix().length())
-                        + getOutputFileSuffix();
-                File outputFile = new File(outputDir, outputFileName);
-                solutionDao.writeSolution(solution, outputFile);
-            }
-        }
-    }
-
-    public abstract Solution readSolution(File inputFile);
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,58 +0,0 @@
-package org.drools.planner.examples.common.persistence;
-
-import java.io.File;
-import java.util.Arrays;
-
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.app.LoggingMain;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class AbstractOutputConverter extends LoggingMain {
-
-    private static final String DEFAULT_INPUT_FILE_SUFFIX = ".xml";
-    protected SolutionDao solutionDao;
-
-    public AbstractOutputConverter(SolutionDao solutionDao) {
-        this.solutionDao = solutionDao;
-    }
-
-    protected File getInputDir() {
-        return new File(solutionDao.getDataDir(), "solved");
-    }
-
-    protected File getOutputDir() {
-        return new File(solutionDao.getDataDir(), "output");
-    }
-
-    protected String getInputFileSuffix() {
-        return DEFAULT_INPUT_FILE_SUFFIX;
-    }
-
-    protected abstract String getOutputFileSuffix();
-
-    public void convertAll() {
-        File inputDir = getInputDir();
-        File outputDir = getOutputDir();
-        File[] inputFiles = inputDir.listFiles();
-        Arrays.sort(inputFiles);
-        if (inputFiles == null) {
-            throw new IllegalArgumentException(
-                    "Your working dir should be drools-planner-examples and contain: " + inputDir);
-        }
-        for (File inputFile : inputFiles) {
-            String inputFileName = inputFile.getName();
-            if (inputFileName.endsWith(getInputFileSuffix())) {
-                Solution solution = solutionDao.readSolution(inputFile);
-                String outputFileName = inputFileName.substring(0,
-                        inputFileName.length() - getInputFileSuffix().length())
-                        + getOutputFileSuffix();
-                File outputFile = new File(outputDir, outputFileName);
-                writeSolution(solution, outputFile);
-            }
-        }
-    }
-
-    public abstract void writeSolution(Solution solution, File outputFile);
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionExporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,58 @@
+package org.drools.planner.examples.common.persistence;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.app.LoggingMain;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class AbstractSolutionExporter extends LoggingMain {
+
+    private static final String DEFAULT_INPUT_FILE_SUFFIX = ".xml";
+    protected SolutionDao solutionDao;
+
+    public AbstractSolutionExporter(SolutionDao solutionDao) {
+        this.solutionDao = solutionDao;
+    }
+
+    protected File getInputDir() {
+        return new File(solutionDao.getDataDir(), "solved");
+    }
+
+    protected File getOutputDir() {
+        return new File(solutionDao.getDataDir(), "output");
+    }
+
+    protected String getInputFileSuffix() {
+        return DEFAULT_INPUT_FILE_SUFFIX;
+    }
+
+    protected abstract String getOutputFileSuffix();
+
+    public void convertAll() {
+        File inputDir = getInputDir();
+        File outputDir = getOutputDir();
+        File[] inputFiles = inputDir.listFiles();
+        Arrays.sort(inputFiles);
+        if (inputFiles == null) {
+            throw new IllegalArgumentException(
+                    "Your working dir should be drools-planner-examples and contain: " + inputDir);
+        }
+        for (File inputFile : inputFiles) {
+            String inputFileName = inputFile.getName();
+            if (inputFileName.endsWith(getInputFileSuffix())) {
+                Solution solution = solutionDao.readSolution(inputFile);
+                String outputFileName = inputFileName.substring(0,
+                        inputFileName.length() - getInputFileSuffix().length())
+                        + getOutputFileSuffix();
+                File outputFile = new File(outputDir, outputFileName);
+                writeSolution(solution, outputFile);
+            }
+        }
+    }
+
+    public abstract void writeSolution(Solution solution, File outputFile);
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,60 @@
+package org.drools.planner.examples.common.persistence;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.app.LoggingMain;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class AbstractSolutionImporter extends LoggingMain {
+
+    protected static final String DEFAULT_OUTPUT_FILE_SUFFIX = ".xml";
+    
+    protected SolutionDao solutionDao;
+
+    public AbstractSolutionImporter(SolutionDao solutionDao) {
+        this.solutionDao = solutionDao;
+    }
+
+    protected File getInputDir() {
+        return new File(solutionDao.getDataDir(), "input");
+    }
+
+    protected abstract String getInputFileSuffix();
+
+    protected File getOutputDir() {
+        return new File(solutionDao.getDataDir(), "unsolved");
+    }
+
+    protected String getOutputFileSuffix() {
+        return DEFAULT_OUTPUT_FILE_SUFFIX;
+    }
+
+    public void convertAll() {
+        File inputDir = getInputDir();
+        File outputDir = getOutputDir();
+        File[] inputFiles = inputDir.listFiles();
+        if (inputFiles == null) {
+            throw new IllegalArgumentException(
+                    "Your working dir should be drools-planner-examples and contain: " + inputDir);
+        }
+        Arrays.sort(inputFiles);
+        for (File inputFile : inputFiles) {
+            String inputFileName = inputFile.getName();
+            if (inputFileName.endsWith(getInputFileSuffix())) {
+                Solution solution = readSolution(inputFile);
+                String outputFileName = inputFileName.substring(0,
+                        inputFileName.length() - getInputFileSuffix().length())
+                        + getOutputFileSuffix();
+                File outputFile = new File(outputDir, outputFileName);
+                solutionDao.writeSolution(solution, outputFile);
+            }
+        }
+    }
+
+    public abstract Solution readSolution(File inputFile);
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,101 +0,0 @@
-package org.drools.planner.examples.common.persistence;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-
-import org.apache.commons.io.IOUtils;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class AbstractTxtInputConverter extends AbstractInputConverter {
-
-    private static final String DEFAULT_INPUT_FILE_SUFFIX = ".txt";
-
-    protected AbstractTxtInputConverter(SolutionDao solutionDao) {
-        super(solutionDao);
-    }
-
-    protected String getInputFileSuffix() {
-        return DEFAULT_INPUT_FILE_SUFFIX;
-    }
-
-    public abstract TxtInputBuilder createTxtInputBuilder();
-
-    public Solution readSolution(File inputFile) {
-        BufferedReader bufferedReader = null;
-        try {
-            bufferedReader = new BufferedReader(new FileReader(inputFile));
-            TxtInputBuilder txtInputBuilder = createTxtInputBuilder();
-            txtInputBuilder.setBufferedReader(bufferedReader);
-            return txtInputBuilder.readSolution();
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Could not read the file (" + inputFile.getName() + ").", e);
-        } finally {
-            IOUtils.closeQuietly(bufferedReader);
-        }
-    }
-
-    public abstract class TxtInputBuilder {
-
-        protected BufferedReader bufferedReader;
-
-        public void setBufferedReader(BufferedReader bufferedReader) {
-            this.bufferedReader = bufferedReader;
-        }
-
-        public abstract Solution readSolution() throws IOException;
-
-        // ************************************************************************
-        // Helper methods
-        // ************************************************************************
-
-        public void readEmptyLine() throws IOException {
-            readConstantLine("");
-        }
-
-        public void readConstantLine(String constantValue) throws IOException {
-            String line = bufferedReader.readLine();
-            String value = line.trim();
-            if (!value.equals(constantValue)) {
-                throw new IllegalArgumentException("Read line (" + line + ") is expected to be a constant value ("
-                        + constantValue + ").");
-            }
-        }
-
-        public int readIntegerValue() throws IOException {
-            return readIntegerValue("");
-        }
-
-        public int readIntegerValue(String prefix) throws IOException {
-            return readIntegerValue(prefix, "");
-        }
-
-        public int readIntegerValue(String prefix, String suffix) throws IOException {
-            String line = bufferedReader.readLine();
-            String value = line.trim();
-            if (!value.startsWith(prefix)) {
-                throw new IllegalArgumentException("Read line (" + line + ") is expected to start with prefix ("
-                        + prefix + ").");
-            }
-            value = value.substring(prefix.length());
-            if (!value.endsWith(suffix)) {
-                throw new IllegalArgumentException("Read line (" + line + ") is expected to end with suffix ("
-                        + suffix + ").");
-            }
-            value = value.substring(0, value.length() - suffix.length());
-            value = value.trim();
-            try {
-                return Integer.parseInt(value);
-            } catch (NumberFormatException e) {
-                throw new IllegalArgumentException("Read line (" + line + ") is expected to contain an integer value ("
-                        + value + ").", e);
-            }
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,61 +0,0 @@
-package org.drools.planner.examples.common.persistence;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-
-import org.apache.commons.io.IOUtils;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class AbstractTxtOutputConverter extends AbstractOutputConverter {
-
-    protected static final String DEFAULT_OUTPUT_FILE_SUFFIX = ".txt";
-
-    protected AbstractTxtOutputConverter(SolutionDao solutionDao) {
-        super(solutionDao);
-    }
-
-    protected String getOutputFileSuffix() {
-        return DEFAULT_OUTPUT_FILE_SUFFIX;
-    }
-
-    public abstract TxtOutputBuilder createTxtOutputBuilder();
-
-    public void writeSolution(Solution solution, File outputFile) {
-        BufferedWriter bufferedWriter = null;
-        try {
-            bufferedWriter = new BufferedWriter(new FileWriter(outputFile));
-            TxtOutputBuilder txtOutputBuilder = createTxtOutputBuilder();
-            txtOutputBuilder.setBufferedWriter(bufferedWriter);
-            txtOutputBuilder.setSolution(solution);
-            txtOutputBuilder.writeSolution();
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Could not write the file (" + outputFile.getName() + ").", e);
-        } finally {
-            IOUtils.closeQuietly(bufferedWriter);
-        }
-    }
-
-    public abstract class TxtOutputBuilder {
-
-        protected BufferedWriter bufferedWriter;
-
-        public void setBufferedWriter(BufferedWriter bufferedWriter) {
-            this.bufferedWriter = bufferedWriter;
-        }
-        
-        public abstract void setSolution(Solution solution);
-
-        public abstract void writeSolution() throws IOException;
-
-        // ************************************************************************
-        // Helper methods
-        // ************************************************************************
-
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionExporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,61 @@
+package org.drools.planner.examples.common.persistence;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+
+import org.apache.commons.io.IOUtils;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class AbstractTxtSolutionExporter extends AbstractSolutionExporter {
+
+    protected static final String DEFAULT_OUTPUT_FILE_SUFFIX = ".txt";
+
+    protected AbstractTxtSolutionExporter(SolutionDao solutionDao) {
+        super(solutionDao);
+    }
+
+    protected String getOutputFileSuffix() {
+        return DEFAULT_OUTPUT_FILE_SUFFIX;
+    }
+
+    public abstract TxtOutputBuilder createTxtOutputBuilder();
+
+    public void writeSolution(Solution solution, File outputFile) {
+        BufferedWriter bufferedWriter = null;
+        try {
+            bufferedWriter = new BufferedWriter(new FileWriter(outputFile));
+            TxtOutputBuilder txtOutputBuilder = createTxtOutputBuilder();
+            txtOutputBuilder.setBufferedWriter(bufferedWriter);
+            txtOutputBuilder.setSolution(solution);
+            txtOutputBuilder.writeSolution();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Could not write the file (" + outputFile.getName() + ").", e);
+        } finally {
+            IOUtils.closeQuietly(bufferedWriter);
+        }
+    }
+
+    public abstract class TxtOutputBuilder {
+
+        protected BufferedWriter bufferedWriter;
+
+        public void setBufferedWriter(BufferedWriter bufferedWriter) {
+            this.bufferedWriter = bufferedWriter;
+        }
+        
+        public abstract void setSolution(Solution solution);
+
+        public abstract void writeSolution() throws IOException;
+
+        // ************************************************************************
+        // Helper methods
+        // ************************************************************************
+
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractTxtSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,101 @@
+package org.drools.planner.examples.common.persistence;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class AbstractTxtSolutionImporter extends AbstractSolutionImporter {
+
+    private static final String DEFAULT_INPUT_FILE_SUFFIX = ".txt";
+
+    protected AbstractTxtSolutionImporter(SolutionDao solutionDao) {
+        super(solutionDao);
+    }
+
+    protected String getInputFileSuffix() {
+        return DEFAULT_INPUT_FILE_SUFFIX;
+    }
+
+    public abstract TxtInputBuilder createTxtInputBuilder();
+
+    public Solution readSolution(File inputFile) {
+        BufferedReader bufferedReader = null;
+        try {
+            bufferedReader = new BufferedReader(new FileReader(inputFile));
+            TxtInputBuilder txtInputBuilder = createTxtInputBuilder();
+            txtInputBuilder.setBufferedReader(bufferedReader);
+            return txtInputBuilder.readSolution();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Could not read the file (" + inputFile.getName() + ").", e);
+        } finally {
+            IOUtils.closeQuietly(bufferedReader);
+        }
+    }
+
+    public abstract class TxtInputBuilder {
+
+        protected BufferedReader bufferedReader;
+
+        public void setBufferedReader(BufferedReader bufferedReader) {
+            this.bufferedReader = bufferedReader;
+        }
+
+        public abstract Solution readSolution() throws IOException;
+
+        // ************************************************************************
+        // Helper methods
+        // ************************************************************************
+
+        public void readEmptyLine() throws IOException {
+            readConstantLine("");
+        }
+
+        public void readConstantLine(String constantValue) throws IOException {
+            String line = bufferedReader.readLine();
+            String value = line.trim();
+            if (!value.equals(constantValue)) {
+                throw new IllegalArgumentException("Read line (" + line + ") is expected to be a constant value ("
+                        + constantValue + ").");
+            }
+        }
+
+        public int readIntegerValue() throws IOException {
+            return readIntegerValue("");
+        }
+
+        public int readIntegerValue(String prefix) throws IOException {
+            return readIntegerValue(prefix, "");
+        }
+
+        public int readIntegerValue(String prefix, String suffix) throws IOException {
+            String line = bufferedReader.readLine();
+            String value = line.trim();
+            if (!value.startsWith(prefix)) {
+                throw new IllegalArgumentException("Read line (" + line + ") is expected to start with prefix ("
+                        + prefix + ").");
+            }
+            value = value.substring(prefix.length());
+            if (!value.endsWith(suffix)) {
+                throw new IllegalArgumentException("Read line (" + line + ") is expected to end with suffix ("
+                        + suffix + ").");
+            }
+            value = value.substring(0, value.length() - suffix.length());
+            value = value.trim();
+            try {
+                return Integer.parseInt(value);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Read line (" + line + ") is expected to contain an integer value ("
+                        + value + ").", e);
+            }
+        }
+
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,75 +0,0 @@
-package org.drools.planner.examples.common.persistence;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.commons.io.IOUtils;
-import org.drools.planner.core.solution.Solution;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class AbstractXmlInputConverter extends AbstractInputConverter {
-
-    private static final String DEFAULT_INPUT_FILE_SUFFIX = ".xml";
-
-    protected AbstractXmlInputConverter(SolutionDao solutionDao) {
-        super(solutionDao);
-    }
-
-    protected String getInputFileSuffix() {
-        return DEFAULT_INPUT_FILE_SUFFIX;
-    }
-
-    public abstract XmlInputBuilder createXmlInputBuilder();
-
-    public Solution readSolution(File inputFile) {
-        InputStream in = null;
-        try {
-            in = new FileInputStream(inputFile);
-            SAXBuilder builder = new SAXBuilder(false);
-            Document document = builder.build(in);
-            XmlInputBuilder txtInputBuilder = createXmlInputBuilder();
-            txtInputBuilder.setDocument(document);
-            return txtInputBuilder.readSolution();
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Could not read the file (" + inputFile.getName() + ").", e);
-        } catch (JDOMException e) {
-            throw new IllegalArgumentException("Could not parse the XML file (" + inputFile.getName() + ").", e);
-        } finally {
-            IOUtils.closeQuietly(in);
-        }
-    }
-
-    public abstract class XmlInputBuilder {
-
-        protected Document document;
-
-        public void setDocument(Document document) {
-            this.document = document;
-        }
-
-        public abstract Solution readSolution() throws IOException, JDOMException;
-
-        // ************************************************************************
-        // Helper methods
-        // ************************************************************************
-
-        protected void assertElementName(Element element, String name) {
-            if (!element.getName().equals(name)) {
-                throw new IllegalStateException("Element name (" + element.getName()
-                        + ") should be " + name +".");
-            }
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,73 +0,0 @@
-package org.drools.planner.examples.common.persistence;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.commons.io.IOUtils;
-import org.drools.planner.core.solution.Solution;
-import org.jdom.Document;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-import org.jdom.output.Format;
-import org.jdom.output.XMLOutputter;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class AbstractXmlOutputConverter extends AbstractOutputConverter {
-
-    protected static final String DEFAULT_OUTPUT_FILE_SUFFIX = ".xml";
-
-    protected AbstractXmlOutputConverter(SolutionDao solutionDao) {
-        super(solutionDao);
-    }
-
-    protected String getOutputFileSuffix() {
-        return DEFAULT_OUTPUT_FILE_SUFFIX;
-    }
-
-    public abstract XmlOutputBuilder createXmlOutputBuilder();
-
-    public void writeSolution(Solution solution, File outputFile) {
-        OutputStream out = null;
-        try {
-            out = new FileOutputStream(outputFile);
-            Document document = new Document();
-            XmlOutputBuilder xmlOutputBuilder = createXmlOutputBuilder();
-            xmlOutputBuilder.setDocument(document);
-            xmlOutputBuilder.setSolution(solution);
-            xmlOutputBuilder.writeSolution();
-            XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
-            outputter.output(document, out);
-        } catch (IOException e) {
-            throw new IllegalArgumentException("Could not write the file (" + outputFile.getName() + ").", e);
-        } catch (JDOMException e) {
-            throw new IllegalArgumentException("Could not format the XML file (" + outputFile.getName() + ").", e);
-        } finally {
-            IOUtils.closeQuietly(out);
-        }
-    }
-
-    public abstract class XmlOutputBuilder {
-
-        protected Document document;
-
-        public void setDocument(Document document) {
-            this.document = document;
-        }
-
-        public abstract void setSolution(Solution solution);
-
-        public abstract void writeSolution() throws IOException, JDOMException;
-
-        // ************************************************************************
-        // Helper methods
-        // ************************************************************************
-
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionExporter.java (from rev 32330, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,70 @@
+package org.drools.planner.examples.common.persistence;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.drools.planner.core.solution.Solution;
+import org.jdom.Document;
+import org.jdom.JDOMException;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class AbstractXmlSolutionExporter extends AbstractSolutionExporter {
+
+    protected static final String DEFAULT_OUTPUT_FILE_SUFFIX = ".xml";
+
+    protected AbstractXmlSolutionExporter(SolutionDao solutionDao) {
+        super(solutionDao);
+    }
+
+    protected String getOutputFileSuffix() {
+        return DEFAULT_OUTPUT_FILE_SUFFIX;
+    }
+
+    public abstract XmlOutputBuilder createXmlOutputBuilder();
+
+    public void writeSolution(Solution solution, File outputFile) {
+        OutputStream out = null;
+        try {
+            out = new FileOutputStream(outputFile);
+            Document document = new Document();
+            XmlOutputBuilder xmlOutputBuilder = createXmlOutputBuilder();
+            xmlOutputBuilder.setDocument(document);
+            xmlOutputBuilder.setSolution(solution);
+            xmlOutputBuilder.writeSolution();
+            XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
+            outputter.output(document, out);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Could not write the file (" + outputFile.getName() + ").", e);
+        } catch (JDOMException e) {
+            throw new IllegalArgumentException("Could not format the XML file (" + outputFile.getName() + ").", e);
+        } finally {
+            IOUtils.closeQuietly(out);
+        }
+    }
+
+    public abstract class XmlOutputBuilder {
+
+        protected Document document;
+
+        public void setDocument(Document document) {
+            this.document = document;
+        }
+
+        public abstract void setSolution(Solution solution);
+
+        public abstract void writeSolution() throws IOException, JDOMException;
+
+        // ************************************************************************
+        // Helper methods
+        // ************************************************************************
+
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/persistence/AbstractXmlSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,73 @@
+package org.drools.planner.examples.common.persistence;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.drools.planner.core.solution.Solution;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class AbstractXmlSolutionImporter extends AbstractSolutionImporter {
+
+    private static final String DEFAULT_INPUT_FILE_SUFFIX = ".xml";
+
+    protected AbstractXmlSolutionImporter(SolutionDao solutionDao) {
+        super(solutionDao);
+    }
+
+    protected String getInputFileSuffix() {
+        return DEFAULT_INPUT_FILE_SUFFIX;
+    }
+
+    public abstract XmlInputBuilder createXmlInputBuilder();
+
+    public Solution readSolution(File inputFile) {
+        InputStream in = null;
+        try {
+            in = new FileInputStream(inputFile);
+            SAXBuilder builder = new SAXBuilder(false);
+            Document document = builder.build(in);
+            XmlInputBuilder txtInputBuilder = createXmlInputBuilder();
+            txtInputBuilder.setDocument(document);
+            return txtInputBuilder.readSolution();
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Could not read the file (" + inputFile.getName() + ").", e);
+        } catch (JDOMException e) {
+            throw new IllegalArgumentException("Could not parse the XML file (" + inputFile.getName() + ").", e);
+        } finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+    public abstract class XmlInputBuilder {
+
+        protected Document document;
+
+        public void setDocument(Document document) {
+            this.document = document;
+        }
+
+        public abstract Solution readSolution() throws IOException, JDOMException;
+
+        // ************************************************************************
+        // Helper methods
+        // ************************************************************************
+
+        protected void assertElementName(Element element, String name) {
+            if (!element.getName().equals(name)) {
+                throw new IllegalStateException("Element name (" + element.getName()
+                        + ") should be " + name +".");
+            }
+        }
+
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/swingui/WorkflowFrame.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/swingui/WorkflowFrame.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/common/swingui/WorkflowFrame.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -4,8 +4,6 @@
 import java.awt.Dimension;
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
 import java.io.File;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -50,7 +48,9 @@
     private Action cancelSolvingAction;
     private Action solveAction;
     private Action saveAction;
-    
+    private Action importAction;
+    private Action exportAction;
+
     private JProgressBar progressBar;
     private JLabel resultLabel;
     private ShowConstraintScoreMapDialogAction showConstraintScoreMapDialogAction;
@@ -141,10 +141,8 @@
         }
 
         public void actionPerformed(ActionEvent e) {
-            solutionBusiness.load(file);
-            solveAction.setEnabled(true);
-            saveAction.setEnabled(true);
-            updateScreen();
+            solutionBusiness.loadSolution(file);
+            setSolutionLoaded();
         }
 
     }
@@ -160,9 +158,22 @@
         saveAction = new SaveAction();
         saveAction.setEnabled(false);
         panel.add(new JButton(saveAction));
+        importAction = new ImportAction();
+        importAction.setEnabled(solutionBusiness.hasImporter());
+        panel.add(new JButton(importAction));
+        exportAction = new ExportAction();
+        exportAction.setEnabled(false);
+        panel.add(new JButton(exportAction));
         return panel;
     }
 
+    private void setSolutionLoaded() {
+        solveAction.setEnabled(true);
+        saveAction.setEnabled(true);
+        exportAction.setEnabled(solutionBusiness.hasExporter());
+        updateScreen();
+    }
+
     private void setSolvingState(boolean solving) {
         for (Action action : loadUnsolvedActionList) {
             action.setEnabled(!solving);
@@ -173,6 +184,8 @@
         solveAction.setEnabled(!solving);
         cancelSolvingAction.setEnabled(solving);
         saveAction.setEnabled(!solving);
+        importAction.setEnabled(!solving && solutionBusiness.hasImporter());
+        exportAction.setEnabled(!solving && solutionBusiness.hasExporter());
         solutionPanel.setEnabled(!solving);
         progressBar.setIndeterminate(solving);
         progressBar.setStringPainted(solving);
@@ -243,12 +256,61 @@
             });
             int approved = fileChooser.showSaveDialog(WorkflowFrame.this);
             if (approved == JFileChooser.APPROVE_OPTION) {
-                solutionBusiness.save(fileChooser.getSelectedFile());
+                solutionBusiness.saveSolution(fileChooser.getSelectedFile());
             }
         }
 
     }
 
+    private class ImportAction extends AbstractAction {
+
+        public ImportAction() {
+            super("Import...");
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            JFileChooser fileChooser = new JFileChooser(solutionBusiness.getImportDataDir());
+            fileChooser.setFileFilter(new FileFilter() {
+                public boolean accept(File file) {
+                    return file.isDirectory() || file.getName().endsWith(".xml"); // TODO
+                }
+                public String getDescription() {
+                    return "Solver xml files"; // TODO
+                }
+            });
+            int approved = fileChooser.showOpenDialog(WorkflowFrame.this);
+            if (approved == JFileChooser.APPROVE_OPTION) {
+                solutionBusiness.importSolution(fileChooser.getSelectedFile());
+                setSolutionLoaded();
+            }
+        }
+
+    }
+
+    private class ExportAction extends AbstractAction {
+
+        public ExportAction() {
+            super("Export as...");
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            JFileChooser fileChooser = new JFileChooser(solutionBusiness.getExportDataDir());
+            fileChooser.setFileFilter(new FileFilter() {
+                public boolean accept(File file) {
+                    return file.isDirectory() || file.getName().endsWith(".xml"); // TODO
+                }
+                public String getDescription() {
+                    return "Solver xml files"; // TODO
+                }
+            });
+            int approved = fileChooser.showSaveDialog(WorkflowFrame.this);
+            if (approved == JFileChooser.APPROVE_OPTION) {
+                solutionBusiness.exportSolution(fileChooser.getSelectedFile());
+            }
+        }
+
+    }
+
     private JPanel createScorePanel() {
         JPanel panel = new JPanel(new BorderLayout());
         progressBar = new JProgressBar(0, 100);

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/app/CurriculumCourseApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/app/CurriculumCourseApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/app/CurriculumCourseApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -3,9 +3,13 @@
 import org.drools.planner.config.XmlSolverConfigurer;
 import org.drools.planner.core.Solver;
 import org.drools.planner.examples.common.app.CommonApp;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
 import org.drools.planner.examples.curriculumcourse.persistence.CurriculumCourseDaoImpl;
+import org.drools.planner.examples.curriculumcourse.persistence.CurriculumCourseSolutionExporter;
+import org.drools.planner.examples.curriculumcourse.persistence.CurriculumCourseSolutionImporter;
 import org.drools.planner.examples.curriculumcourse.swingui.CurriculumCoursePanel;
 
 /**
@@ -21,11 +25,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new CurriculumCourseDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -37,4 +36,19 @@
         return new CurriculumCoursePanel();
     }
 
-}
\ No newline at end of file
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new CurriculumCourseDaoImpl();
+    }
+
+    @Override
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return new CurriculumCourseSolutionImporter();
+    }
+
+    @Override
+    protected AbstractSolutionExporter createSolutionExporter() {
+        return new CurriculumCourseSolutionExporter();
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,275 +0,0 @@
-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.AbstractTxtInputConverter;
-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 CurriculumCourseInputConverter extends AbstractTxtInputConverter {
-
-    private static final String INPUT_FILE_SUFFIX = ".ctt";
-    private static final String SPLIT_REGEX = "[\\ \\t]+";
-
-    public static void main(String[] args) {
-        new CurriculumCourseInputConverter().convertAll();
-    }
-
-    public CurriculumCourseInputConverter() {
-        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 + "\".");
-            }
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,52 +0,0 @@
-package org.drools.planner.examples.curriculumcourse.persistence;
-
-import java.io.IOException;
-
-import org.drools.planner.examples.common.persistence.AbstractTxtOutputConverter;
-import org.drools.planner.examples.curriculumcourse.domain.CurriculumCourseSchedule;
-import org.drools.planner.examples.curriculumcourse.domain.Lecture;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public class CurriculumCourseOutputConverter extends AbstractTxtOutputConverter {
-
-    private static final String OUTPUT_FILE_SUFFIX = ".sol";
-
-    public static void main(String[] args) {
-        new CurriculumCourseOutputConverter().convertAll();
-    }
-
-    public CurriculumCourseOutputConverter() {
-        super(new CurriculumCourseDaoImpl());
-    }
-
-    @Override
-    protected String getOutputFileSuffix() {
-        return OUTPUT_FILE_SUFFIX;
-    }
-
-    public TxtOutputBuilder createTxtOutputBuilder() {
-        return new CurriculumCourseOutputBuilder();
-    }
-
-    public class CurriculumCourseOutputBuilder extends TxtOutputBuilder {
-
-        private CurriculumCourseSchedule schedule;
-
-        public void setSolution(Solution solution) {
-            schedule = (CurriculumCourseSchedule) solution;
-        }
-
-        public void writeSolution() throws IOException {
-            for (Lecture lecture : schedule.getLectureList()) {
-                bufferedWriter.write(lecture.getCourse().getCode()
-                        + " r" + lecture.getRoom().getCode()
-                        + " " + lecture.getPeriod().getDay().getDayIndex()
-                        + " " + lecture.getPeriod().getTimeslot().getTimeslotIndex() + "\r\n");
-            }
-        }
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionExporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,52 @@
+package org.drools.planner.examples.curriculumcourse.persistence;
+
+import java.io.IOException;
+
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionExporter;
+import org.drools.planner.examples.curriculumcourse.domain.CurriculumCourseSchedule;
+import org.drools.planner.examples.curriculumcourse.domain.Lecture;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class CurriculumCourseSolutionExporter extends AbstractTxtSolutionExporter {
+
+    private static final String OUTPUT_FILE_SUFFIX = ".sol";
+
+    public static void main(String[] args) {
+        new CurriculumCourseSolutionExporter().convertAll();
+    }
+
+    public CurriculumCourseSolutionExporter() {
+        super(new CurriculumCourseDaoImpl());
+    }
+
+    @Override
+    protected String getOutputFileSuffix() {
+        return OUTPUT_FILE_SUFFIX;
+    }
+
+    public TxtOutputBuilder createTxtOutputBuilder() {
+        return new CurriculumCourseOutputBuilder();
+    }
+
+    public class CurriculumCourseOutputBuilder extends TxtOutputBuilder {
+
+        private CurriculumCourseSchedule schedule;
+
+        public void setSolution(Solution solution) {
+            schedule = (CurriculumCourseSchedule) solution;
+        }
+
+        public void writeSolution() throws IOException {
+            for (Lecture lecture : schedule.getLectureList()) {
+                bufferedWriter.write(lecture.getCourse().getCode()
+                        + " r" + lecture.getRoom().getCode()
+                        + " " + lecture.getPeriod().getDay().getDayIndex()
+                        + " " + lecture.getPeriod().getTimeslot().getTimeslotIndex() + "\r\n");
+            }
+        }
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/curriculumcourse/persistence/CurriculumCourseSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,275 @@
+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 + "\".");
+            }
+        }
+
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/app/ExaminationApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/app/ExaminationApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/app/ExaminationApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -3,9 +3,13 @@
 import org.drools.planner.config.XmlSolverConfigurer;
 import org.drools.planner.core.Solver;
 import org.drools.planner.examples.common.app.CommonApp;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
 import org.drools.planner.examples.examination.persistence.ExaminationDaoImpl;
+import org.drools.planner.examples.examination.persistence.ExaminationSolutionExporter;
+import org.drools.planner.examples.examination.persistence.ExaminationSolutionImporter;
 import org.drools.planner.examples.examination.swingui.ExaminationPanel;
 
 /**
@@ -21,11 +25,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new ExaminationDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -37,4 +36,19 @@
         return new ExaminationPanel();
     }
 
-}
\ No newline at end of file
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new ExaminationDaoImpl();
+    }
+
+    @Override
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return new ExaminationSolutionImporter();
+    }
+
+    @Override
+    protected AbstractSolutionExporter createSolutionExporter() {
+        return new ExaminationSolutionExporter();
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,331 +0,0 @@
-package org.drools.planner.examples.examination.persistence;
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.lang.builder.CompareToBuilder;
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.persistence.AbstractTxtInputConverter;
-import org.drools.planner.examples.examination.domain.Examination;
-import org.drools.planner.examples.examination.domain.InstitutionalWeighting;
-import org.drools.planner.examples.examination.domain.Period;
-import org.drools.planner.examples.examination.domain.PeriodHardConstraint;
-import org.drools.planner.examples.examination.domain.PeriodHardConstraintType;
-import org.drools.planner.examples.examination.domain.Room;
-import org.drools.planner.examples.examination.domain.RoomHardConstraint;
-import org.drools.planner.examples.examination.domain.RoomHardConstraintType;
-import org.drools.planner.examples.examination.domain.Student;
-import org.drools.planner.examples.examination.domain.Topic;
-
-/**
- * @author Geoffrey De Smet
- */
-public class ExaminationInputConverter extends AbstractTxtInputConverter {
-
-    private static final String INPUT_FILE_SUFFIX = ".exam";
-    private static final String SPLIT_REGEX = "\\,\\ ?";
-
-    public static void main(String[] args) {
-        new ExaminationInputConverter().convertAll();
-    }
-
-    public ExaminationInputConverter() {
-        super(new ExaminationDaoImpl());
-    }
-
-    @Override
-    protected String getInputFileSuffix() {
-        return INPUT_FILE_SUFFIX;
-    }
-
-    public TxtInputBuilder createTxtInputBuilder() {
-        return new ExaminationInputBuilder();
-    }
-
-    public class ExaminationInputBuilder extends TxtInputBuilder {
-
-        public Solution readSolution() throws IOException {
-            Examination examination = new Examination();
-            examination.setId(0L);
-
-            readTopicListAndStudentList(examination);
-            readPeriodList(examination);
-            readRoomList(examination);
-
-            String line = bufferedReader.readLine();
-            if (!line.equals("[PeriodHardConstraints]")) {
-                throw new IllegalStateException("Read line (" + line
-                        + " is not the expected header ([PeriodHardConstraints])");
-            }
-            readPeriodHardConstraintList(examination);
-            readRoomHardConstraintList(examination);
-            readInstitutionalWeighting(examination);
-            tagFrontLoadLargeTopics(examination);
-            tagFrontLoadLastPeriods(examination);
-
-            logger.info("Examination with {} students, {} topics/exams, {} periods, {} rooms, {} period constraints" +
-                    " and {} room constraints.",
-                    new Object[]{examination.getStudentList().size(), examination.getTopicList().size(),
-                            examination.getPeriodList().size(), examination.getRoomList().size(),
-                            examination.getPeriodHardConstraintList().size(),
-                            examination.getRoomHardConstraintList().size()});
-
-            // Note: examList stays null, that's work for the StartingSolutionInitializer
-            return examination;
-        }
-
-        private void readTopicListAndStudentList(Examination examination) throws IOException {
-            Map<Integer, Student> studentMap = new HashMap<Integer, Student>();
-            int examSize = readHeaderWithNumber("Exams");
-            List<Topic> topicList = new ArrayList<Topic>(examSize);
-            for (int i = 0; i < examSize; i++) {
-                Topic topic = new Topic();
-                topic.setId((long) i);
-                String line = bufferedReader.readLine();
-                String[] lineTokens = line.split(SPLIT_REGEX);
-                topic.setDuration(Integer.parseInt(lineTokens[0]));
-                List<Student> topicStudentList = new ArrayList<Student>(lineTokens.length - 1);
-                for (int j = 1; j < lineTokens.length; j++) {
-                    topicStudentList.add(findOrCreateStudent(studentMap, Integer.parseInt(lineTokens[j])));
-                }
-                topic.setStudentList(topicStudentList);
-                topic.setFrontLoadLarge(false);
-                topicList.add(topic);
-            }
-            examination.setTopicList(topicList);
-            List<Student> studentList = new ArrayList<Student>(studentMap.values());
-            examination.setStudentList(studentList);
-        }
-
-        private Student findOrCreateStudent(Map<Integer, Student> studentMap, int id) {
-            Student student = studentMap.get(id);
-            if (student == null) {
-                student = new Student();
-                student.setId((long) id);
-                studentMap.put(id, student);
-            }
-            return student;
-        }
-
-        private void readPeriodList(Examination examination) throws IOException {
-            int periodSize = readHeaderWithNumber("Periods");
-            List<Period> periodList = new ArrayList<Period>(periodSize);
-            // Everything is in the default timezone and the default locale.
-            Calendar calendar = Calendar.getInstance();
-            final DateFormat DATE_FORMAT = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
-            int referenceDayOfYear = -1;
-            int referenceYear = -1;
-            for (int i = 0; i < periodSize; i++) {
-                Period period = new Period();
-                period.setId((long) i);
-                String line = bufferedReader.readLine();
-                String[] lineTokens = line.split(SPLIT_REGEX);
-                if (lineTokens.length != 4) {
-                    throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 4 tokens.");
-                }
-                String startDateTimeString = lineTokens[0] + " " + lineTokens[1];
-                period.setStartDateTimeString(startDateTimeString);
-                period.setPeriodIndex(i);
-                int dayOfYear;
-                int year;
-                try {
-                    calendar.setTime(DATE_FORMAT.parse(startDateTimeString));
-                    calendar.get(Calendar.DAY_OF_YEAR);
-                    dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
-                    year = calendar.get(Calendar.YEAR);
-                } catch (ParseException e) {
-                    throw new IllegalArgumentException("Illegal startDateTimeString (" + startDateTimeString + ").", e);
-                }
-                if (referenceDayOfYear < 0) {
-                    referenceDayOfYear = dayOfYear;
-                    referenceYear = year;
-                }
-                if (year != referenceYear) {
-                    // Because the Calendar API in JSE sucks... (java 7 will fix that FINALLY)
-                    throw new IllegalStateException("Not yet implemented to handle periods spread over different years...");
-                }
-                int dayIndex = dayOfYear - referenceDayOfYear;
-                if (dayIndex < 0) {
-                    throw new IllegalStateException("The periods should be in ascending order.");
-                }
-                period.setDayIndex(dayIndex);
-                period.setDuration(Integer.parseInt(lineTokens[2]));
-                period.setPenalty(Integer.parseInt(lineTokens[3]));
-                periodList.add(period);
-            }
-            examination.setPeriodList(periodList);
-        }
-
-        private void readRoomList(Examination examination) throws IOException {
-            int roomSize = readHeaderWithNumber("Rooms");
-            List<Room> roomList = new ArrayList<Room>(roomSize);
-            for (int i = 0; i < roomSize; i++) {
-                Room room = new Room();
-                room.setId((long) i);
-                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.setCapacity(Integer.parseInt(lineTokens[0]));
-                room.setPenalty(Integer.parseInt(lineTokens[1]));
-                roomList.add(room);
-            }
-            examination.setRoomList(roomList);
-        }
-
-        private void readPeriodHardConstraintList(Examination examination)
-                throws IOException {
-            List<Topic> topicList = examination.getTopicList();
-            List<PeriodHardConstraint> periodHardConstraintList = new ArrayList<PeriodHardConstraint>();
-            String line = bufferedReader.readLine();
-            int id = 0;
-            while (!line.equals("[RoomHardConstraints]")) {
-                String[] lineTokens = line.split(SPLIT_REGEX);
-                PeriodHardConstraint periodHardConstraint = new PeriodHardConstraint();
-                periodHardConstraint.setId((long) id);
-                if (lineTokens.length != 3) {
-                    throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 3 tokens.");
-                }
-                Topic leftTopic = topicList.get(Integer.parseInt(lineTokens[0]));
-                periodHardConstraint.setLeftSideTopic(leftTopic);
-                PeriodHardConstraintType periodHardConstraintType = PeriodHardConstraintType.valueOf(lineTokens[1]);
-                periodHardConstraint.setPeriodHardConstraintType(periodHardConstraintType);
-                Topic rightTopic = topicList.get(Integer.parseInt(lineTokens[2]));
-                periodHardConstraint.setRightSideTopic(rightTopic);
-                if (periodHardConstraintType == PeriodHardConstraintType.EXAM_COINCIDENCE) {
-                    // It's not specified what happens
-                    // when A coincidences with B and B coincidences with C
-                    // and when A and C share students (but don't directly coincidence)
-                    if (!Collections.disjoint(leftTopic.getStudentList(), rightTopic.getStudentList())) {
-                        logger.warn("Filtering out periodHardConstraint (" + periodHardConstraint
-                                + ") because the left and right topic share students.");
-                    } else {
-                        periodHardConstraintList.add(periodHardConstraint);
-                    }
-                } else {
-                    periodHardConstraintList.add(periodHardConstraint);
-                }
-                line = bufferedReader.readLine();
-                id++;
-            }
-            examination.setPeriodHardConstraintList(periodHardConstraintList);
-        }
-
-        private void readRoomHardConstraintList(Examination examination)
-                throws IOException {
-            List<Topic> topicList = examination.getTopicList();
-            List<RoomHardConstraint> roomHardConstraintList = new ArrayList<RoomHardConstraint>();
-            String line = bufferedReader.readLine();
-            int id = 0;
-            while (!line.equals("[InstitutionalWeightings]")) {
-                String[] lineTokens = line.split(SPLIT_REGEX);
-                RoomHardConstraint roomHardConstraint = new RoomHardConstraint();
-                roomHardConstraint.setId((long) id);
-                if (lineTokens.length != 2) {
-                    throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 3 tokens.");
-                }
-                roomHardConstraint.setTopic(topicList.get(Integer.parseInt(lineTokens[0])));
-                roomHardConstraint.setRoomHardConstraintType(RoomHardConstraintType.valueOf(lineTokens[1]));
-                roomHardConstraintList.add(roomHardConstraint);
-                line = bufferedReader.readLine();
-                id++;
-            }
-            examination.setRoomHardConstraintList(roomHardConstraintList);
-        }
-
-        private int readHeaderWithNumber(String header) throws IOException {
-            String line = bufferedReader.readLine();
-            if (!line.startsWith("[" + header + ":") || !line.endsWith("]")) {
-                throw new IllegalStateException("Read line (" + line + " is not the expected header (["
-                        + header + ":number])");
-            }
-            return Integer.parseInt(line.substring(header.length() + 2, line.length() - 1));
-        }
-
-        private void readInstitutionalWeighting(Examination examination) throws IOException {
-            InstitutionalWeighting institutionalWeighting = new InstitutionalWeighting();
-            institutionalWeighting.setId(0L);
-            String[] lineTokens;
-            lineTokens = readInstitutionalWeightingProperty("TWOINAROW", 2);
-            institutionalWeighting.setTwoInARowPenality(Integer.parseInt(lineTokens[1]));
-            lineTokens = readInstitutionalWeightingProperty("TWOINADAY", 2);
-            institutionalWeighting.setTwoInADayPenality(Integer.parseInt(lineTokens[1]));
-            lineTokens = readInstitutionalWeightingProperty("PERIODSPREAD", 2);
-            institutionalWeighting.setPeriodSpreadLength(Integer.parseInt(lineTokens[1]));
-            institutionalWeighting.setPeriodSpreadPenality(1); // constant
-            lineTokens = readInstitutionalWeightingProperty("NONMIXEDDURATIONS", 2);
-            institutionalWeighting.setMixedDurationPenality(Integer.parseInt(lineTokens[1]));
-            lineTokens = readInstitutionalWeightingProperty("FRONTLOAD", 4);
-            institutionalWeighting.setFrontLoadLargeTopicSize(Integer.parseInt(lineTokens[1]));
-            institutionalWeighting.setFrontLoadLastPeriodSize(Integer.parseInt(lineTokens[2]));
-            institutionalWeighting.setFrontLoadPenality(Integer.parseInt(lineTokens[3]));
-            examination.setInstitutionalWeighting(institutionalWeighting);
-        }
-
-        private String[] readInstitutionalWeightingProperty(String property,
-                int propertySize) throws IOException {
-            String[] lineTokens;
-            lineTokens = bufferedReader.readLine().split(SPLIT_REGEX);
-            if (!lineTokens[0].equals(property) || lineTokens.length != propertySize) {
-                throw new IllegalArgumentException("Read line (" + Arrays.toString(lineTokens)
-                        + ") is expected to contain " + propertySize + " tokens and start with " + property + ".");
-            }
-            return lineTokens;
-        }
-
-        private void tagFrontLoadLargeTopics(Examination examination) {
-            List<Topic> sortedTopicList = new ArrayList<Topic>(examination.getTopicList());
-            Collections.sort(sortedTopicList, new Comparator<Topic>() {
-                public int compare(Topic a, Topic b) {
-                    return new CompareToBuilder()
-                            .append(a.getStudentSize(), b.getStudentSize()) // Ascending
-                            .append(b.getId(), a.getId()) // Descending (according to spec)
-                            .toComparison();
-                }
-            });
-            int frontLoadLargeTopicSize = examination.getInstitutionalWeighting().getFrontLoadLargeTopicSize();
-            if (frontLoadLargeTopicSize == 0) {
-                return;
-            }
-            int minimumTopicId = sortedTopicList.size() - frontLoadLargeTopicSize;
-            if (minimumTopicId < 0) {
-                logger.warn("The frontLoadLargeTopicSize (" + frontLoadLargeTopicSize + ") is bigger than topicListSize ("
-                        + sortedTopicList.size() + "). Tagging all topic as frontLoadLarge...");
-                minimumTopicId = 0;
-            }
-            for (Topic topic : sortedTopicList.subList(minimumTopicId, sortedTopicList.size())) {
-                topic.setFrontLoadLarge(true);
-            }
-        }
-
-        private void tagFrontLoadLastPeriods(Examination examination) {
-            List<Period> periodList = examination.getPeriodList();
-            int frontLoadLastPeriodSize = examination.getInstitutionalWeighting().getFrontLoadLastPeriodSize();
-            if (frontLoadLastPeriodSize == 0) {
-                return;
-            }
-            int minimumPeriodId = periodList.size() - frontLoadLastPeriodSize;
-            if (minimumPeriodId < 0) {
-                logger.warn("The frontLoadLastPeriodSize (" + frontLoadLastPeriodSize + ") is bigger than periodListSize ("
-                        + periodList.size() + "). Tagging all periods as frontLoadLast...");
-                minimumPeriodId = 0;
-            }
-            for (Period period : periodList.subList(minimumPeriodId, periodList.size())) {
-                period.setFrontLoadLast(true);
-            }
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,53 +0,0 @@
-package org.drools.planner.examples.examination.persistence;
-
-import java.io.IOException;
-import java.util.Collections;
-
-import org.drools.planner.examples.common.domain.PersistableIdComparator;
-import org.drools.planner.examples.common.persistence.AbstractTxtOutputConverter;
-import org.drools.planner.examples.examination.domain.Exam;
-import org.drools.planner.examples.examination.domain.Examination;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public class ExaminationOutputConverter extends AbstractTxtOutputConverter {
-
-    private static final String OUTPUT_FILE_SUFFIX = ".sln";
-
-    public static void main(String[] args) {
-        new ExaminationOutputConverter().convertAll();
-    }
-
-    public ExaminationOutputConverter() {
-        super(new ExaminationDaoImpl());
-    }
-
-    @Override
-    protected String getOutputFileSuffix() {
-        return OUTPUT_FILE_SUFFIX;
-    }
-
-    public TxtOutputBuilder createTxtOutputBuilder() {
-        return new ExaminationOutputBuilder();
-    }
-
-    public class ExaminationOutputBuilder extends TxtOutputBuilder {
-
-        private Examination examination;
-
-        public void setSolution(Solution solution) {
-            examination = (Examination) solution;
-        }
-
-        public void writeSolution() throws IOException {
-            Collections.sort(examination.getExamList(), new PersistableIdComparator()); // TODO remove me when obsolete
-            for (Exam exam : examination.getExamList()) {
-                bufferedWriter.write(exam.getPeriod().getId() + ", " + exam.getRoom().getId() + "\r\n");
-            }
-        }
-        
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionExporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,53 @@
+package org.drools.planner.examples.examination.persistence;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import org.drools.planner.examples.common.domain.PersistableIdComparator;
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionExporter;
+import org.drools.planner.examples.examination.domain.Exam;
+import org.drools.planner.examples.examination.domain.Examination;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class ExaminationSolutionExporter extends AbstractTxtSolutionExporter {
+
+    private static final String OUTPUT_FILE_SUFFIX = ".sln";
+
+    public static void main(String[] args) {
+        new ExaminationSolutionExporter().convertAll();
+    }
+
+    public ExaminationSolutionExporter() {
+        super(new ExaminationDaoImpl());
+    }
+
+    @Override
+    protected String getOutputFileSuffix() {
+        return OUTPUT_FILE_SUFFIX;
+    }
+
+    public TxtOutputBuilder createTxtOutputBuilder() {
+        return new ExaminationOutputBuilder();
+    }
+
+    public class ExaminationOutputBuilder extends TxtOutputBuilder {
+
+        private Examination examination;
+
+        public void setSolution(Solution solution) {
+            examination = (Examination) solution;
+        }
+
+        public void writeSolution() throws IOException {
+            Collections.sort(examination.getExamList(), new PersistableIdComparator()); // TODO remove me when obsolete
+            for (Exam exam : examination.getExamList()) {
+                bufferedWriter.write(exam.getPeriod().getId() + ", " + exam.getRoom().getId() + "\r\n");
+            }
+        }
+        
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/examination/persistence/ExaminationSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,331 @@
+package org.drools.planner.examples.examination.persistence;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.builder.CompareToBuilder;
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionImporter;
+import org.drools.planner.examples.examination.domain.Examination;
+import org.drools.planner.examples.examination.domain.InstitutionalWeighting;
+import org.drools.planner.examples.examination.domain.Period;
+import org.drools.planner.examples.examination.domain.PeriodHardConstraint;
+import org.drools.planner.examples.examination.domain.PeriodHardConstraintType;
+import org.drools.planner.examples.examination.domain.Room;
+import org.drools.planner.examples.examination.domain.RoomHardConstraint;
+import org.drools.planner.examples.examination.domain.RoomHardConstraintType;
+import org.drools.planner.examples.examination.domain.Student;
+import org.drools.planner.examples.examination.domain.Topic;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class ExaminationSolutionImporter extends AbstractTxtSolutionImporter {
+
+    private static final String INPUT_FILE_SUFFIX = ".exam";
+    private static final String SPLIT_REGEX = "\\,\\ ?";
+
+    public static void main(String[] args) {
+        new ExaminationSolutionImporter().convertAll();
+    }
+
+    public ExaminationSolutionImporter() {
+        super(new ExaminationDaoImpl());
+    }
+
+    @Override
+    protected String getInputFileSuffix() {
+        return INPUT_FILE_SUFFIX;
+    }
+
+    public TxtInputBuilder createTxtInputBuilder() {
+        return new ExaminationInputBuilder();
+    }
+
+    public class ExaminationInputBuilder extends TxtInputBuilder {
+
+        public Solution readSolution() throws IOException {
+            Examination examination = new Examination();
+            examination.setId(0L);
+
+            readTopicListAndStudentList(examination);
+            readPeriodList(examination);
+            readRoomList(examination);
+
+            String line = bufferedReader.readLine();
+            if (!line.equals("[PeriodHardConstraints]")) {
+                throw new IllegalStateException("Read line (" + line
+                        + " is not the expected header ([PeriodHardConstraints])");
+            }
+            readPeriodHardConstraintList(examination);
+            readRoomHardConstraintList(examination);
+            readInstitutionalWeighting(examination);
+            tagFrontLoadLargeTopics(examination);
+            tagFrontLoadLastPeriods(examination);
+
+            logger.info("Examination with {} students, {} topics/exams, {} periods, {} rooms, {} period constraints" +
+                    " and {} room constraints.",
+                    new Object[]{examination.getStudentList().size(), examination.getTopicList().size(),
+                            examination.getPeriodList().size(), examination.getRoomList().size(),
+                            examination.getPeriodHardConstraintList().size(),
+                            examination.getRoomHardConstraintList().size()});
+
+            // Note: examList stays null, that's work for the StartingSolutionInitializer
+            return examination;
+        }
+
+        private void readTopicListAndStudentList(Examination examination) throws IOException {
+            Map<Integer, Student> studentMap = new HashMap<Integer, Student>();
+            int examSize = readHeaderWithNumber("Exams");
+            List<Topic> topicList = new ArrayList<Topic>(examSize);
+            for (int i = 0; i < examSize; i++) {
+                Topic topic = new Topic();
+                topic.setId((long) i);
+                String line = bufferedReader.readLine();
+                String[] lineTokens = line.split(SPLIT_REGEX);
+                topic.setDuration(Integer.parseInt(lineTokens[0]));
+                List<Student> topicStudentList = new ArrayList<Student>(lineTokens.length - 1);
+                for (int j = 1; j < lineTokens.length; j++) {
+                    topicStudentList.add(findOrCreateStudent(studentMap, Integer.parseInt(lineTokens[j])));
+                }
+                topic.setStudentList(topicStudentList);
+                topic.setFrontLoadLarge(false);
+                topicList.add(topic);
+            }
+            examination.setTopicList(topicList);
+            List<Student> studentList = new ArrayList<Student>(studentMap.values());
+            examination.setStudentList(studentList);
+        }
+
+        private Student findOrCreateStudent(Map<Integer, Student> studentMap, int id) {
+            Student student = studentMap.get(id);
+            if (student == null) {
+                student = new Student();
+                student.setId((long) id);
+                studentMap.put(id, student);
+            }
+            return student;
+        }
+
+        private void readPeriodList(Examination examination) throws IOException {
+            int periodSize = readHeaderWithNumber("Periods");
+            List<Period> periodList = new ArrayList<Period>(periodSize);
+            // Everything is in the default timezone and the default locale.
+            Calendar calendar = Calendar.getInstance();
+            final DateFormat DATE_FORMAT = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
+            int referenceDayOfYear = -1;
+            int referenceYear = -1;
+            for (int i = 0; i < periodSize; i++) {
+                Period period = new Period();
+                period.setId((long) i);
+                String line = bufferedReader.readLine();
+                String[] lineTokens = line.split(SPLIT_REGEX);
+                if (lineTokens.length != 4) {
+                    throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 4 tokens.");
+                }
+                String startDateTimeString = lineTokens[0] + " " + lineTokens[1];
+                period.setStartDateTimeString(startDateTimeString);
+                period.setPeriodIndex(i);
+                int dayOfYear;
+                int year;
+                try {
+                    calendar.setTime(DATE_FORMAT.parse(startDateTimeString));
+                    calendar.get(Calendar.DAY_OF_YEAR);
+                    dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
+                    year = calendar.get(Calendar.YEAR);
+                } catch (ParseException e) {
+                    throw new IllegalArgumentException("Illegal startDateTimeString (" + startDateTimeString + ").", e);
+                }
+                if (referenceDayOfYear < 0) {
+                    referenceDayOfYear = dayOfYear;
+                    referenceYear = year;
+                }
+                if (year != referenceYear) {
+                    // Because the Calendar API in JSE sucks... (java 7 will fix that FINALLY)
+                    throw new IllegalStateException("Not yet implemented to handle periods spread over different years...");
+                }
+                int dayIndex = dayOfYear - referenceDayOfYear;
+                if (dayIndex < 0) {
+                    throw new IllegalStateException("The periods should be in ascending order.");
+                }
+                period.setDayIndex(dayIndex);
+                period.setDuration(Integer.parseInt(lineTokens[2]));
+                period.setPenalty(Integer.parseInt(lineTokens[3]));
+                periodList.add(period);
+            }
+            examination.setPeriodList(periodList);
+        }
+
+        private void readRoomList(Examination examination) throws IOException {
+            int roomSize = readHeaderWithNumber("Rooms");
+            List<Room> roomList = new ArrayList<Room>(roomSize);
+            for (int i = 0; i < roomSize; i++) {
+                Room room = new Room();
+                room.setId((long) i);
+                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.setCapacity(Integer.parseInt(lineTokens[0]));
+                room.setPenalty(Integer.parseInt(lineTokens[1]));
+                roomList.add(room);
+            }
+            examination.setRoomList(roomList);
+        }
+
+        private void readPeriodHardConstraintList(Examination examination)
+                throws IOException {
+            List<Topic> topicList = examination.getTopicList();
+            List<PeriodHardConstraint> periodHardConstraintList = new ArrayList<PeriodHardConstraint>();
+            String line = bufferedReader.readLine();
+            int id = 0;
+            while (!line.equals("[RoomHardConstraints]")) {
+                String[] lineTokens = line.split(SPLIT_REGEX);
+                PeriodHardConstraint periodHardConstraint = new PeriodHardConstraint();
+                periodHardConstraint.setId((long) id);
+                if (lineTokens.length != 3) {
+                    throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 3 tokens.");
+                }
+                Topic leftTopic = topicList.get(Integer.parseInt(lineTokens[0]));
+                periodHardConstraint.setLeftSideTopic(leftTopic);
+                PeriodHardConstraintType periodHardConstraintType = PeriodHardConstraintType.valueOf(lineTokens[1]);
+                periodHardConstraint.setPeriodHardConstraintType(periodHardConstraintType);
+                Topic rightTopic = topicList.get(Integer.parseInt(lineTokens[2]));
+                periodHardConstraint.setRightSideTopic(rightTopic);
+                if (periodHardConstraintType == PeriodHardConstraintType.EXAM_COINCIDENCE) {
+                    // It's not specified what happens
+                    // when A coincidences with B and B coincidences with C
+                    // and when A and C share students (but don't directly coincidence)
+                    if (!Collections.disjoint(leftTopic.getStudentList(), rightTopic.getStudentList())) {
+                        logger.warn("Filtering out periodHardConstraint (" + periodHardConstraint
+                                + ") because the left and right topic share students.");
+                    } else {
+                        periodHardConstraintList.add(periodHardConstraint);
+                    }
+                } else {
+                    periodHardConstraintList.add(periodHardConstraint);
+                }
+                line = bufferedReader.readLine();
+                id++;
+            }
+            examination.setPeriodHardConstraintList(periodHardConstraintList);
+        }
+
+        private void readRoomHardConstraintList(Examination examination)
+                throws IOException {
+            List<Topic> topicList = examination.getTopicList();
+            List<RoomHardConstraint> roomHardConstraintList = new ArrayList<RoomHardConstraint>();
+            String line = bufferedReader.readLine();
+            int id = 0;
+            while (!line.equals("[InstitutionalWeightings]")) {
+                String[] lineTokens = line.split(SPLIT_REGEX);
+                RoomHardConstraint roomHardConstraint = new RoomHardConstraint();
+                roomHardConstraint.setId((long) id);
+                if (lineTokens.length != 2) {
+                    throw new IllegalArgumentException("Read line (" + line + ") is expected to contain 3 tokens.");
+                }
+                roomHardConstraint.setTopic(topicList.get(Integer.parseInt(lineTokens[0])));
+                roomHardConstraint.setRoomHardConstraintType(RoomHardConstraintType.valueOf(lineTokens[1]));
+                roomHardConstraintList.add(roomHardConstraint);
+                line = bufferedReader.readLine();
+                id++;
+            }
+            examination.setRoomHardConstraintList(roomHardConstraintList);
+        }
+
+        private int readHeaderWithNumber(String header) throws IOException {
+            String line = bufferedReader.readLine();
+            if (!line.startsWith("[" + header + ":") || !line.endsWith("]")) {
+                throw new IllegalStateException("Read line (" + line + " is not the expected header (["
+                        + header + ":number])");
+            }
+            return Integer.parseInt(line.substring(header.length() + 2, line.length() - 1));
+        }
+
+        private void readInstitutionalWeighting(Examination examination) throws IOException {
+            InstitutionalWeighting institutionalWeighting = new InstitutionalWeighting();
+            institutionalWeighting.setId(0L);
+            String[] lineTokens;
+            lineTokens = readInstitutionalWeightingProperty("TWOINAROW", 2);
+            institutionalWeighting.setTwoInARowPenality(Integer.parseInt(lineTokens[1]));
+            lineTokens = readInstitutionalWeightingProperty("TWOINADAY", 2);
+            institutionalWeighting.setTwoInADayPenality(Integer.parseInt(lineTokens[1]));
+            lineTokens = readInstitutionalWeightingProperty("PERIODSPREAD", 2);
+            institutionalWeighting.setPeriodSpreadLength(Integer.parseInt(lineTokens[1]));
+            institutionalWeighting.setPeriodSpreadPenality(1); // constant
+            lineTokens = readInstitutionalWeightingProperty("NONMIXEDDURATIONS", 2);
+            institutionalWeighting.setMixedDurationPenality(Integer.parseInt(lineTokens[1]));
+            lineTokens = readInstitutionalWeightingProperty("FRONTLOAD", 4);
+            institutionalWeighting.setFrontLoadLargeTopicSize(Integer.parseInt(lineTokens[1]));
+            institutionalWeighting.setFrontLoadLastPeriodSize(Integer.parseInt(lineTokens[2]));
+            institutionalWeighting.setFrontLoadPenality(Integer.parseInt(lineTokens[3]));
+            examination.setInstitutionalWeighting(institutionalWeighting);
+        }
+
+        private String[] readInstitutionalWeightingProperty(String property,
+                int propertySize) throws IOException {
+            String[] lineTokens;
+            lineTokens = bufferedReader.readLine().split(SPLIT_REGEX);
+            if (!lineTokens[0].equals(property) || lineTokens.length != propertySize) {
+                throw new IllegalArgumentException("Read line (" + Arrays.toString(lineTokens)
+                        + ") is expected to contain " + propertySize + " tokens and start with " + property + ".");
+            }
+            return lineTokens;
+        }
+
+        private void tagFrontLoadLargeTopics(Examination examination) {
+            List<Topic> sortedTopicList = new ArrayList<Topic>(examination.getTopicList());
+            Collections.sort(sortedTopicList, new Comparator<Topic>() {
+                public int compare(Topic a, Topic b) {
+                    return new CompareToBuilder()
+                            .append(a.getStudentSize(), b.getStudentSize()) // Ascending
+                            .append(b.getId(), a.getId()) // Descending (according to spec)
+                            .toComparison();
+                }
+            });
+            int frontLoadLargeTopicSize = examination.getInstitutionalWeighting().getFrontLoadLargeTopicSize();
+            if (frontLoadLargeTopicSize == 0) {
+                return;
+            }
+            int minimumTopicId = sortedTopicList.size() - frontLoadLargeTopicSize;
+            if (minimumTopicId < 0) {
+                logger.warn("The frontLoadLargeTopicSize (" + frontLoadLargeTopicSize + ") is bigger than topicListSize ("
+                        + sortedTopicList.size() + "). Tagging all topic as frontLoadLarge...");
+                minimumTopicId = 0;
+            }
+            for (Topic topic : sortedTopicList.subList(minimumTopicId, sortedTopicList.size())) {
+                topic.setFrontLoadLarge(true);
+            }
+        }
+
+        private void tagFrontLoadLastPeriods(Examination examination) {
+            List<Period> periodList = examination.getPeriodList();
+            int frontLoadLastPeriodSize = examination.getInstitutionalWeighting().getFrontLoadLastPeriodSize();
+            if (frontLoadLastPeriodSize == 0) {
+                return;
+            }
+            int minimumPeriodId = periodList.size() - frontLoadLastPeriodSize;
+            if (minimumPeriodId < 0) {
+                logger.warn("The frontLoadLastPeriodSize (" + frontLoadLastPeriodSize + ") is bigger than periodListSize ("
+                        + periodList.size() + "). Tagging all periods as frontLoadLast...");
+                minimumPeriodId = 0;
+            }
+            for (Period period : periodList.subList(minimumPeriodId, periodList.size())) {
+                period.setFrontLoadLast(true);
+            }
+        }
+
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/lessonschedule/app/LessonScheduleApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/lessonschedule/app/LessonScheduleApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/lessonschedule/app/LessonScheduleApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -22,11 +22,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new LessonScheduleDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -37,5 +32,10 @@
     protected SolutionPanel createSolutionPanel() {
         return new LessonSchedulePanel();
     }
-    
+
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new LessonScheduleDaoImpl();
+    }
+
 }

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/app/Manners2009App.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/app/Manners2009App.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/app/Manners2009App.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -3,9 +3,12 @@
 import org.drools.planner.config.XmlSolverConfigurer;
 import org.drools.planner.core.Solver;
 import org.drools.planner.examples.common.app.CommonApp;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
 import org.drools.planner.examples.manners2009.persistence.Manners2009DaoImpl;
+import org.drools.planner.examples.manners2009.persistence.Manners2009SolutionImporter;
 import org.drools.planner.examples.manners2009.swingui.Manners2009Panel;
 
 /**
@@ -21,11 +24,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new Manners2009DaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -37,4 +35,14 @@
         return new Manners2009Panel();
     }
 
-}
\ No newline at end of file
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new Manners2009DaoImpl();
+    }
+
+    @Override
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return new Manners2009SolutionImporter();
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009InputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009InputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009InputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,150 +0,0 @@
-package org.drools.planner.examples.manners2009.persistence;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.persistence.AbstractTxtInputConverter;
-import org.drools.planner.examples.manners2009.domain.Gender;
-import org.drools.planner.examples.manners2009.domain.Guest;
-import org.drools.planner.examples.manners2009.domain.Hobby;
-import org.drools.planner.examples.manners2009.domain.HobbyPractician;
-import org.drools.planner.examples.manners2009.domain.Job;
-import org.drools.planner.examples.manners2009.domain.JobType;
-import org.drools.planner.examples.manners2009.domain.Manners2009;
-import org.drools.planner.examples.manners2009.domain.Seat;
-import org.drools.planner.examples.manners2009.domain.Table;
-
-/**
- * @author Geoffrey De Smet
- */
-public class Manners2009InputConverter extends AbstractTxtInputConverter {
-
-    public static void main(String[] args) {
-        new Manners2009InputConverter().convertAll();
-    }
-
-    public Manners2009InputConverter() {
-        super(new Manners2009DaoImpl());
-    }
-
-    public TxtInputBuilder createTxtInputBuilder() {
-        return new Manners2009InputBuilder();
-    }
-
-    public class Manners2009InputBuilder extends TxtInputBuilder {
-
-        public Solution readSolution() throws IOException {
-            Manners2009 manners2009 = new Manners2009();
-            manners2009.setId(0L);
-
-            readTableListAndSeatList(manners2009);
-            readJobListGuestListAndHobbyPracticianList(manners2009);
-
-            logger.info("Manners2009 with {} jobs, {} guests, {} hobby practicians, {} tables and {} seats.",
-                    new Object[]{manners2009.getJobList().size(),
-                            manners2009.getGuestList().size(),
-                            manners2009.getHobbyPracticianList().size(),
-                            manners2009.getTableList().size(),
-                            manners2009.getSeatList().size()});
-
-            return manners2009;
-        }
-
-        private void readTableListAndSeatList(Manners2009 manners2009)
-                throws IOException {
-            int tableListSize = readIntegerValue("Tables:");
-            int seatsPerTable = readIntegerValue("SeatsPerTable:");
-            List<Table> tableList = new ArrayList<Table>(tableListSize);
-            List<Seat> seatList = new ArrayList<Seat>(tableListSize * seatsPerTable);
-            for (int i = 0; i < tableListSize; i++) {
-                Table table = new Table();
-                table.setId((long) i);
-                table.setTableIndex(i);
-                List<Seat> tableSeatList = new ArrayList<Seat>(seatsPerTable);
-                Seat firstSeat = null;
-                Seat previousSeat = null;
-                for (int j = 0; j < seatsPerTable; j++) {
-                    Seat seat = new Seat();
-                    seat.setId((long) ((i * seatsPerTable) + j));
-                    seat.setTable(table);
-                    seat.setSeatIndexInTable(j);
-                    if (previousSeat != null) {
-                        seat.setLeftSeat(previousSeat);
-                        previousSeat.setRightSeat(seat);
-                    } else {
-                        firstSeat = seat;
-                    }
-                    tableSeatList.add(seat);
-                    seatList.add(seat);
-                    previousSeat = seat;
-                }
-                firstSeat.setLeftSeat(previousSeat);
-                previousSeat.setRightSeat(firstSeat);
-                table.setSeatList(tableSeatList);
-                tableList.add(table);
-            }
-            manners2009.setTableList(tableList);
-            manners2009.setSeatList(seatList);
-        }
-
-
-        private void readJobListGuestListAndHobbyPracticianList(Manners2009 manners2009)
-                throws IOException {
-            readConstantLine("Num,Profession,SubProf,Gender,Spt1,Spt2,Spt3");
-            readConstantLine("-------------------------------------------");
-            int guestSize = manners2009.getSeatList().size();
-
-            List<Guest> guestList = new ArrayList<Guest>(guestSize);
-            List<HobbyPractician> hobbyPracticianList = new ArrayList<HobbyPractician>(guestSize * 3);
-            Map<String, Job> jobMap = new HashMap<String, Job>(JobType.values().length * 5);
-            int jobNextId = 0;
-            int hobbyPracticianJobId = 0;
-            for (int i = 0; i < guestSize; i++) {
-                Guest guest = new Guest();
-                guest.setId((long) i);
-                String line = bufferedReader.readLine();
-                String[] lineTokens = line.split("\\,");
-                if (lineTokens.length < 5) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain at least 5 tokens.");
-                }
-                guest.setCode(lineTokens[0].trim());
-                JobType jobType = JobType.valueOfCode(lineTokens[1].trim());
-                String jobName = lineTokens[2].trim();
-                String jobMapKey = jobType + "/" + jobName;
-                Job job = jobMap.get(jobMapKey);
-                if (job == null) {
-                    job = new Job();
-                    job.setId((long) jobNextId);
-                    jobNextId++;
-                    job.setJobType(jobType);
-                    job.setName(jobName);
-                    jobMap.put(jobMapKey, job);
-                }
-                guest.setJob(job);
-                guest.setGender(Gender.valueOfCode(lineTokens[3].trim()));
-                List<HobbyPractician> hobbyPracticianOfGuestList = new ArrayList<HobbyPractician>(lineTokens.length - 4);
-                for (int j = 4; j < lineTokens.length; j++) {
-                    HobbyPractician hobbyPractician = new HobbyPractician();
-                    hobbyPractician.setId((long) hobbyPracticianJobId);
-                    hobbyPracticianJobId++;
-                    hobbyPractician.setGuest(guest);
-                    hobbyPractician.setHobby(Hobby.valueOfCode(lineTokens[j].trim()));
-                    hobbyPracticianOfGuestList.add(hobbyPractician);
-                    hobbyPracticianList.add(hobbyPractician);
-                }
-                guest.setHobbyPracticianList(hobbyPracticianOfGuestList);
-                guestList.add(guest);
-            }
-            manners2009.setJobList(new ArrayList<Job>(jobMap.values()));
-            manners2009.setGuestList(guestList);
-            manners2009.setHobbyPracticianList(hobbyPracticianList);
-        }
-
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009SolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009InputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009SolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/manners2009/persistence/Manners2009SolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,150 @@
+package org.drools.planner.examples.manners2009.persistence;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionImporter;
+import org.drools.planner.examples.manners2009.domain.Gender;
+import org.drools.planner.examples.manners2009.domain.Guest;
+import org.drools.planner.examples.manners2009.domain.Hobby;
+import org.drools.planner.examples.manners2009.domain.HobbyPractician;
+import org.drools.planner.examples.manners2009.domain.Job;
+import org.drools.planner.examples.manners2009.domain.JobType;
+import org.drools.planner.examples.manners2009.domain.Manners2009;
+import org.drools.planner.examples.manners2009.domain.Seat;
+import org.drools.planner.examples.manners2009.domain.Table;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class Manners2009SolutionImporter extends AbstractTxtSolutionImporter {
+
+    public static void main(String[] args) {
+        new Manners2009SolutionImporter().convertAll();
+    }
+
+    public Manners2009SolutionImporter() {
+        super(new Manners2009DaoImpl());
+    }
+
+    public TxtInputBuilder createTxtInputBuilder() {
+        return new Manners2009InputBuilder();
+    }
+
+    public class Manners2009InputBuilder extends TxtInputBuilder {
+
+        public Solution readSolution() throws IOException {
+            Manners2009 manners2009 = new Manners2009();
+            manners2009.setId(0L);
+
+            readTableListAndSeatList(manners2009);
+            readJobListGuestListAndHobbyPracticianList(manners2009);
+
+            logger.info("Manners2009 with {} jobs, {} guests, {} hobby practicians, {} tables and {} seats.",
+                    new Object[]{manners2009.getJobList().size(),
+                            manners2009.getGuestList().size(),
+                            manners2009.getHobbyPracticianList().size(),
+                            manners2009.getTableList().size(),
+                            manners2009.getSeatList().size()});
+
+            return manners2009;
+        }
+
+        private void readTableListAndSeatList(Manners2009 manners2009)
+                throws IOException {
+            int tableListSize = readIntegerValue("Tables:");
+            int seatsPerTable = readIntegerValue("SeatsPerTable:");
+            List<Table> tableList = new ArrayList<Table>(tableListSize);
+            List<Seat> seatList = new ArrayList<Seat>(tableListSize * seatsPerTable);
+            for (int i = 0; i < tableListSize; i++) {
+                Table table = new Table();
+                table.setId((long) i);
+                table.setTableIndex(i);
+                List<Seat> tableSeatList = new ArrayList<Seat>(seatsPerTable);
+                Seat firstSeat = null;
+                Seat previousSeat = null;
+                for (int j = 0; j < seatsPerTable; j++) {
+                    Seat seat = new Seat();
+                    seat.setId((long) ((i * seatsPerTable) + j));
+                    seat.setTable(table);
+                    seat.setSeatIndexInTable(j);
+                    if (previousSeat != null) {
+                        seat.setLeftSeat(previousSeat);
+                        previousSeat.setRightSeat(seat);
+                    } else {
+                        firstSeat = seat;
+                    }
+                    tableSeatList.add(seat);
+                    seatList.add(seat);
+                    previousSeat = seat;
+                }
+                firstSeat.setLeftSeat(previousSeat);
+                previousSeat.setRightSeat(firstSeat);
+                table.setSeatList(tableSeatList);
+                tableList.add(table);
+            }
+            manners2009.setTableList(tableList);
+            manners2009.setSeatList(seatList);
+        }
+
+
+        private void readJobListGuestListAndHobbyPracticianList(Manners2009 manners2009)
+                throws IOException {
+            readConstantLine("Num,Profession,SubProf,Gender,Spt1,Spt2,Spt3");
+            readConstantLine("-------------------------------------------");
+            int guestSize = manners2009.getSeatList().size();
+
+            List<Guest> guestList = new ArrayList<Guest>(guestSize);
+            List<HobbyPractician> hobbyPracticianList = new ArrayList<HobbyPractician>(guestSize * 3);
+            Map<String, Job> jobMap = new HashMap<String, Job>(JobType.values().length * 5);
+            int jobNextId = 0;
+            int hobbyPracticianJobId = 0;
+            for (int i = 0; i < guestSize; i++) {
+                Guest guest = new Guest();
+                guest.setId((long) i);
+                String line = bufferedReader.readLine();
+                String[] lineTokens = line.split("\\,");
+                if (lineTokens.length < 5) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain at least 5 tokens.");
+                }
+                guest.setCode(lineTokens[0].trim());
+                JobType jobType = JobType.valueOfCode(lineTokens[1].trim());
+                String jobName = lineTokens[2].trim();
+                String jobMapKey = jobType + "/" + jobName;
+                Job job = jobMap.get(jobMapKey);
+                if (job == null) {
+                    job = new Job();
+                    job.setId((long) jobNextId);
+                    jobNextId++;
+                    job.setJobType(jobType);
+                    job.setName(jobName);
+                    jobMap.put(jobMapKey, job);
+                }
+                guest.setJob(job);
+                guest.setGender(Gender.valueOfCode(lineTokens[3].trim()));
+                List<HobbyPractician> hobbyPracticianOfGuestList = new ArrayList<HobbyPractician>(lineTokens.length - 4);
+                for (int j = 4; j < lineTokens.length; j++) {
+                    HobbyPractician hobbyPractician = new HobbyPractician();
+                    hobbyPractician.setId((long) hobbyPracticianJobId);
+                    hobbyPracticianJobId++;
+                    hobbyPractician.setGuest(guest);
+                    hobbyPractician.setHobby(Hobby.valueOfCode(lineTokens[j].trim()));
+                    hobbyPracticianOfGuestList.add(hobbyPractician);
+                    hobbyPracticianList.add(hobbyPractician);
+                }
+                guest.setHobbyPracticianList(hobbyPracticianOfGuestList);
+                guestList.add(guest);
+            }
+            manners2009.setJobList(new ArrayList<Job>(jobMap.values()));
+            manners2009.setGuestList(guestList);
+            manners2009.setHobbyPracticianList(hobbyPracticianList);
+        }
+
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nqueens/app/NQueensApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nqueens/app/NQueensApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nqueens/app/NQueensApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -21,11 +21,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new NQueensDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -37,4 +32,9 @@
         return new NQueensPanel();
     }
 
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new NQueensDaoImpl();
+    }
+
 }

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/app/NurseRosteringApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/app/NurseRosteringApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/app/NurseRosteringApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -3,9 +3,13 @@
 import org.drools.planner.config.XmlSolverConfigurer;
 import org.drools.planner.core.Solver;
 import org.drools.planner.examples.common.app.CommonApp;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
 import org.drools.planner.examples.nurserostering.persistence.NurseRosteringDaoImpl;
+import org.drools.planner.examples.nurserostering.persistence.NurseRosteringSolutionExporter;
+import org.drools.planner.examples.nurserostering.persistence.NurseRosteringSolutionImporter;
 import org.drools.planner.examples.nurserostering.swingui.NurseRosteringPanel;
 
 /**
@@ -21,11 +25,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new NurseRosteringDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -37,4 +36,19 @@
         return new NurseRosteringPanel();
     }
 
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new NurseRosteringDaoImpl();
+    }
+
+    @Override
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return new NurseRosteringSolutionImporter();
+    }
+
+    @Override
+    protected AbstractSolutionExporter createSolutionExporter() {
+        return new NurseRosteringSolutionExporter();
+    }
+
 }

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,645 +0,0 @@
-package org.drools.planner.examples.nurserostering.persistence;
-
-import java.io.IOException;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TimeZone;
-
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.persistence.AbstractXmlInputConverter;
-import org.drools.planner.examples.nurserostering.domain.Contract;
-import org.drools.planner.examples.nurserostering.domain.DayOfWeek;
-import org.drools.planner.examples.nurserostering.domain.DayOffRequest;
-import org.drools.planner.examples.nurserostering.domain.DayOnRequest;
-import org.drools.planner.examples.nurserostering.domain.Employee;
-import org.drools.planner.examples.nurserostering.domain.NurseRoster;
-import org.drools.planner.examples.nurserostering.domain.Pattern;
-import org.drools.planner.examples.nurserostering.domain.Shift;
-import org.drools.planner.examples.nurserostering.domain.ShiftDate;
-import org.drools.planner.examples.nurserostering.domain.ShiftOffRequest;
-import org.drools.planner.examples.nurserostering.domain.ShiftOnRequest;
-import org.drools.planner.examples.nurserostering.domain.ShiftType;
-import org.drools.planner.examples.nurserostering.domain.ShiftTypeSkillRequirement;
-import org.drools.planner.examples.nurserostering.domain.Skill;
-import org.drools.planner.examples.nurserostering.domain.SkillProficiency;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-
-/**
- * @author Geoffrey De Smet
- */
-public class NurseRosteringInputConverter extends AbstractXmlInputConverter {
-
-    public static void main(String[] args) {
-        new NurseRosteringInputConverter().convertAll();
-    }
-
-    public NurseRosteringInputConverter() {
-        super(new NurseRosteringDaoImpl());
-    }
-
-    public XmlInputBuilder createXmlInputBuilder() {
-        return new NurseRosteringInputBuilder();
-    }
-
-    public class NurseRosteringInputBuilder extends XmlInputBuilder {
-
-        protected Map<String, ShiftDate> shiftDateMap;
-        protected Map<String, Skill> skillMap;
-        protected Map<String, ShiftType> shiftTypeMap;
-        protected Map<List<String>, Shift> dateAndShiftTypeToShiftMap;
-        protected Map<List<Object>, List<Shift>> dayOfWeekAndShiftTypeToShiftListMap;
-        protected Map<String, Pattern> patternMap;
-        protected Map<String, Contract> contractMap;
-        protected Map<String, Employee> employeeMap;
-
-        public Solution readSolution() throws IOException, JDOMException {
-            // Note: javax.xml is terrible. JDom is much much easier.
-
-            Element schedulingPeriodElement = document.getRootElement();
-            assertElementName(schedulingPeriodElement, "SchedulingPeriod");
-            NurseRoster nurseRoster = new NurseRoster();
-            nurseRoster.setId(0L);
-            nurseRoster.setCode(schedulingPeriodElement.getAttribute("ID").getValue());
-
-            generateShiftDateList(nurseRoster,
-                    schedulingPeriodElement.getChild("StartDate"),
-                    schedulingPeriodElement.getChild("EndDate"));
-            readSkillList(nurseRoster, schedulingPeriodElement.getChild("Skills"));
-            readShiftTypeList(nurseRoster, schedulingPeriodElement.getChild("ShiftTypes"));
-            readPatternList(nurseRoster, schedulingPeriodElement.getChild("Patterns"));
-            readContractList(nurseRoster, schedulingPeriodElement.getChild("Contracts"));
-            readEmployeeList(nurseRoster, schedulingPeriodElement.getChild("Employees"));
-            readRequiredEmployeeSizes(nurseRoster, schedulingPeriodElement.getChild("CoverRequirements"));
-            readDayOffRequestList(nurseRoster, schedulingPeriodElement.getChild("DayOffRequests"));
-            readDayOnRequestList(nurseRoster, schedulingPeriodElement.getChild("DayOnRequests"));
-            readShiftOffRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOffRequests"));
-            readShiftOnRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOnRequests"));
-
-            logger.info("NurseRoster {} with {} skills, {} shiftTypes, {} patterns, {} contracts, {} employees," +
-                    " {} shiftDates, {} shifts and {} requests.",
-                    new Object[]{nurseRoster.getCode(),
-                        nurseRoster.getSkillList().size(),
-                        nurseRoster.getShiftTypeList().size(),
-                        nurseRoster.getPatternList().size(),
-                        nurseRoster.getContractList().size(),
-                        nurseRoster.getEmployeeList().size(),
-                        nurseRoster.getShiftDateList().size(),
-                        nurseRoster.getShiftList().size(),
-                        nurseRoster.getDayOffRequestList().size() + nurseRoster.getDayOnRequestList().size()
-                            + nurseRoster.getShiftOffRequestList().size() + nurseRoster.getShiftOnRequestList().size()
-                    });
-
-            return nurseRoster;
-        }
-
-        private void generateShiftDateList(NurseRoster nurseRoster,
-                Element startDateElement, Element endDateElement) throws JDOMException {
-            // Mimic JSR-310 LocalDate
-            TimeZone LOCAL_TIMEZONE = TimeZone.getTimeZone("GMT");
-            Calendar calendar = Calendar.getInstance();
-            calendar.setTimeZone(LOCAL_TIMEZONE);
-            calendar.clear();
-            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
-            dateFormat.setCalendar(calendar);
-            Date startDate;
-            try {
-                startDate = dateFormat.parse(startDateElement.getText());
-            } catch (ParseException e) {
-                throw new IllegalArgumentException("Invalid startDate (" + startDateElement.getText() + ").", e);
-            }
-            calendar.setTime(startDate);
-            int startDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
-            int startYear = calendar.get(Calendar.YEAR);
-            Date endDate;
-            try {
-                endDate = dateFormat.parse(endDateElement.getText());
-            } catch (ParseException e) {
-                throw new IllegalArgumentException("Invalid endDate (" + endDateElement.getText() + ").", e);
-            }
-            calendar.setTime(endDate);
-            int endDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
-            int endYear = calendar.get(Calendar.YEAR);
-            int maxDayIndex = endDayOfYear - startDayOfYear;
-            if (startYear > endYear) {
-                throw new IllegalStateException("The startYear (" + startYear
-                        + " must be before endYear (" + endYear + ").");
-            } if (startYear < endYear) {
-                int tmpYear = startYear;
-                calendar.setTime(startDate);
-                while (tmpYear < endYear) {
-                    maxDayIndex += calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
-                    calendar.add(Calendar.YEAR, 1);
-                    tmpYear++;
-                }
-            }
-            int shiftDateSize = maxDayIndex + 1;
-            List<ShiftDate> shiftDateList = new ArrayList<ShiftDate>(shiftDateSize);
-            shiftDateMap = new HashMap<String, ShiftDate>(shiftDateSize);
-            long id = 0L;
-            int dayIndex = 0;
-            calendar.setTime(startDate);
-            for (int i = 0; i < shiftDateSize; i++) {
-                ShiftDate shiftDate = new ShiftDate();
-                shiftDate.setId(id);
-                shiftDate.setDayIndex(dayIndex);
-                String dateString = dateFormat.format(calendar.getTime());
-                shiftDate.setDateString(dateString);
-                shiftDate.setDayOfWeek(DayOfWeek.valueOfCalendar(calendar.get(Calendar.DAY_OF_WEEK)));
-                shiftDate.setShiftList(new ArrayList<Shift>());
-                shiftDateList.add(shiftDate);
-                shiftDateMap.put(dateString, shiftDate);
-                id++;
-                dayIndex++;
-                calendar.add(Calendar.DAY_OF_YEAR, 1);
-            }
-            nurseRoster.setShiftDateList(shiftDateList);
-        }
-
-        private void readSkillList(NurseRoster nurseRoster, Element skillsElement) throws JDOMException {
-            List<Skill> skillList;
-            if (skillsElement == null) {
-                skillList = Collections.emptyList();
-            } else {
-                List<Element> skillElementList = (List<Element>) skillsElement.getChildren();
-                skillList = new ArrayList<Skill>(skillElementList.size());
-                skillMap = new HashMap<String, Skill>(skillElementList.size());
-                long id = 0L;
-                for (Element element : skillElementList) {
-                    assertElementName(element, "Skill");
-                    Skill skill = new Skill();
-                    skill.setId(id);
-                    skill.setCode(element.getText());
-                    skillList.add(skill);
-                    skillMap.put(skill.getCode(), skill);
-                    id++;
-                }
-            }
-            nurseRoster.setSkillList(skillList);
-        }
-
-        private void readShiftTypeList(NurseRoster nurseRoster, Element shiftTypesElement) throws JDOMException {
-            List<Element> shiftElementList = (List<Element>) shiftTypesElement.getChildren();
-            List<ShiftType> shiftTypeList = new ArrayList<ShiftType>(shiftElementList.size());
-            shiftTypeMap = new HashMap<String, ShiftType>(shiftElementList.size());
-            long id = 0L;
-            List<ShiftTypeSkillRequirement> shiftTypeSkillRequirementList
-                    = new ArrayList<ShiftTypeSkillRequirement>(shiftElementList.size() * 2);
-            long shiftTypeSkillRequirementId = 0L;
-            int shiftListSize = shiftDateMap.size() * shiftElementList.size();
-            List<Shift> shiftList = new ArrayList<Shift>(shiftListSize);
-            dateAndShiftTypeToShiftMap = new HashMap<List<String>, Shift>(shiftListSize);
-            dayOfWeekAndShiftTypeToShiftListMap = new HashMap<List<Object>, List<Shift>>(7 * shiftElementList.size());
-            long shiftId = 0L;
-            for (Element element : shiftElementList) {
-                assertElementName(element, "Shift");
-                ShiftType shiftType = new ShiftType();
-                shiftType.setId(id);
-                shiftType.setCode(element.getAttribute("ID").getValue());
-                shiftType.setStartTimeString(element.getChild("StartTime").getText());
-                shiftType.setEndTimeString(element.getChild("EndTime").getText());
-                shiftType.setDescription(element.getChild("Description").getText());
-
-                Element skillsElement = element.getChild("Skills");
-                if (skillsElement != null) {
-                    List<Element> skillElementList = (List<Element>) skillsElement.getChildren();
-                    for (Element skillElement : skillElementList) {
-                        assertElementName(skillElement, "Skill");
-                        ShiftTypeSkillRequirement shiftTypeSkillRequirement = new ShiftTypeSkillRequirement();
-                        shiftTypeSkillRequirement.setId(shiftTypeSkillRequirementId);
-                        shiftTypeSkillRequirement.setShiftType(shiftType);
-                        Skill skill = skillMap.get(skillElement.getText());
-                        if (skill == null) {
-                            throw new IllegalArgumentException("The skill (" + skillElement.getText()
-                                    + ") of shiftType (" + shiftType.getCode() + ") does not exist.");
-                        }
-                        shiftTypeSkillRequirement.setSkill(skill);
-                        shiftTypeSkillRequirementList.add(shiftTypeSkillRequirement);
-                        shiftTypeSkillRequirementId++;
-                    }
-                }
-
-                for (Map.Entry<String, ShiftDate> shiftDateEntry : shiftDateMap.entrySet()) {
-                    Shift shift = new Shift();
-                    shift.setId(shiftId);
-                    ShiftDate shiftDate = shiftDateEntry.getValue();
-                    shift.setShiftDate(shiftDate);
-                    shiftDate.getShiftList().add(shift);
-                    shift.setShiftType(shiftType);
-                    shift.setRequiredEmployeeSize(0); // Filled in later
-                    shiftList.add(shift);
-                    dateAndShiftTypeToShiftMap.put(Arrays.asList(shiftDateEntry.getKey(), shiftType.getCode()), shift);
-                    addShiftToDayOfWeekAndShiftTypeToShiftListMap(shiftDate, shiftType, shift);
-                    shiftId++;
-                }
-
-                shiftTypeList.add(shiftType);
-                shiftTypeMap.put(shiftType.getCode(), shiftType);
-                id++;
-            }
-            nurseRoster.setShiftTypeList(shiftTypeList);
-            nurseRoster.setShiftTypeSkillRequirementList(shiftTypeSkillRequirementList);
-            nurseRoster.setShiftList(shiftList);
-        }
-
-        private void addShiftToDayOfWeekAndShiftTypeToShiftListMap(ShiftDate shiftDate, ShiftType shiftType,
-                Shift shift) {
-            List<Object> key = Arrays.<Object>asList(shiftDate.getDayOfWeek(), shiftType);
-            List<Shift> dayOfWeekAndShiftTypeToShiftList = dayOfWeekAndShiftTypeToShiftListMap.get(key);
-            if (dayOfWeekAndShiftTypeToShiftList == null) {
-                dayOfWeekAndShiftTypeToShiftList = new ArrayList<Shift>((shiftDateMap.size() + 6) / 7);
-                dayOfWeekAndShiftTypeToShiftListMap.put(key, dayOfWeekAndShiftTypeToShiftList);
-            }
-            dayOfWeekAndShiftTypeToShiftList.add(shift);
-        }
-
-        private void readPatternList(NurseRoster nurseRoster, Element patternsElement) throws JDOMException {
-            List<Pattern> patternList;
-            if (patternsElement == null) {
-                patternList = Collections.emptyList();
-            } else {
-                List<Element> patternElementList = (List<Element>) patternsElement.getChildren();
-                patternList = new ArrayList<Pattern>(patternElementList.size());
-                patternMap = new HashMap<String, Pattern>(patternElementList.size());
-                long id = 0L;
-                for (Element element : patternElementList) {
-                    assertElementName(element, "Pattern");
-                    Pattern pattern = new Pattern();
-                    pattern.setId(id);
-                    pattern.setCode(element.getAttribute("ID").getValue());
-                    pattern.setWeight(element.getAttribute("weight").getIntValue());
-
-                    List<Element> patternEntryElementList = (List<Element>) element.getChild("PatternEntries")
-                            .getChildren();
-                    for (Element patternEntryElement : patternEntryElementList) {
-                        assertElementName(patternEntryElement, "PatternEntry");
-                        Element shiftTypeElement = patternEntryElement.getChild("ShiftType");
-                        ShiftType shiftType = shiftTypeMap.get(shiftTypeElement.getText());
-                        if (shiftType == null) {
-                            if (shiftTypeElement.getText().equals("Any")) {
-                                // TODO
-
-
-                            } else if (shiftTypeElement.getText().equals("None")) {
-                                // TODO
-
-
-                            } else {
-                                throw new IllegalArgumentException("The shiftType (" + shiftTypeElement.getText()
-                                        + ") of pattern (" + pattern.getCode() + ") does not exist.");
-                            }
-                        }
-                        // TODO shiftType & day etc
-
-    //        <PatternEntry index="0">
-    //          <ShiftType>None</ShiftType>
-    //          <Day>Friday</Day>
-    //        </PatternEntry>
-    //        <PatternEntry index="1">
-    //          <ShiftType>Any</ShiftType>
-    //          <Day>Saturday</Day>
-    //        </PatternEntry>
-    //        <PatternEntry index="2">
-    //          <ShiftType>Any</ShiftType>
-    //          <Day>Sunday</Day>
-    //        </PatternEntry>
-
-                    }
-
-                    patternList.add(pattern);
-                    patternMap.put(pattern.getCode(), pattern);
-                    id++;
-                }
-            }
-            nurseRoster.setPatternList(patternList);
-        }
-
-        private void readContractList(NurseRoster nurseRoster, Element contractsElement) throws JDOMException {
-            List<Element> contractElementList = (List<Element>) contractsElement.getChildren();
-            List<Contract> contractList = new ArrayList<Contract>(contractElementList.size());
-            contractMap = new HashMap<String, Contract>(contractElementList.size());
-            long id = 0L;
-            for (Element element : contractElementList) {
-                assertElementName(element, "Contract");
-                Contract contract = new Contract();
-                contract.setId(id);
-                contract.setCode(element.getAttribute("ID").getValue());
-                contract.setDescription(element.getChild("Description").getText());
-                // TODO the rest of the contract
-//      <SingleAssignmentPerDay weight="1">true</SingleAssignmentPerDay>
-//      <MaxNumAssignments on="1" weight="1">16</MaxNumAssignments>
-//      <MinNumAssignments on="1" weight="1">6</MinNumAssignments>
-//      <MaxConsecutiveWorkingDays on="1" weight="1">7</MaxConsecutiveWorkingDays>
-//      <MinConsecutiveWorkingDays on="1" weight="1">1</MinConsecutiveWorkingDays>
-//      <MaxConsecutiveFreeDays on="1" weight="1">5</MaxConsecutiveFreeDays>
-//      <MinConsecutiveFreeDays on="1" weight="1">1</MinConsecutiveFreeDays>
-//      <MaxConsecutiveWorkingWeekends on="0" weight="0">7</MaxConsecutiveWorkingWeekends>
-//      <MinConsecutiveWorkingWeekends on="0" weight="0">1</MinConsecutiveWorkingWeekends>
-//      <MaxWorkingWeekendsInFourWeeks on="0" weight="0">0</MaxWorkingWeekendsInFourWeeks>
-//      <WeekendDefinition>SaturdaySunday</WeekendDefinition>
-//      <CompleteWeekends weight="1">true</CompleteWeekends>
-//      <IdenticalShiftTypesDuringWeekend weight="1">true</IdenticalShiftTypesDuringWeekend>
-//      <NoNightShiftBeforeFreeWeekend weight="0">false</NoNightShiftBeforeFreeWeekend>
-//      <AlternativeSkillCategory weight="0">false</AlternativeSkillCategory>
-
-
-                List<Element> unwantedPatternElementList = (List<Element>) element.getChild("UnwantedPatterns")
-                        .getChildren();
-                for (Element patternElement : unwantedPatternElementList) {
-                    assertElementName(patternElement, "Pattern");
-                    Pattern pattern = patternMap.get(patternElement.getText());
-                    if (pattern == null) {
-                        throw new IllegalArgumentException("The pattern (" + patternElement.getText()
-                                + ") of contract (" + contract.getCode() + ") does not exist.");
-                    }
-                    // TODO unwanted pattern
-//      <UnwantedPatterns>
-//        <Pattern>0</Pattern>
-//        <Pattern>1</Pattern>
-//        <Pattern>2</Pattern>
-//      </UnwantedPatterns>
-
-
-                }
-
-                contractList.add(contract);
-                contractMap.put(contract.getCode(), contract);
-                id++;
-            }
-            nurseRoster.setContractList(contractList);
-        }
-
-        private void readEmployeeList(NurseRoster nurseRoster, Element employeesElement) throws JDOMException {
-            List<Element> employeeElementList = (List<Element>) employeesElement.getChildren();
-            List<Employee> employeeList = new ArrayList<Employee>(employeeElementList.size());
-            employeeMap = new HashMap<String, Employee>(employeeElementList.size());
-            long id = 0L;
-            List<SkillProficiency> skillProficiencyList
-                    = new ArrayList<SkillProficiency>(employeeElementList.size() * 2);
-            long skillProficiencyId = 0L;
-            for (Element element : employeeElementList) {
-                assertElementName(element, "Employee");
-                Employee employee = new Employee();
-                employee.setId(id);
-                employee.setCode(element.getAttribute("ID").getValue());
-                employee.setName(element.getChild("Name").getText());
-                Element contractElement = element.getChild("ContractID");
-                Contract contract = contractMap.get(contractElement.getText());
-                if (contract == null) {
-                    throw new IllegalArgumentException("The contract (" + contractElement.getText()
-                            + ") of employee (" + employee.getCode() + ") does not exist.");
-                }
-                employee.setContract(contract);
-
-                Element skillsElement = element.getChild("Skills");
-                if (skillsElement != null) {
-                    List<Element> skillElementList = (List<Element>) skillsElement.getChildren();
-                    for (Element skillElement : skillElementList) {
-                        assertElementName(skillElement, "Skill");
-                        Skill skill = skillMap.get(skillElement.getText());
-                        if (skill == null) {
-                            throw new IllegalArgumentException("The skill (" + skillElement.getText()
-                                    + ") of employee (" + employee.getCode() + ") does not exist.");
-                        }
-                        SkillProficiency skillProficiency = new SkillProficiency();
-                        skillProficiency.setId(skillProficiencyId);
-                        skillProficiency.setEmployee(employee);
-                        skillProficiency.setSkill(skill);
-                        skillProficiencyList.add(skillProficiency);
-                        skillProficiencyId++;
-                    }
-                }
-
-                employeeList.add(employee);
-                employeeMap.put(employee.getCode(), employee);
-                id++;
-            }
-            nurseRoster.setEmployeeList(employeeList);
-            nurseRoster.setSkillProficiencyList(skillProficiencyList);
-        }
-
-        private void readRequiredEmployeeSizes(NurseRoster nurseRoster, Element coverRequirementsElement) {
-            List<Element> coverRequirementElementList = (List<Element>) coverRequirementsElement.getChildren();
-            for (Element element : coverRequirementElementList) {
-                if (element.getName().equals("DayOfWeekCover")) {
-                    Element dayOfWeekElement = element.getChild("Day");
-                    DayOfWeek dayOfWeek = DayOfWeek.valueOfCode(dayOfWeekElement.getText());
-                    if (dayOfWeek == null) {
-                        throw new IllegalArgumentException("The dayOfWeek (" + dayOfWeekElement.getText()
-                                + ") of an entity DayOfWeekCover does not exist.");
-                    }
-
-                    List<Element> coverElementList = (List<Element>) element.getChildren("Cover");
-                    for (Element coverElement : coverElementList) {
-                        Element shiftTypeElement = coverElement.getChild("Shift");
-                        ShiftType shiftType = shiftTypeMap.get(shiftTypeElement.getText());
-                        if (shiftType == null) {
-                            if (shiftTypeElement.getText().equals("Any")) {
-                                throw new IllegalStateException("The shiftType Any is not supported on DayOfWeekCover.");
-                            } else if (shiftTypeElement.getText().equals("None")) {
-                                throw new IllegalStateException("The shiftType None is not supported on DayOfWeekCover.");
-                            } else {
-                                throw new IllegalArgumentException("The shiftType (" + shiftTypeElement.getText()
-                                        + ") of an entity DayOfWeekCover does not exist.");
-                            }
-                        }
-                        List<Object> key = Arrays.<Object>asList(dayOfWeek, shiftType);
-                        List<Shift> shiftList = dayOfWeekAndShiftTypeToShiftListMap.get(key);
-                        if (shiftList == null) {
-                            throw new IllegalArgumentException("The dayOfWeek (" + dayOfWeekElement.getText()
-                                    + ") with the shiftType (" + shiftTypeElement.getText()
-                                    + ") of an entity DayOfWeekCover does not have any shifts.");
-                        }
-                        int requiredEmployeeSize = Integer.parseInt(coverElement.getChild("Preferred").getText());
-                        for (Shift shift : shiftList) {
-                            shift.setRequiredEmployeeSize(shift.getRequiredEmployeeSize() + requiredEmployeeSize);
-                        }
-                    }
-                } else if (element.getName().equals("DateSpecificCover")) {
-                    Element dateElement = element.getChild("Date");
-                    List<Element> coverElementList = (List<Element>) element.getChildren("Cover");
-                    for (Element coverElement : coverElementList) {
-                        Element shiftTypeElement = coverElement.getChild("Shift");
-                        Shift shift = dateAndShiftTypeToShiftMap.get(Arrays.asList(dateElement.getText(), shiftTypeElement.getText()));
-                        if (shift == null) {
-                            throw new IllegalArgumentException("The date (" + dateElement.getText()
-                                    + ") with the shiftType (" + shiftTypeElement.getText()
-                                    + ") of an entity DateSpecificCover does not have a shift.");
-                        }
-                        int requiredEmployeeSize = Integer.parseInt(coverElement.getChild("Preferred").getText());
-                        shift.setRequiredEmployeeSize(shift.getRequiredEmployeeSize() + requiredEmployeeSize);
-                    }
-                } else {
-                    throw new IllegalArgumentException("Unknown cover entity (" + element.getName() + ").");
-                }
-            }
-        }
-
-        private void readDayOffRequestList(NurseRoster nurseRoster, Element dayOffRequestsElement) throws JDOMException {
-            List<DayOffRequest> dayOffRequestList;
-            if (dayOffRequestsElement == null) {
-                dayOffRequestList = Collections.emptyList();
-            } else {
-                List<Element> dayOffElementList = (List<Element>) dayOffRequestsElement.getChildren();
-                dayOffRequestList = new ArrayList<DayOffRequest>(dayOffElementList.size());
-                long id = 0L;
-                for (Element element : dayOffElementList) {
-                    assertElementName(element, "DayOff");
-                    DayOffRequest dayOffRequest = new DayOffRequest();
-                    dayOffRequest.setId(id);
-
-                    Element employeeElement = element.getChild("EmployeeID");
-                    Employee employee = employeeMap.get(employeeElement.getText());
-                    if (employee == null) {
-                        throw new IllegalArgumentException("The shiftDate (" + employeeElement.getText()
-                                + ") of dayOffRequest (" + dayOffRequest + ") does not exist.");
-                    }
-                    dayOffRequest.setEmployee(employee);
-
-                    Element dateElement = element.getChild("Date");
-                    ShiftDate shiftDate = shiftDateMap.get(dateElement.getText());
-                    if (shiftDate == null) {
-                        throw new IllegalArgumentException("The date (" + dateElement.getText()
-                                + ") of dayOffRequest (" + dayOffRequest + ") does not exist.");
-                    }
-                    dayOffRequest.setShiftDate(shiftDate);
-
-                    dayOffRequest.setWeight(element.getAttribute("weight").getIntValue());
-
-                    dayOffRequestList.add(dayOffRequest);
-                    id++;
-                }
-            }
-            nurseRoster.setDayOffRequestList(dayOffRequestList);
-        }
-
-        private void readDayOnRequestList(NurseRoster nurseRoster, Element dayOnRequestsElement) throws JDOMException {
-            List<DayOnRequest> dayOnRequestList;
-            if (dayOnRequestsElement == null) {
-                dayOnRequestList = Collections.emptyList();
-            } else {
-                List<Element> dayOnElementList = (List<Element>) dayOnRequestsElement.getChildren();
-                dayOnRequestList = new ArrayList<DayOnRequest>(dayOnElementList.size());
-                long id = 0L;
-                for (Element element : dayOnElementList) {
-                    assertElementName(element, "DayOn");
-                    DayOnRequest dayOnRequest = new DayOnRequest();
-                    dayOnRequest.setId(id);
-
-                    Element employeeElement = element.getChild("EmployeeID");
-                    Employee employee = employeeMap.get(employeeElement.getText());
-                    if (employee == null) {
-                        throw new IllegalArgumentException("The shiftDate (" + employeeElement.getText()
-                                + ") of dayOnRequest (" + dayOnRequest + ") does not exist.");
-                    }
-                    dayOnRequest.setEmployee(employee);
-
-                    Element dateElement = element.getChild("Date");
-                    ShiftDate shiftDate = shiftDateMap.get(dateElement.getText());
-                    if (shiftDate == null) {
-                        throw new IllegalArgumentException("The date (" + dateElement.getText()
-                                + ") of dayOnRequest (" + dayOnRequest + ") does not exist.");
-                    }
-                    dayOnRequest.setShiftDate(shiftDate);
-
-                    dayOnRequest.setWeight(element.getAttribute("weight").getIntValue());
-
-                    dayOnRequestList.add(dayOnRequest);
-                    id++;
-                }
-            }
-            nurseRoster.setDayOnRequestList(dayOnRequestList);
-        }
-
-        private void readShiftOffRequestList(NurseRoster nurseRoster, Element shiftOffRequestsElement) throws JDOMException {
-            List<ShiftOffRequest> shiftOffRequestList;
-            if (shiftOffRequestsElement == null) {
-                shiftOffRequestList = Collections.emptyList();
-            } else {
-                List<Element> shiftOffElementList = (List<Element>) shiftOffRequestsElement.getChildren();
-                shiftOffRequestList = new ArrayList<ShiftOffRequest>(shiftOffElementList.size());
-                long id = 0L;
-                for (Element element : shiftOffElementList) {
-                    assertElementName(element, "ShiftOff");
-                    ShiftOffRequest shiftOffRequest = new ShiftOffRequest();
-                    shiftOffRequest.setId(id);
-
-                    Element employeeElement = element.getChild("EmployeeID");
-                    Employee employee = employeeMap.get(employeeElement.getText());
-                    if (employee == null) {
-                        throw new IllegalArgumentException("The shift (" + employeeElement.getText()
-                                + ") of shiftOffRequest (" + shiftOffRequest + ") does not exist.");
-                    }
-                    shiftOffRequest.setEmployee(employee);
-
-                    Element dateElement = element.getChild("Date");
-                    Element shiftTypeElement = element.getChild("ShiftTypeID");
-                    Shift shift = dateAndShiftTypeToShiftMap.get(Arrays.asList(dateElement.getText(), shiftTypeElement.getText()));
-                    if (shift == null) {
-                        throw new IllegalArgumentException("The date (" + dateElement.getText()
-                                + ") or the shiftType (" + shiftTypeElement.getText()
-                                + ") of shiftOffRequest (" + shiftOffRequest + ") does not exist.");
-                    }
-                    shiftOffRequest.setShift(shift);
-
-                    shiftOffRequest.setWeight(element.getAttribute("weight").getIntValue());
-
-                    shiftOffRequestList.add(shiftOffRequest);
-                    id++;
-                }
-            }
-            nurseRoster.setShiftOffRequestList(shiftOffRequestList);
-        }
-
-        private void readShiftOnRequestList(NurseRoster nurseRoster, Element shiftOnRequestsElement) throws JDOMException {
-            List<ShiftOnRequest> shiftOnRequestList;
-            if (shiftOnRequestsElement == null) {
-                shiftOnRequestList = Collections.emptyList();
-            } else {
-                List<Element> shiftOnElementList = (List<Element>) shiftOnRequestsElement.getChildren();
-                shiftOnRequestList = new ArrayList<ShiftOnRequest>(shiftOnElementList.size());
-                long id = 0L;
-                for (Element element : shiftOnElementList) {
-                    assertElementName(element, "ShiftOn");
-                    ShiftOnRequest shiftOnRequest = new ShiftOnRequest();
-                    shiftOnRequest.setId(id);
-
-                    Element employeeElement = element.getChild("EmployeeID");
-                    Employee employee = employeeMap.get(employeeElement.getText());
-                    if (employee == null) {
-                        throw new IllegalArgumentException("The shift (" + employeeElement.getText()
-                                + ") of shiftOnRequest (" + shiftOnRequest + ") does not exist.");
-                    }
-                    shiftOnRequest.setEmployee(employee);
-
-                    Element dateElement = element.getChild("Date");
-                    Element shiftTypeElement = element.getChild("ShiftTypeID");
-                    Shift shift = dateAndShiftTypeToShiftMap.get(Arrays.asList(dateElement.getText(), shiftTypeElement.getText()));
-                    if (shift == null) {
-                        throw new IllegalArgumentException("The date (" + dateElement.getText()
-                                + ") or the shiftType (" + shiftTypeElement.getText()
-                                + ") of shiftOnRequest (" + shiftOnRequest + ") does not exist.");
-                    }
-                    shiftOnRequest.setShift(shift);
-
-                    shiftOnRequest.setWeight(element.getAttribute("weight").getIntValue());
-
-                    shiftOnRequestList.add(shiftOnRequest);
-                    id++;
-                }
-            }
-            nurseRoster.setShiftOnRequestList(shiftOnRequestList);
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,76 +0,0 @@
-package org.drools.planner.examples.nurserostering.persistence;
-
-import java.io.IOException;
-
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.persistence.AbstractTxtOutputConverter;
-import org.drools.planner.examples.common.persistence.AbstractXmlOutputConverter;
-import org.drools.planner.examples.nurserostering.domain.EmployeeAssignment;
-import org.drools.planner.examples.nurserostering.domain.NurseRoster;
-import org.drools.planner.examples.nurserostering.domain.Shift;
-import org.jdom.Element;
-
-/**
- * @author Geoffrey De Smet
- */
-public class NurseRosteringOutputConverter extends AbstractXmlOutputConverter {
-
-    public static void main(String[] args) {
-        new NurseRosteringOutputConverter().convertAll();
-    }
-
-    public NurseRosteringOutputConverter() {
-        super(new NurseRosteringDaoImpl());
-    }
-
-    public XmlOutputBuilder createXmlOutputBuilder() {
-        return new NurseRosteringOutputBuilder();
-    }
-
-    public class NurseRosteringOutputBuilder extends XmlOutputBuilder {
-
-        private NurseRoster nurseRoster;
-
-        public void setSolution(Solution solution) {
-            nurseRoster = (NurseRoster) solution;
-        }
-
-        public void writeSolution() throws IOException {
-            Element solutionElement = new Element("Solution");
-            document.setRootElement(solutionElement);
-
-            Element schedulingPeriodIDElement = new Element("SchedulingPeriodID");
-            schedulingPeriodIDElement.setText(nurseRoster.getCode());
-            solutionElement.addContent(schedulingPeriodIDElement);
-
-            Element competitorElement = new Element("Competitor");
-            competitorElement.setText("Geoffrey De Smet with Drools Planner");
-            solutionElement.addContent(competitorElement);
-
-            Element softConstraintsPenaltyElement = new Element("SoftConstraintsPenalty");
-            softConstraintsPenaltyElement.setText(Integer.toString(nurseRoster.getScore().getSoftScore()));
-            solutionElement.addContent(softConstraintsPenaltyElement);
-
-            for (EmployeeAssignment employeeAssignment : nurseRoster.getEmployeeAssignmentList()) {
-                Shift shift = employeeAssignment.getShift();
-                if (shift != null) {
-                    Element assignmentElement = new Element("Assignment");
-                    solutionElement.addContent(assignmentElement);
-
-                    Element dateElement = new Element("Date");
-                    dateElement.setText(shift.getShiftDate().getDateString());
-                    assignmentElement.addContent(dateElement);
-
-                    Element employeeElement = new Element("Employee");
-                    employeeElement.setText(employeeAssignment.getEmployee().getCode());
-                    assignmentElement.addContent(employeeElement);
-
-                    Element shiftTypeElement = new Element("ShiftType");
-                    shiftTypeElement.setText(shift.getShiftType().getCode());
-                    assignmentElement.addContent(shiftTypeElement);
-                }
-            }
-        }
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionExporter.java (from rev 32330, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,75 @@
+package org.drools.planner.examples.nurserostering.persistence;
+
+import java.io.IOException;
+
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.persistence.AbstractXmlSolutionExporter;
+import org.drools.planner.examples.nurserostering.domain.EmployeeAssignment;
+import org.drools.planner.examples.nurserostering.domain.NurseRoster;
+import org.drools.planner.examples.nurserostering.domain.Shift;
+import org.jdom.Element;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class NurseRosteringSolutionExporter extends AbstractXmlSolutionExporter {
+
+    public static void main(String[] args) {
+        new NurseRosteringSolutionExporter().convertAll();
+    }
+
+    public NurseRosteringSolutionExporter() {
+        super(new NurseRosteringDaoImpl());
+    }
+
+    public XmlOutputBuilder createXmlOutputBuilder() {
+        return new NurseRosteringOutputBuilder();
+    }
+
+    public class NurseRosteringOutputBuilder extends XmlOutputBuilder {
+
+        private NurseRoster nurseRoster;
+
+        public void setSolution(Solution solution) {
+            nurseRoster = (NurseRoster) solution;
+        }
+
+        public void writeSolution() throws IOException {
+            Element solutionElement = new Element("Solution");
+            document.setRootElement(solutionElement);
+
+            Element schedulingPeriodIDElement = new Element("SchedulingPeriodID");
+            schedulingPeriodIDElement.setText(nurseRoster.getCode());
+            solutionElement.addContent(schedulingPeriodIDElement);
+
+            Element competitorElement = new Element("Competitor");
+            competitorElement.setText("Geoffrey De Smet with Drools Planner");
+            solutionElement.addContent(competitorElement);
+
+            Element softConstraintsPenaltyElement = new Element("SoftConstraintsPenalty");
+            softConstraintsPenaltyElement.setText(Integer.toString(nurseRoster.getScore().getSoftScore()));
+            solutionElement.addContent(softConstraintsPenaltyElement);
+
+            for (EmployeeAssignment employeeAssignment : nurseRoster.getEmployeeAssignmentList()) {
+                Shift shift = employeeAssignment.getShift();
+                if (shift != null) {
+                    Element assignmentElement = new Element("Assignment");
+                    solutionElement.addContent(assignmentElement);
+
+                    Element dateElement = new Element("Date");
+                    dateElement.setText(shift.getShiftDate().getDateString());
+                    assignmentElement.addContent(dateElement);
+
+                    Element employeeElement = new Element("Employee");
+                    employeeElement.setText(employeeAssignment.getEmployee().getCode());
+                    assignmentElement.addContent(employeeElement);
+
+                    Element shiftTypeElement = new Element("ShiftType");
+                    shiftTypeElement.setText(shift.getShiftType().getCode());
+                    assignmentElement.addContent(shiftTypeElement);
+                }
+            }
+        }
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/nurserostering/persistence/NurseRosteringSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,645 @@
+package org.drools.planner.examples.nurserostering.persistence;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.persistence.AbstractXmlSolutionImporter;
+import org.drools.planner.examples.nurserostering.domain.Contract;
+import org.drools.planner.examples.nurserostering.domain.DayOfWeek;
+import org.drools.planner.examples.nurserostering.domain.DayOffRequest;
+import org.drools.planner.examples.nurserostering.domain.DayOnRequest;
+import org.drools.planner.examples.nurserostering.domain.Employee;
+import org.drools.planner.examples.nurserostering.domain.NurseRoster;
+import org.drools.planner.examples.nurserostering.domain.Pattern;
+import org.drools.planner.examples.nurserostering.domain.Shift;
+import org.drools.planner.examples.nurserostering.domain.ShiftDate;
+import org.drools.planner.examples.nurserostering.domain.ShiftOffRequest;
+import org.drools.planner.examples.nurserostering.domain.ShiftOnRequest;
+import org.drools.planner.examples.nurserostering.domain.ShiftType;
+import org.drools.planner.examples.nurserostering.domain.ShiftTypeSkillRequirement;
+import org.drools.planner.examples.nurserostering.domain.Skill;
+import org.drools.planner.examples.nurserostering.domain.SkillProficiency;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class NurseRosteringSolutionImporter extends AbstractXmlSolutionImporter {
+
+    public static void main(String[] args) {
+        new NurseRosteringSolutionImporter().convertAll();
+    }
+
+    public NurseRosteringSolutionImporter() {
+        super(new NurseRosteringDaoImpl());
+    }
+
+    public XmlInputBuilder createXmlInputBuilder() {
+        return new NurseRosteringInputBuilder();
+    }
+
+    public class NurseRosteringInputBuilder extends XmlInputBuilder {
+
+        protected Map<String, ShiftDate> shiftDateMap;
+        protected Map<String, Skill> skillMap;
+        protected Map<String, ShiftType> shiftTypeMap;
+        protected Map<List<String>, Shift> dateAndShiftTypeToShiftMap;
+        protected Map<List<Object>, List<Shift>> dayOfWeekAndShiftTypeToShiftListMap;
+        protected Map<String, Pattern> patternMap;
+        protected Map<String, Contract> contractMap;
+        protected Map<String, Employee> employeeMap;
+
+        public Solution readSolution() throws IOException, JDOMException {
+            // Note: javax.xml is terrible. JDom is much much easier.
+
+            Element schedulingPeriodElement = document.getRootElement();
+            assertElementName(schedulingPeriodElement, "SchedulingPeriod");
+            NurseRoster nurseRoster = new NurseRoster();
+            nurseRoster.setId(0L);
+            nurseRoster.setCode(schedulingPeriodElement.getAttribute("ID").getValue());
+
+            generateShiftDateList(nurseRoster,
+                    schedulingPeriodElement.getChild("StartDate"),
+                    schedulingPeriodElement.getChild("EndDate"));
+            readSkillList(nurseRoster, schedulingPeriodElement.getChild("Skills"));
+            readShiftTypeList(nurseRoster, schedulingPeriodElement.getChild("ShiftTypes"));
+            readPatternList(nurseRoster, schedulingPeriodElement.getChild("Patterns"));
+            readContractList(nurseRoster, schedulingPeriodElement.getChild("Contracts"));
+            readEmployeeList(nurseRoster, schedulingPeriodElement.getChild("Employees"));
+            readRequiredEmployeeSizes(nurseRoster, schedulingPeriodElement.getChild("CoverRequirements"));
+            readDayOffRequestList(nurseRoster, schedulingPeriodElement.getChild("DayOffRequests"));
+            readDayOnRequestList(nurseRoster, schedulingPeriodElement.getChild("DayOnRequests"));
+            readShiftOffRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOffRequests"));
+            readShiftOnRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOnRequests"));
+
+            logger.info("NurseRoster {} with {} skills, {} shiftTypes, {} patterns, {} contracts, {} employees," +
+                    " {} shiftDates, {} shifts and {} requests.",
+                    new Object[]{nurseRoster.getCode(),
+                        nurseRoster.getSkillList().size(),
+                        nurseRoster.getShiftTypeList().size(),
+                        nurseRoster.getPatternList().size(),
+                        nurseRoster.getContractList().size(),
+                        nurseRoster.getEmployeeList().size(),
+                        nurseRoster.getShiftDateList().size(),
+                        nurseRoster.getShiftList().size(),
+                        nurseRoster.getDayOffRequestList().size() + nurseRoster.getDayOnRequestList().size()
+                            + nurseRoster.getShiftOffRequestList().size() + nurseRoster.getShiftOnRequestList().size()
+                    });
+
+            return nurseRoster;
+        }
+
+        private void generateShiftDateList(NurseRoster nurseRoster,
+                Element startDateElement, Element endDateElement) throws JDOMException {
+            // Mimic JSR-310 LocalDate
+            TimeZone LOCAL_TIMEZONE = TimeZone.getTimeZone("GMT");
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTimeZone(LOCAL_TIMEZONE);
+            calendar.clear();
+            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+            dateFormat.setCalendar(calendar);
+            Date startDate;
+            try {
+                startDate = dateFormat.parse(startDateElement.getText());
+            } catch (ParseException e) {
+                throw new IllegalArgumentException("Invalid startDate (" + startDateElement.getText() + ").", e);
+            }
+            calendar.setTime(startDate);
+            int startDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
+            int startYear = calendar.get(Calendar.YEAR);
+            Date endDate;
+            try {
+                endDate = dateFormat.parse(endDateElement.getText());
+            } catch (ParseException e) {
+                throw new IllegalArgumentException("Invalid endDate (" + endDateElement.getText() + ").", e);
+            }
+            calendar.setTime(endDate);
+            int endDayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
+            int endYear = calendar.get(Calendar.YEAR);
+            int maxDayIndex = endDayOfYear - startDayOfYear;
+            if (startYear > endYear) {
+                throw new IllegalStateException("The startYear (" + startYear
+                        + " must be before endYear (" + endYear + ").");
+            } if (startYear < endYear) {
+                int tmpYear = startYear;
+                calendar.setTime(startDate);
+                while (tmpYear < endYear) {
+                    maxDayIndex += calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
+                    calendar.add(Calendar.YEAR, 1);
+                    tmpYear++;
+                }
+            }
+            int shiftDateSize = maxDayIndex + 1;
+            List<ShiftDate> shiftDateList = new ArrayList<ShiftDate>(shiftDateSize);
+            shiftDateMap = new HashMap<String, ShiftDate>(shiftDateSize);
+            long id = 0L;
+            int dayIndex = 0;
+            calendar.setTime(startDate);
+            for (int i = 0; i < shiftDateSize; i++) {
+                ShiftDate shiftDate = new ShiftDate();
+                shiftDate.setId(id);
+                shiftDate.setDayIndex(dayIndex);
+                String dateString = dateFormat.format(calendar.getTime());
+                shiftDate.setDateString(dateString);
+                shiftDate.setDayOfWeek(DayOfWeek.valueOfCalendar(calendar.get(Calendar.DAY_OF_WEEK)));
+                shiftDate.setShiftList(new ArrayList<Shift>());
+                shiftDateList.add(shiftDate);
+                shiftDateMap.put(dateString, shiftDate);
+                id++;
+                dayIndex++;
+                calendar.add(Calendar.DAY_OF_YEAR, 1);
+            }
+            nurseRoster.setShiftDateList(shiftDateList);
+        }
+
+        private void readSkillList(NurseRoster nurseRoster, Element skillsElement) throws JDOMException {
+            List<Skill> skillList;
+            if (skillsElement == null) {
+                skillList = Collections.emptyList();
+            } else {
+                List<Element> skillElementList = (List<Element>) skillsElement.getChildren();
+                skillList = new ArrayList<Skill>(skillElementList.size());
+                skillMap = new HashMap<String, Skill>(skillElementList.size());
+                long id = 0L;
+                for (Element element : skillElementList) {
+                    assertElementName(element, "Skill");
+                    Skill skill = new Skill();
+                    skill.setId(id);
+                    skill.setCode(element.getText());
+                    skillList.add(skill);
+                    skillMap.put(skill.getCode(), skill);
+                    id++;
+                }
+            }
+            nurseRoster.setSkillList(skillList);
+        }
+
+        private void readShiftTypeList(NurseRoster nurseRoster, Element shiftTypesElement) throws JDOMException {
+            List<Element> shiftElementList = (List<Element>) shiftTypesElement.getChildren();
+            List<ShiftType> shiftTypeList = new ArrayList<ShiftType>(shiftElementList.size());
+            shiftTypeMap = new HashMap<String, ShiftType>(shiftElementList.size());
+            long id = 0L;
+            List<ShiftTypeSkillRequirement> shiftTypeSkillRequirementList
+                    = new ArrayList<ShiftTypeSkillRequirement>(shiftElementList.size() * 2);
+            long shiftTypeSkillRequirementId = 0L;
+            int shiftListSize = shiftDateMap.size() * shiftElementList.size();
+            List<Shift> shiftList = new ArrayList<Shift>(shiftListSize);
+            dateAndShiftTypeToShiftMap = new HashMap<List<String>, Shift>(shiftListSize);
+            dayOfWeekAndShiftTypeToShiftListMap = new HashMap<List<Object>, List<Shift>>(7 * shiftElementList.size());
+            long shiftId = 0L;
+            for (Element element : shiftElementList) {
+                assertElementName(element, "Shift");
+                ShiftType shiftType = new ShiftType();
+                shiftType.setId(id);
+                shiftType.setCode(element.getAttribute("ID").getValue());
+                shiftType.setStartTimeString(element.getChild("StartTime").getText());
+                shiftType.setEndTimeString(element.getChild("EndTime").getText());
+                shiftType.setDescription(element.getChild("Description").getText());
+
+                Element skillsElement = element.getChild("Skills");
+                if (skillsElement != null) {
+                    List<Element> skillElementList = (List<Element>) skillsElement.getChildren();
+                    for (Element skillElement : skillElementList) {
+                        assertElementName(skillElement, "Skill");
+                        ShiftTypeSkillRequirement shiftTypeSkillRequirement = new ShiftTypeSkillRequirement();
+                        shiftTypeSkillRequirement.setId(shiftTypeSkillRequirementId);
+                        shiftTypeSkillRequirement.setShiftType(shiftType);
+                        Skill skill = skillMap.get(skillElement.getText());
+                        if (skill == null) {
+                            throw new IllegalArgumentException("The skill (" + skillElement.getText()
+                                    + ") of shiftType (" + shiftType.getCode() + ") does not exist.");
+                        }
+                        shiftTypeSkillRequirement.setSkill(skill);
+                        shiftTypeSkillRequirementList.add(shiftTypeSkillRequirement);
+                        shiftTypeSkillRequirementId++;
+                    }
+                }
+
+                for (Map.Entry<String, ShiftDate> shiftDateEntry : shiftDateMap.entrySet()) {
+                    Shift shift = new Shift();
+                    shift.setId(shiftId);
+                    ShiftDate shiftDate = shiftDateEntry.getValue();
+                    shift.setShiftDate(shiftDate);
+                    shiftDate.getShiftList().add(shift);
+                    shift.setShiftType(shiftType);
+                    shift.setRequiredEmployeeSize(0); // Filled in later
+                    shiftList.add(shift);
+                    dateAndShiftTypeToShiftMap.put(Arrays.asList(shiftDateEntry.getKey(), shiftType.getCode()), shift);
+                    addShiftToDayOfWeekAndShiftTypeToShiftListMap(shiftDate, shiftType, shift);
+                    shiftId++;
+                }
+
+                shiftTypeList.add(shiftType);
+                shiftTypeMap.put(shiftType.getCode(), shiftType);
+                id++;
+            }
+            nurseRoster.setShiftTypeList(shiftTypeList);
+            nurseRoster.setShiftTypeSkillRequirementList(shiftTypeSkillRequirementList);
+            nurseRoster.setShiftList(shiftList);
+        }
+
+        private void addShiftToDayOfWeekAndShiftTypeToShiftListMap(ShiftDate shiftDate, ShiftType shiftType,
+                Shift shift) {
+            List<Object> key = Arrays.<Object>asList(shiftDate.getDayOfWeek(), shiftType);
+            List<Shift> dayOfWeekAndShiftTypeToShiftList = dayOfWeekAndShiftTypeToShiftListMap.get(key);
+            if (dayOfWeekAndShiftTypeToShiftList == null) {
+                dayOfWeekAndShiftTypeToShiftList = new ArrayList<Shift>((shiftDateMap.size() + 6) / 7);
+                dayOfWeekAndShiftTypeToShiftListMap.put(key, dayOfWeekAndShiftTypeToShiftList);
+            }
+            dayOfWeekAndShiftTypeToShiftList.add(shift);
+        }
+
+        private void readPatternList(NurseRoster nurseRoster, Element patternsElement) throws JDOMException {
+            List<Pattern> patternList;
+            if (patternsElement == null) {
+                patternList = Collections.emptyList();
+            } else {
+                List<Element> patternElementList = (List<Element>) patternsElement.getChildren();
+                patternList = new ArrayList<Pattern>(patternElementList.size());
+                patternMap = new HashMap<String, Pattern>(patternElementList.size());
+                long id = 0L;
+                for (Element element : patternElementList) {
+                    assertElementName(element, "Pattern");
+                    Pattern pattern = new Pattern();
+                    pattern.setId(id);
+                    pattern.setCode(element.getAttribute("ID").getValue());
+                    pattern.setWeight(element.getAttribute("weight").getIntValue());
+
+                    List<Element> patternEntryElementList = (List<Element>) element.getChild("PatternEntries")
+                            .getChildren();
+                    for (Element patternEntryElement : patternEntryElementList) {
+                        assertElementName(patternEntryElement, "PatternEntry");
+                        Element shiftTypeElement = patternEntryElement.getChild("ShiftType");
+                        ShiftType shiftType = shiftTypeMap.get(shiftTypeElement.getText());
+                        if (shiftType == null) {
+                            if (shiftTypeElement.getText().equals("Any")) {
+                                // TODO
+
+
+                            } else if (shiftTypeElement.getText().equals("None")) {
+                                // TODO
+
+
+                            } else {
+                                throw new IllegalArgumentException("The shiftType (" + shiftTypeElement.getText()
+                                        + ") of pattern (" + pattern.getCode() + ") does not exist.");
+                            }
+                        }
+                        // TODO shiftType & day etc
+
+    //        <PatternEntry index="0">
+    //          <ShiftType>None</ShiftType>
+    //          <Day>Friday</Day>
+    //        </PatternEntry>
+    //        <PatternEntry index="1">
+    //          <ShiftType>Any</ShiftType>
+    //          <Day>Saturday</Day>
+    //        </PatternEntry>
+    //        <PatternEntry index="2">
+    //          <ShiftType>Any</ShiftType>
+    //          <Day>Sunday</Day>
+    //        </PatternEntry>
+
+                    }
+
+                    patternList.add(pattern);
+                    patternMap.put(pattern.getCode(), pattern);
+                    id++;
+                }
+            }
+            nurseRoster.setPatternList(patternList);
+        }
+
+        private void readContractList(NurseRoster nurseRoster, Element contractsElement) throws JDOMException {
+            List<Element> contractElementList = (List<Element>) contractsElement.getChildren();
+            List<Contract> contractList = new ArrayList<Contract>(contractElementList.size());
+            contractMap = new HashMap<String, Contract>(contractElementList.size());
+            long id = 0L;
+            for (Element element : contractElementList) {
+                assertElementName(element, "Contract");
+                Contract contract = new Contract();
+                contract.setId(id);
+                contract.setCode(element.getAttribute("ID").getValue());
+                contract.setDescription(element.getChild("Description").getText());
+                // TODO the rest of the contract
+//      <SingleAssignmentPerDay weight="1">true</SingleAssignmentPerDay>
+//      <MaxNumAssignments on="1" weight="1">16</MaxNumAssignments>
+//      <MinNumAssignments on="1" weight="1">6</MinNumAssignments>
+//      <MaxConsecutiveWorkingDays on="1" weight="1">7</MaxConsecutiveWorkingDays>
+//      <MinConsecutiveWorkingDays on="1" weight="1">1</MinConsecutiveWorkingDays>
+//      <MaxConsecutiveFreeDays on="1" weight="1">5</MaxConsecutiveFreeDays>
+//      <MinConsecutiveFreeDays on="1" weight="1">1</MinConsecutiveFreeDays>
+//      <MaxConsecutiveWorkingWeekends on="0" weight="0">7</MaxConsecutiveWorkingWeekends>
+//      <MinConsecutiveWorkingWeekends on="0" weight="0">1</MinConsecutiveWorkingWeekends>
+//      <MaxWorkingWeekendsInFourWeeks on="0" weight="0">0</MaxWorkingWeekendsInFourWeeks>
+//      <WeekendDefinition>SaturdaySunday</WeekendDefinition>
+//      <CompleteWeekends weight="1">true</CompleteWeekends>
+//      <IdenticalShiftTypesDuringWeekend weight="1">true</IdenticalShiftTypesDuringWeekend>
+//      <NoNightShiftBeforeFreeWeekend weight="0">false</NoNightShiftBeforeFreeWeekend>
+//      <AlternativeSkillCategory weight="0">false</AlternativeSkillCategory>
+
+
+                List<Element> unwantedPatternElementList = (List<Element>) element.getChild("UnwantedPatterns")
+                        .getChildren();
+                for (Element patternElement : unwantedPatternElementList) {
+                    assertElementName(patternElement, "Pattern");
+                    Pattern pattern = patternMap.get(patternElement.getText());
+                    if (pattern == null) {
+                        throw new IllegalArgumentException("The pattern (" + patternElement.getText()
+                                + ") of contract (" + contract.getCode() + ") does not exist.");
+                    }
+                    // TODO unwanted pattern
+//      <UnwantedPatterns>
+//        <Pattern>0</Pattern>
+//        <Pattern>1</Pattern>
+//        <Pattern>2</Pattern>
+//      </UnwantedPatterns>
+
+
+                }
+
+                contractList.add(contract);
+                contractMap.put(contract.getCode(), contract);
+                id++;
+            }
+            nurseRoster.setContractList(contractList);
+        }
+
+        private void readEmployeeList(NurseRoster nurseRoster, Element employeesElement) throws JDOMException {
+            List<Element> employeeElementList = (List<Element>) employeesElement.getChildren();
+            List<Employee> employeeList = new ArrayList<Employee>(employeeElementList.size());
+            employeeMap = new HashMap<String, Employee>(employeeElementList.size());
+            long id = 0L;
+            List<SkillProficiency> skillProficiencyList
+                    = new ArrayList<SkillProficiency>(employeeElementList.size() * 2);
+            long skillProficiencyId = 0L;
+            for (Element element : employeeElementList) {
+                assertElementName(element, "Employee");
+                Employee employee = new Employee();
+                employee.setId(id);
+                employee.setCode(element.getAttribute("ID").getValue());
+                employee.setName(element.getChild("Name").getText());
+                Element contractElement = element.getChild("ContractID");
+                Contract contract = contractMap.get(contractElement.getText());
+                if (contract == null) {
+                    throw new IllegalArgumentException("The contract (" + contractElement.getText()
+                            + ") of employee (" + employee.getCode() + ") does not exist.");
+                }
+                employee.setContract(contract);
+
+                Element skillsElement = element.getChild("Skills");
+                if (skillsElement != null) {
+                    List<Element> skillElementList = (List<Element>) skillsElement.getChildren();
+                    for (Element skillElement : skillElementList) {
+                        assertElementName(skillElement, "Skill");
+                        Skill skill = skillMap.get(skillElement.getText());
+                        if (skill == null) {
+                            throw new IllegalArgumentException("The skill (" + skillElement.getText()
+                                    + ") of employee (" + employee.getCode() + ") does not exist.");
+                        }
+                        SkillProficiency skillProficiency = new SkillProficiency();
+                        skillProficiency.setId(skillProficiencyId);
+                        skillProficiency.setEmployee(employee);
+                        skillProficiency.setSkill(skill);
+                        skillProficiencyList.add(skillProficiency);
+                        skillProficiencyId++;
+                    }
+                }
+
+                employeeList.add(employee);
+                employeeMap.put(employee.getCode(), employee);
+                id++;
+            }
+            nurseRoster.setEmployeeList(employeeList);
+            nurseRoster.setSkillProficiencyList(skillProficiencyList);
+        }
+
+        private void readRequiredEmployeeSizes(NurseRoster nurseRoster, Element coverRequirementsElement) {
+            List<Element> coverRequirementElementList = (List<Element>) coverRequirementsElement.getChildren();
+            for (Element element : coverRequirementElementList) {
+                if (element.getName().equals("DayOfWeekCover")) {
+                    Element dayOfWeekElement = element.getChild("Day");
+                    DayOfWeek dayOfWeek = DayOfWeek.valueOfCode(dayOfWeekElement.getText());
+                    if (dayOfWeek == null) {
+                        throw new IllegalArgumentException("The dayOfWeek (" + dayOfWeekElement.getText()
+                                + ") of an entity DayOfWeekCover does not exist.");
+                    }
+
+                    List<Element> coverElementList = (List<Element>) element.getChildren("Cover");
+                    for (Element coverElement : coverElementList) {
+                        Element shiftTypeElement = coverElement.getChild("Shift");
+                        ShiftType shiftType = shiftTypeMap.get(shiftTypeElement.getText());
+                        if (shiftType == null) {
+                            if (shiftTypeElement.getText().equals("Any")) {
+                                throw new IllegalStateException("The shiftType Any is not supported on DayOfWeekCover.");
+                            } else if (shiftTypeElement.getText().equals("None")) {
+                                throw new IllegalStateException("The shiftType None is not supported on DayOfWeekCover.");
+                            } else {
+                                throw new IllegalArgumentException("The shiftType (" + shiftTypeElement.getText()
+                                        + ") of an entity DayOfWeekCover does not exist.");
+                            }
+                        }
+                        List<Object> key = Arrays.<Object>asList(dayOfWeek, shiftType);
+                        List<Shift> shiftList = dayOfWeekAndShiftTypeToShiftListMap.get(key);
+                        if (shiftList == null) {
+                            throw new IllegalArgumentException("The dayOfWeek (" + dayOfWeekElement.getText()
+                                    + ") with the shiftType (" + shiftTypeElement.getText()
+                                    + ") of an entity DayOfWeekCover does not have any shifts.");
+                        }
+                        int requiredEmployeeSize = Integer.parseInt(coverElement.getChild("Preferred").getText());
+                        for (Shift shift : shiftList) {
+                            shift.setRequiredEmployeeSize(shift.getRequiredEmployeeSize() + requiredEmployeeSize);
+                        }
+                    }
+                } else if (element.getName().equals("DateSpecificCover")) {
+                    Element dateElement = element.getChild("Date");
+                    List<Element> coverElementList = (List<Element>) element.getChildren("Cover");
+                    for (Element coverElement : coverElementList) {
+                        Element shiftTypeElement = coverElement.getChild("Shift");
+                        Shift shift = dateAndShiftTypeToShiftMap.get(Arrays.asList(dateElement.getText(), shiftTypeElement.getText()));
+                        if (shift == null) {
+                            throw new IllegalArgumentException("The date (" + dateElement.getText()
+                                    + ") with the shiftType (" + shiftTypeElement.getText()
+                                    + ") of an entity DateSpecificCover does not have a shift.");
+                        }
+                        int requiredEmployeeSize = Integer.parseInt(coverElement.getChild("Preferred").getText());
+                        shift.setRequiredEmployeeSize(shift.getRequiredEmployeeSize() + requiredEmployeeSize);
+                    }
+                } else {
+                    throw new IllegalArgumentException("Unknown cover entity (" + element.getName() + ").");
+                }
+            }
+        }
+
+        private void readDayOffRequestList(NurseRoster nurseRoster, Element dayOffRequestsElement) throws JDOMException {
+            List<DayOffRequest> dayOffRequestList;
+            if (dayOffRequestsElement == null) {
+                dayOffRequestList = Collections.emptyList();
+            } else {
+                List<Element> dayOffElementList = (List<Element>) dayOffRequestsElement.getChildren();
+                dayOffRequestList = new ArrayList<DayOffRequest>(dayOffElementList.size());
+                long id = 0L;
+                for (Element element : dayOffElementList) {
+                    assertElementName(element, "DayOff");
+                    DayOffRequest dayOffRequest = new DayOffRequest();
+                    dayOffRequest.setId(id);
+
+                    Element employeeElement = element.getChild("EmployeeID");
+                    Employee employee = employeeMap.get(employeeElement.getText());
+                    if (employee == null) {
+                        throw new IllegalArgumentException("The shiftDate (" + employeeElement.getText()
+                                + ") of dayOffRequest (" + dayOffRequest + ") does not exist.");
+                    }
+                    dayOffRequest.setEmployee(employee);
+
+                    Element dateElement = element.getChild("Date");
+                    ShiftDate shiftDate = shiftDateMap.get(dateElement.getText());
+                    if (shiftDate == null) {
+                        throw new IllegalArgumentException("The date (" + dateElement.getText()
+                                + ") of dayOffRequest (" + dayOffRequest + ") does not exist.");
+                    }
+                    dayOffRequest.setShiftDate(shiftDate);
+
+                    dayOffRequest.setWeight(element.getAttribute("weight").getIntValue());
+
+                    dayOffRequestList.add(dayOffRequest);
+                    id++;
+                }
+            }
+            nurseRoster.setDayOffRequestList(dayOffRequestList);
+        }
+
+        private void readDayOnRequestList(NurseRoster nurseRoster, Element dayOnRequestsElement) throws JDOMException {
+            List<DayOnRequest> dayOnRequestList;
+            if (dayOnRequestsElement == null) {
+                dayOnRequestList = Collections.emptyList();
+            } else {
+                List<Element> dayOnElementList = (List<Element>) dayOnRequestsElement.getChildren();
+                dayOnRequestList = new ArrayList<DayOnRequest>(dayOnElementList.size());
+                long id = 0L;
+                for (Element element : dayOnElementList) {
+                    assertElementName(element, "DayOn");
+                    DayOnRequest dayOnRequest = new DayOnRequest();
+                    dayOnRequest.setId(id);
+
+                    Element employeeElement = element.getChild("EmployeeID");
+                    Employee employee = employeeMap.get(employeeElement.getText());
+                    if (employee == null) {
+                        throw new IllegalArgumentException("The shiftDate (" + employeeElement.getText()
+                                + ") of dayOnRequest (" + dayOnRequest + ") does not exist.");
+                    }
+                    dayOnRequest.setEmployee(employee);
+
+                    Element dateElement = element.getChild("Date");
+                    ShiftDate shiftDate = shiftDateMap.get(dateElement.getText());
+                    if (shiftDate == null) {
+                        throw new IllegalArgumentException("The date (" + dateElement.getText()
+                                + ") of dayOnRequest (" + dayOnRequest + ") does not exist.");
+                    }
+                    dayOnRequest.setShiftDate(shiftDate);
+
+                    dayOnRequest.setWeight(element.getAttribute("weight").getIntValue());
+
+                    dayOnRequestList.add(dayOnRequest);
+                    id++;
+                }
+            }
+            nurseRoster.setDayOnRequestList(dayOnRequestList);
+        }
+
+        private void readShiftOffRequestList(NurseRoster nurseRoster, Element shiftOffRequestsElement) throws JDOMException {
+            List<ShiftOffRequest> shiftOffRequestList;
+            if (shiftOffRequestsElement == null) {
+                shiftOffRequestList = Collections.emptyList();
+            } else {
+                List<Element> shiftOffElementList = (List<Element>) shiftOffRequestsElement.getChildren();
+                shiftOffRequestList = new ArrayList<ShiftOffRequest>(shiftOffElementList.size());
+                long id = 0L;
+                for (Element element : shiftOffElementList) {
+                    assertElementName(element, "ShiftOff");
+                    ShiftOffRequest shiftOffRequest = new ShiftOffRequest();
+                    shiftOffRequest.setId(id);
+
+                    Element employeeElement = element.getChild("EmployeeID");
+                    Employee employee = employeeMap.get(employeeElement.getText());
+                    if (employee == null) {
+                        throw new IllegalArgumentException("The shift (" + employeeElement.getText()
+                                + ") of shiftOffRequest (" + shiftOffRequest + ") does not exist.");
+                    }
+                    shiftOffRequest.setEmployee(employee);
+
+                    Element dateElement = element.getChild("Date");
+                    Element shiftTypeElement = element.getChild("ShiftTypeID");
+                    Shift shift = dateAndShiftTypeToShiftMap.get(Arrays.asList(dateElement.getText(), shiftTypeElement.getText()));
+                    if (shift == null) {
+                        throw new IllegalArgumentException("The date (" + dateElement.getText()
+                                + ") or the shiftType (" + shiftTypeElement.getText()
+                                + ") of shiftOffRequest (" + shiftOffRequest + ") does not exist.");
+                    }
+                    shiftOffRequest.setShift(shift);
+
+                    shiftOffRequest.setWeight(element.getAttribute("weight").getIntValue());
+
+                    shiftOffRequestList.add(shiftOffRequest);
+                    id++;
+                }
+            }
+            nurseRoster.setShiftOffRequestList(shiftOffRequestList);
+        }
+
+        private void readShiftOnRequestList(NurseRoster nurseRoster, Element shiftOnRequestsElement) throws JDOMException {
+            List<ShiftOnRequest> shiftOnRequestList;
+            if (shiftOnRequestsElement == null) {
+                shiftOnRequestList = Collections.emptyList();
+            } else {
+                List<Element> shiftOnElementList = (List<Element>) shiftOnRequestsElement.getChildren();
+                shiftOnRequestList = new ArrayList<ShiftOnRequest>(shiftOnElementList.size());
+                long id = 0L;
+                for (Element element : shiftOnElementList) {
+                    assertElementName(element, "ShiftOn");
+                    ShiftOnRequest shiftOnRequest = new ShiftOnRequest();
+                    shiftOnRequest.setId(id);
+
+                    Element employeeElement = element.getChild("EmployeeID");
+                    Employee employee = employeeMap.get(employeeElement.getText());
+                    if (employee == null) {
+                        throw new IllegalArgumentException("The shift (" + employeeElement.getText()
+                                + ") of shiftOnRequest (" + shiftOnRequest + ") does not exist.");
+                    }
+                    shiftOnRequest.setEmployee(employee);
+
+                    Element dateElement = element.getChild("Date");
+                    Element shiftTypeElement = element.getChild("ShiftTypeID");
+                    Shift shift = dateAndShiftTypeToShiftMap.get(Arrays.asList(dateElement.getText(), shiftTypeElement.getText()));
+                    if (shift == null) {
+                        throw new IllegalArgumentException("The date (" + dateElement.getText()
+                                + ") or the shiftType (" + shiftTypeElement.getText()
+                                + ") of shiftOnRequest (" + shiftOnRequest + ") does not exist.");
+                    }
+                    shiftOnRequest.setShift(shift);
+
+                    shiftOnRequest.setWeight(element.getAttribute("weight").getIntValue());
+
+                    shiftOnRequestList.add(shiftOnRequest);
+                    id++;
+                }
+            }
+            nurseRoster.setShiftOnRequestList(shiftOnRequestList);
+        }
+
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/app/PatientAdmissionScheduleApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/app/PatientAdmissionScheduleApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/app/PatientAdmissionScheduleApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -3,10 +3,14 @@
 import org.drools.planner.config.XmlSolverConfigurer;
 import org.drools.planner.core.Solver;
 import org.drools.planner.examples.common.app.CommonApp;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
 import org.drools.planner.examples.manners2009.persistence.Manners2009DaoImpl;
 import org.drools.planner.examples.pas.persistence.PatientAdmissionScheduleDaoImpl;
+import org.drools.planner.examples.pas.persistence.PatientAdmissionScheduleSolutionExporter;
+import org.drools.planner.examples.pas.persistence.PatientAdmissionScheduleSolutionImporter;
 import org.drools.planner.examples.pas.swingui.PatientAdmissionSchedulePanel;
 
 /**
@@ -22,11 +26,6 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new PatientAdmissionScheduleDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
@@ -38,4 +37,19 @@
         return new PatientAdmissionSchedulePanel();
     }
 
-}
\ No newline at end of file
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new PatientAdmissionScheduleDaoImpl();
+    }
+
+    @Override
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return new PatientAdmissionScheduleSolutionImporter();
+    }
+
+    @Override
+    protected AbstractSolutionExporter createSolutionExporter() {
+        return new PatientAdmissionScheduleSolutionExporter();
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,523 +0,0 @@
-package org.drools.planner.examples.pas.persistence;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Collections;
-
-import org.drools.planner.core.solution.Solution;
-import org.drools.planner.examples.common.persistence.AbstractTxtInputConverter;
-import org.drools.planner.examples.pas.domain.AdmissionPart;
-import org.drools.planner.examples.pas.domain.Bed;
-import org.drools.planner.examples.pas.domain.Department;
-import org.drools.planner.examples.pas.domain.DepartmentSpecialism;
-import org.drools.planner.examples.pas.domain.Equipment;
-import org.drools.planner.examples.pas.domain.Gender;
-import org.drools.planner.examples.pas.domain.GenderLimitation;
-import org.drools.planner.examples.pas.domain.Night;
-import org.drools.planner.examples.pas.domain.Patient;
-import org.drools.planner.examples.pas.domain.PatientAdmissionSchedule;
-import org.drools.planner.examples.pas.domain.PreferredPatientEquipment;
-import org.drools.planner.examples.pas.domain.RequiredPatientEquipment;
-import org.drools.planner.examples.pas.domain.Room;
-import org.drools.planner.examples.pas.domain.RoomEquipment;
-import org.drools.planner.examples.pas.domain.RoomSpecialism;
-import org.drools.planner.examples.pas.domain.Specialism;
-
-/**
- * @author Geoffrey De Smet
- * @author Wim Vancroonenburg
- */
-public class PatientAdmissionScheduleInputConverter extends AbstractTxtInputConverter {
-
-    public static void main(String[] args) {
-        new PatientAdmissionScheduleInputConverter().convertAll();
-    }
-
-    public PatientAdmissionScheduleInputConverter() {
-        super(new PatientAdmissionScheduleDaoImpl());
-    }
-
-    public TxtInputBuilder createTxtInputBuilder() {
-        return new PatientAdmissionScheduleInputBuilder();
-    }
-
-    public class PatientAdmissionScheduleInputBuilder extends TxtInputBuilder {
-
-        private PatientAdmissionSchedule patientAdmissionSchedule;
-
-        private int specialismListSize;
-        private int departmentListSize;
-        private int equipmentListSize;
-        private int roomListSize;
-        private int bedListSize;
-        private int nightListSize;
-        private int patientListSize;
-
-        private Map<Long, Specialism> idToSpecialismMap = null;
-        private Map<Long, Department> idToDepartmentMap = null;
-        private Map<Integer, Equipment> indexToEquipmentMap = null;
-        private Map<Long, Room> idToRoomMap = null;
-        private Map<Integer, Night> indexToNightMap = null;
-
-        public Solution readSolution() throws IOException {
-            patientAdmissionSchedule = new PatientAdmissionSchedule();
-            patientAdmissionSchedule.setId(0L);
-            readSizes();
-            readEmptyLine();
-            readEmptyLine();
-            readSpecialismList();
-            readEmptyLine();
-            readDepartmentListAndDepartmentSpecialismList();
-            readEmptyLine();
-            readEquipmentList();
-            readEmptyLine();
-            readRoomListAndRoomSpecialismListAndRoomEquipmentList();
-            readEmptyLine();
-            readBedList();
-            readEmptyLine();
-            generateNightList();
-            readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList();
-            readEmptyLine();
-            readConstantLine("END.");
-            // TODO not all nights are planned, only the "planning horizon" nights are planned
-            logger.info("PatientAdmissionSchedule with {} specialisms, {} equipments, {} departments, {} rooms, "
-                    + "{} beds, {} nights, {} patients and {} admissions.",
-                    new Object[]{patientAdmissionSchedule.getSpecialismList().size(),
-                            patientAdmissionSchedule.getEquipmentList().size(),
-                            patientAdmissionSchedule.getDepartmentList().size(),
-                            patientAdmissionSchedule.getRoomList().size(),
-                            patientAdmissionSchedule.getBedList().size(),
-                            patientAdmissionSchedule.getNightList().size(),
-                            patientAdmissionSchedule.getPatientList().size(),
-                            patientAdmissionSchedule.getAdmissionPartList().size()});
-            return patientAdmissionSchedule;
-        }
-
-        private void readSizes() throws IOException {
-            readConstantLine("ARTICLE BENCHMARK DATA SET");
-            roomListSize = readIntegerValue("Rooms:");
-            equipmentListSize = readIntegerValue("Roomproperties:");
-            bedListSize = readIntegerValue("Beds:");
-            departmentListSize = readIntegerValue("Departments:");
-            specialismListSize = readIntegerValue("Specialisms:");
-            patientListSize = readIntegerValue("Patients:");
-            nightListSize = readIntegerValue("Planning horizon:");
-        }
-
-        private void readSpecialismList() throws IOException {
-            readConstantLine("SPECIALISMS:");
-            List<Specialism> specialismList = new ArrayList<Specialism>(specialismListSize);
-            idToSpecialismMap = new HashMap<Long, Specialism>(specialismListSize);
-            for (int i = 0; i < specialismListSize; i++) {
-                String line = bufferedReader.readLine();
-                String[] lineTokens = splitBySpace(line, 2);
-                Specialism specialism = new Specialism();
-                specialism.setId(Long.parseLong(lineTokens[0]));
-                specialism.setName(lineTokens[1]);
-                specialismList.add(specialism);
-                idToSpecialismMap.put(specialism.getId(), specialism);
-            }
-            patientAdmissionSchedule.setSpecialismList(specialismList);
-        }
-
-        private void readDepartmentListAndDepartmentSpecialismList() throws IOException {
-            readConstantLine("DEPARTMENTS:");
-            List<Department> departmentList = new ArrayList<Department>(departmentListSize);
-            idToDepartmentMap = new HashMap<Long, Department>(departmentListSize);
-            List<DepartmentSpecialism> departmentSpecialismList = new ArrayList<DepartmentSpecialism>(
-                    departmentListSize * 5);
-            long departmentSpecialismId = 0L;
-            for (int i = 0; i < departmentListSize; i++) {
-                String line = bufferedReader.readLine();
-                String[] lineTokens = splitByPipeline(line, 2);
-
-                String[] departmentTokens = splitBySpace(lineTokens[0], 4);
-                Department department = new Department();
-                department.setId(Long.parseLong(departmentTokens[0]));
-                department.setName(departmentTokens[1]);
-                int minimumAge = Integer.parseInt(departmentTokens[2]);
-                if (minimumAge != 0) {
-                    department.setMinimumAge(Integer.valueOf(minimumAge));
-                }
-                int maximumAge = Integer.parseInt(departmentTokens[3]);
-                if (maximumAge != 0) {
-                    department.setMaximumAge(Integer.valueOf(maximumAge));
-                }
-                departmentList.add(department);
-                idToDepartmentMap.put(department.getId(), department);
-
-                String[] departmentSpecialismTokens = splitBySpace(lineTokens[1]);
-                if (departmentSpecialismTokens.length % 2 != 0) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain even number of tokens (" + departmentSpecialismTokens.length
-                            + ") after 1st pipeline (|) seperated by a space ( ).");
-                }
-                for (int j = 0; j < departmentSpecialismTokens.length; j += 2) {
-                    long specialismId = Long.parseLong(departmentSpecialismTokens[j + 1]);
-                    if (specialismId != 0) {
-                        DepartmentSpecialism departmentSpecialism = new DepartmentSpecialism();
-                        departmentSpecialism.setId(departmentSpecialismId);
-                        departmentSpecialism.setDepartment(department);
-                        departmentSpecialism.setPriority(Integer.parseInt(departmentSpecialismTokens[j]));
-                        Specialism specialism = idToSpecialismMap.get(specialismId);
-                        if (specialism == null) {
-                            throw new IllegalArgumentException("Read line (" + line
-                                + ") has a non existing specialismId (" + specialismId + ").");
-                        }
-                        departmentSpecialism.setSpecialism(specialism);
-                        departmentSpecialismList.add(departmentSpecialism);
-                        departmentSpecialismId++;
-                    }
-                }
-            }
-            Collections.sort(departmentList);
-            patientAdmissionSchedule.setDepartmentList(departmentList);
-            patientAdmissionSchedule.setDepartmentSpecialismList(departmentSpecialismList);
-        }
-
-        private void readEquipmentList() throws IOException {
-            readConstantLine("ROOMPROPERTIES:");
-            List<Equipment> equipmentList = new ArrayList<Equipment>(equipmentListSize);
-            indexToEquipmentMap = new HashMap<Integer, Equipment>(equipmentListSize);
-            for (int i = 0; i < equipmentListSize; i++) {
-                String line = bufferedReader.readLine();
-                String[] lineTokens = splitBySpace(line, 2);
-                Equipment equipment = new Equipment();
-                equipment.setId(Long.parseLong(lineTokens[0]));
-                equipment.setName(lineTokens[1]);
-                equipmentList.add(equipment);
-                indexToEquipmentMap.put(i, equipment);
-            }
-            patientAdmissionSchedule.setEquipmentList(equipmentList);
-        }
-
-        private void readRoomListAndRoomSpecialismListAndRoomEquipmentList() throws IOException {
-            readConstantLine("ROOMS:");
-            List<Room> roomList = new ArrayList<Room>(roomListSize);
-            idToRoomMap = new HashMap<Long, Room>(roomListSize);
-            List<RoomSpecialism> roomSpecialismList = new ArrayList<RoomSpecialism>(roomListSize * 5);
-            List<RoomEquipment> roomEquipmentList = new ArrayList<RoomEquipment>(roomListSize * 2);
-            long roomSpecialismId = 0L;
-            long roomEquipmentId = 0L;
-            for (int i = 0; i < roomListSize; i++) {
-                String line = bufferedReader.readLine();
-                String[] lineTokens = splitByPipeline(line, 6);
-
-                String[] roomTokens = splitBySpace(lineTokens[0], 2);
-                Room room = new Room();
-                room.setId(Long.parseLong(roomTokens[0]));
-                room.setName(roomTokens[1]);
-                room.setCapacity(Integer.parseInt(lineTokens[1]));
-                room.setDepartment(idToDepartmentMap.get(
-                        Long.parseLong(lineTokens[2])));
-                room.setGenderLimitation(GenderLimitation.valueOfCode(lineTokens[3]));
-                roomList.add(room);
-                idToRoomMap.put(room.getId(), room);
-
-                String[] roomSpecialismTokens = splitBySpace(lineTokens[4]);
-                if (roomSpecialismTokens.length % 2 != 0) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain even number of tokens (" + roomSpecialismTokens.length
-                            + ") after 4th pipeline (|) seperated by a space ( ).");
-                }
-                List<RoomSpecialism> roomSpecialismListOfRoom = new ArrayList<RoomSpecialism>(roomSpecialismTokens.length / 2);
-                for (int j = 0; j < roomSpecialismTokens.length; j += 2) {
-                    int priority = Integer.parseInt(roomSpecialismTokens[j]);
-                    long specialismId = Long.parseLong(roomSpecialismTokens[j + 1]);
-                    if (specialismId != 0) {
-                        RoomSpecialism roomSpecialism = new RoomSpecialism();
-                        roomSpecialism.setId(roomSpecialismId);
-                        roomSpecialism.setRoom(room);
-                        Specialism specialism = idToSpecialismMap.get(specialismId);
-                        if (specialism == null) {
-                            throw new IllegalArgumentException("Read line (" + line
-                                + ") has a non existing specialismId (" + specialismId + ").");
-                        }
-                        roomSpecialism.setSpecialism(specialism);
-                        roomSpecialism.setPriority(priority);
-                        roomSpecialismListOfRoom.add(roomSpecialism);
-                        roomSpecialismList.add(roomSpecialism);
-                        roomSpecialismId++;
-                    }
-                }
-                room.setRoomSpecialismList(roomSpecialismListOfRoom);
-
-                List<RoomEquipment> roomEquipmentListOfRoom = new ArrayList<RoomEquipment>(equipmentListSize);
-                String[] roomEquipmentTokens = splitBySpace(lineTokens[5]);
-                if (roomEquipmentTokens.length != equipmentListSize) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain equal number of tokens (" + roomEquipmentTokens.length
-                            + ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
-                }
-                for (int j = 0; j < roomEquipmentTokens.length; j++) {
-                    int hasEquipment = Integer.parseInt(roomEquipmentTokens[j]);
-                    if (hasEquipment == 1) {
-                        RoomEquipment roomEquipment = new RoomEquipment();
-                        roomEquipment.setId(roomEquipmentId);
-                        roomEquipment.setRoom(room);
-                        roomEquipment.setEquipment(indexToEquipmentMap.get(j));
-                        roomEquipmentListOfRoom.add(roomEquipment);
-                        roomEquipmentList.add(roomEquipment);
-                        roomEquipmentId++;
-                    } else if (hasEquipment != 0) {
-                        throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
-                    }
-                }
-                room.setRoomEquipmentList(roomEquipmentListOfRoom);
-            }
-            Collections.sort(roomList);
-            patientAdmissionSchedule.setRoomList(roomList);
-            patientAdmissionSchedule.setRoomSpecialismList(roomSpecialismList);
-            patientAdmissionSchedule.setRoomEquipmentList(roomEquipmentList);
-        }
-
-        private void readBedList() throws IOException {
-            readConstantLine("BEDS:");
-            List<Bed> bedList = new ArrayList<Bed>(bedListSize);
-            Map<Room, Integer> roomToLastIndexInRoomMap = new HashMap<Room, Integer>(roomListSize);
-            for (int i = 0; i < bedListSize; i++) {
-                String line = bufferedReader.readLine();
-                String[] lineTokens = splitBySpace(line, 2);
-                Bed bed = new Bed();
-                bed.setId(Long.parseLong(lineTokens[0]));
-                Room room = idToRoomMap.get(Long.parseLong(lineTokens[1]));
-                bed.setRoom(room);
-                Integer indexInRoom = roomToLastIndexInRoomMap.get(room);
-                if (indexInRoom == null) {
-                    indexInRoom = 0;
-                } else {
-                    indexInRoom++;
-                }
-                bed.setIndexInRoom(indexInRoom);
-                roomToLastIndexInRoomMap.put(room, indexInRoom);
-                bedList.add(bed);
-            }
-            Collections.sort(bedList);
-            patientAdmissionSchedule.setBedList(bedList);
-        }
-
-        private void generateNightList() {
-            List<Night> nightList = new ArrayList<Night>(nightListSize);
-            indexToNightMap = new HashMap<Integer, Night>(nightListSize);
-            long nightId = 0L;
-            for (int i = 0; i < nightListSize; i++) {
-                Night night = new Night();
-                night.setId(nightId);
-                night.setIndex(i);
-                nightList.add(night);
-                indexToNightMap.put(i, night);
-                nightId++;
-            }
-            patientAdmissionSchedule.setNightList(nightList);
-        }
-
-        private void readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList() throws IOException {
-            readConstantLine("PATIENTS:");
-            List<Patient> patientList = new ArrayList<Patient>(patientListSize);
-            List<AdmissionPart> admissionPartList = new ArrayList<AdmissionPart>(patientListSize);
-            List<RequiredPatientEquipment> requiredPatientEquipmentList = new ArrayList<RequiredPatientEquipment>(patientListSize * equipmentListSize);
-            List<PreferredPatientEquipment> preferredPatientEquipmentList = new ArrayList<PreferredPatientEquipment>(patientListSize * equipmentListSize);
-            long admissionPartId = 0L;
-            long requiredPatientEquipmentId = 0L;
-            long preferredPatientEquipmentId = 0L;
-            for (int i = 0; i < patientListSize; i++) {
-                String line = bufferedReader.readLine();
-                String[] lineTokens = splitByPipeline(line, 6);
-
-                String[] nightTokens = splitBySpace(lineTokens[1], 2);
-                int firstNightIndex = Integer.parseInt(nightTokens[0]);
-                int lastNightIndex = Integer.parseInt(nightTokens[1]);
-                int patientNightListSize = lastNightIndex - firstNightIndex;
-                // A patient with no nights in the planning horizon or no nights at all is ignored
-                if (firstNightIndex >= nightListSize || patientNightListSize == 0) {
-                    continue;
-                }
-
-                String[] patientTokens = splitBySpace(lineTokens[0], 4);
-                Patient patient = new Patient();
-                patient.setId(Long.parseLong(patientTokens[0]));
-                patient.setName(patientTokens[1]);
-                patient.setAge(Integer.parseInt(patientTokens[2]));
-                patient.setGender(Gender.valueOfCode(patientTokens[3]));
-                int preferredMaximumRoomCapacity = Integer.parseInt(lineTokens[3]);
-                patient.setPreferredMaximumRoomCapacity(preferredMaximumRoomCapacity == 0
-                        ? null : preferredMaximumRoomCapacity);
-                patientList.add(patient);
-
-                String[] admissionPartTokens = splitBySpace(lineTokens[2]);
-                if (admissionPartTokens.length % 2 != 1) {
-                }
-                int patientAdmissionPartListSize = Integer.parseInt(admissionPartTokens[0]);
-                if (admissionPartTokens.length != ((patientAdmissionPartListSize * 2) + 1)) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain " + ((patientAdmissionPartListSize * 2) + 1)
-                            + " number of tokens after 2th pipeline (|).");
-                }
-                int nextFirstNightIndex = firstNightIndex;
-                for (int j = 1; j < admissionPartTokens.length; j += 2) {
-                    long specialismId = Long.parseLong(admissionPartTokens[j]);
-                    int admissionPartNightListSize = Integer.parseInt(admissionPartTokens[j + 1]);
-                    if (nextFirstNightIndex >= nightListSize || admissionPartNightListSize == 0) {
-                        nextFirstNightIndex += admissionPartNightListSize;
-                        continue;
-                    }
-                    AdmissionPart admissionPart = new AdmissionPart();
-                    admissionPart.setId(admissionPartId);
-                    admissionPart.setPatient(patient);
-                    Specialism specialism = (specialismId == 0) ? null : idToSpecialismMap.get(specialismId);
-                    if (specialism == null) {
-                        throw new IllegalArgumentException("Read line (" + line
-                            + ") has a non existing specialismId (" + specialismId + ").");
-                    }
-                    admissionPart.setSpecialism(specialism);
-                    int admissionPartFirstNightIndex = nextFirstNightIndex;
-                    Night admissionPartFirstNight = indexToNightMap.get(admissionPartFirstNightIndex);
-                    if (admissionPartFirstNight == null) {
-                        throw new IllegalStateException(
-                                "The admissionPartFirstNight was not found for admissionPartFirstNightIndex("
-                                        + admissionPartFirstNightIndex + ").");
-                    }
-                    admissionPart.setFirstNight(admissionPartFirstNight);
-                    int admissionPartLastNightIndex = nextFirstNightIndex + admissionPartNightListSize - 1;
-                    // TODO Instead of ensureEnoughNights(lastNightIndex);
-                    // the official score function ignores any broken constraints after the planning horizon
-                    if (admissionPartLastNightIndex >= nightListSize) {
-                        admissionPartLastNightIndex = nightListSize - 1;
-                    }
-                    Night admissionPartLastNight = indexToNightMap.get(admissionPartLastNightIndex);
-                    if (admissionPartLastNight == null) {
-                        throw new IllegalStateException(
-                                "The admissionPartLastNight was not found for admissionPartLastNightIndex("
-                                        + admissionPartLastNightIndex + ").");
-                    }
-                    admissionPart.setLastNight(admissionPartLastNight);
-                    admissionPartList.add(admissionPart);
-                    admissionPartId++;
-                    nextFirstNightIndex += admissionPartNightListSize;
-                }
-                int admissionPartNightListSizeSum = nextFirstNightIndex - firstNightIndex;
-                if (patientNightListSize != admissionPartNightListSizeSum) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") has patientNightListSize (" + patientNightListSize
-                            + ") different from admissionPartNightListSizeSum(" + admissionPartNightListSizeSum + ")");
-                }
-
-                String[] requiredPatientEquipmentTokens = splitBySpace(lineTokens[4]);
-                if (requiredPatientEquipmentTokens.length != equipmentListSize) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain equal number of tokens ("
-                            + requiredPatientEquipmentTokens.length
-                            + ") as equipmentListSize (" + equipmentListSize + ") after 4th pipeline (|).");
-                }
-                List<RequiredPatientEquipment> requiredPatientEquipmentOfPatientList
-                        = new ArrayList<RequiredPatientEquipment>(equipmentListSize);
-                for (int j = 0; j < requiredPatientEquipmentTokens.length; j++) {
-                    int hasEquipment = Integer.parseInt(requiredPatientEquipmentTokens[j]);
-                    if (hasEquipment == 1) {
-                        RequiredPatientEquipment requiredPatientEquipment = new RequiredPatientEquipment();
-                        requiredPatientEquipment.setId(requiredPatientEquipmentId);
-                        requiredPatientEquipment.setPatient(patient);
-                        requiredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
-                        requiredPatientEquipmentOfPatientList.add(requiredPatientEquipment);
-                        requiredPatientEquipmentList.add(requiredPatientEquipment);
-                        requiredPatientEquipmentId++;
-                    } else if (hasEquipment != 0) {
-                        throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
-                    }
-                }
-                patient.setRequiredPatientEquipmentList(requiredPatientEquipmentOfPatientList);
-
-                String[] preferredPatientEquipmentTokens = splitBySpace(lineTokens[5]);
-                if (preferredPatientEquipmentTokens.length != equipmentListSize) {
-                    throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to contain equal number of tokens ("
-                            + preferredPatientEquipmentTokens.length
-                            + ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
-                }
-                List<PreferredPatientEquipment> preferredPatientEquipmentOfPatientList
-                        = new ArrayList<PreferredPatientEquipment>(equipmentListSize);
-                for (int j = 0; j < preferredPatientEquipmentTokens.length; j++) {
-                    int hasEquipment = Integer.parseInt(preferredPatientEquipmentTokens[j]);
-                    if (hasEquipment == 1) {
-                        boolean alreadyRequired = (Integer.parseInt(requiredPatientEquipmentTokens[j]) == 1);
-                        // Official spec: if equipment is required
-                        // then a duplicate preffered constraint should be ignored 
-                        if (!alreadyRequired) {
-                            PreferredPatientEquipment preferredPatientEquipment = new PreferredPatientEquipment();
-                            preferredPatientEquipment.setId(preferredPatientEquipmentId);
-                            preferredPatientEquipment.setPatient(patient);
-                            preferredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
-                            preferredPatientEquipmentOfPatientList.add(preferredPatientEquipment);
-                            preferredPatientEquipmentList.add(preferredPatientEquipment);
-                            preferredPatientEquipmentId++;
-                        }
-                    } else if (hasEquipment != 0) {
-                        throw new IllegalArgumentException("Read line (" + line
-                            + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
-                    }
-                }
-                patient.setPreferredPatientEquipmentList(preferredPatientEquipmentOfPatientList);
-            }
-            patientAdmissionSchedule.setPatientList(patientList);
-            patientAdmissionSchedule.setAdmissionPartList(admissionPartList);
-            patientAdmissionSchedule.setRequiredPatientEquipmentList(requiredPatientEquipmentList);
-            patientAdmissionSchedule.setPreferredPatientEquipmentList(preferredPatientEquipmentList);
-        }
-
-//        /**
-//         * hack to make sure there are enough nights
-//         * @param lastNightIndex >= 0
-//         */
-//        private void ensureEnoughNights(int lastNightIndex) {
-//            List<Night> nightList = patientAdmissionSchedule.getNightList();
-//            if (lastNightIndex >= nightList.size()) {
-//                long nightId = nightList.size();
-//                for (int j = nightList.size(); j <= lastNightIndex; j++) {
-//                    Night night = new Night();
-//                    night.setId(nightId);
-//                    night.setIndex(j);
-//                    nightList.add(night);
-//                    indexToNightMap.put(j, night);
-//                    nightId++;
-//                }
-//            }
-//        }
-
-        // ************************************************************************
-        // Helper methods
-        // ************************************************************************
-
-        private String[] splitBySpace(String line) {
-            String[] lineTokens = line.split("\\ ");
-            return lineTokens;
-        }
-
-        private String[] splitBySpace(String line, int numberOfTokens) {
-            String[] lineTokens = line.split("\\ ");
-            if (lineTokens.length != numberOfTokens) {
-                throw new IllegalArgumentException("Read line (" + line
-                        + ") is expected to contain " +  numberOfTokens + " tokens seperated by a space ( ).");
-            }
-            return lineTokens;
-        }
-
-        private String[] splitByPipeline(String line, int numberOfTokens) {
-            String[] lineTokens = line.split("\\|");
-            if (lineTokens.length != numberOfTokens) {
-                throw new IllegalArgumentException("Read line (" + line
-                        + ") is expected to contain " +  numberOfTokens + " tokens seperated by a pipeline (|).");
-            }
-            for (int i = 0; i < lineTokens.length; i++) {
-                lineTokens[i] = lineTokens[i].trim();
-            }
-            return lineTokens;
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,53 +0,0 @@
-package org.drools.planner.examples.pas.persistence;
-
-import java.io.IOException;
-import java.util.Collections;
-
-import org.drools.planner.examples.common.persistence.AbstractTxtOutputConverter;
-import org.drools.planner.examples.pas.domain.PatientAdmissionSchedule;
-import org.drools.planner.examples.pas.domain.Patient;
-import org.drools.planner.examples.pas.domain.BedDesignation;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public class PatientAdmissionScheduleOutputConverter extends AbstractTxtOutputConverter {
-
-    public static void main(String[] args) {
-        new PatientAdmissionScheduleOutputConverter().convertAll();
-    }
-
-    public PatientAdmissionScheduleOutputConverter() {
-        super(new PatientAdmissionScheduleDaoImpl());
-    }
-
-    public TxtOutputBuilder createTxtOutputBuilder() {
-        return new PatientAdmissionScheduleOutputBuilder();
-    }
-
-    public class PatientAdmissionScheduleOutputBuilder extends TxtOutputBuilder {
-
-        private PatientAdmissionSchedule patientAdmissionSchedule;
-
-        public void setSolution(Solution solution) {
-            patientAdmissionSchedule = (PatientAdmissionSchedule) solution;
-        }
-
-        public void writeSolution() throws IOException {
-            Collections.sort(patientAdmissionSchedule.getBedDesignationList());
-            for (Patient patient : patientAdmissionSchedule.getPatientList()) {
-                bufferedWriter.write(Long.toString(patient.getId()));
-                for (BedDesignation bedDesignation : patientAdmissionSchedule.getBedDesignationList()) {
-                    if (bedDesignation.getPatient().equals(patient)) {
-                        for (int i = 0; i < bedDesignation.getAdmissionPart().getNightCount(); i++) {
-                            bufferedWriter.write(" " + Long.toString(bedDesignation.getBed().getId()));
-                        }
-                    }
-                }
-                bufferedWriter.write("\n");
-            }
-        }
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionExporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,53 @@
+package org.drools.planner.examples.pas.persistence;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionExporter;
+import org.drools.planner.examples.pas.domain.PatientAdmissionSchedule;
+import org.drools.planner.examples.pas.domain.Patient;
+import org.drools.planner.examples.pas.domain.BedDesignation;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class PatientAdmissionScheduleSolutionExporter extends AbstractTxtSolutionExporter {
+
+    public static void main(String[] args) {
+        new PatientAdmissionScheduleSolutionExporter().convertAll();
+    }
+
+    public PatientAdmissionScheduleSolutionExporter() {
+        super(new PatientAdmissionScheduleDaoImpl());
+    }
+
+    public TxtOutputBuilder createTxtOutputBuilder() {
+        return new PatientAdmissionScheduleOutputBuilder();
+    }
+
+    public class PatientAdmissionScheduleOutputBuilder extends TxtOutputBuilder {
+
+        private PatientAdmissionSchedule patientAdmissionSchedule;
+
+        public void setSolution(Solution solution) {
+            patientAdmissionSchedule = (PatientAdmissionSchedule) solution;
+        }
+
+        public void writeSolution() throws IOException {
+            Collections.sort(patientAdmissionSchedule.getBedDesignationList());
+            for (Patient patient : patientAdmissionSchedule.getPatientList()) {
+                bufferedWriter.write(Long.toString(patient.getId()));
+                for (BedDesignation bedDesignation : patientAdmissionSchedule.getBedDesignationList()) {
+                    if (bedDesignation.getPatient().equals(patient)) {
+                        for (int i = 0; i < bedDesignation.getAdmissionPart().getNightCount(); i++) {
+                            bufferedWriter.write(" " + Long.toString(bedDesignation.getBed().getId()));
+                        }
+                    }
+                }
+                bufferedWriter.write("\n");
+            }
+        }
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/pas/persistence/PatientAdmissionScheduleSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,523 @@
+package org.drools.planner.examples.pas.persistence;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+
+import org.drools.planner.core.solution.Solution;
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionImporter;
+import org.drools.planner.examples.pas.domain.AdmissionPart;
+import org.drools.planner.examples.pas.domain.Bed;
+import org.drools.planner.examples.pas.domain.Department;
+import org.drools.planner.examples.pas.domain.DepartmentSpecialism;
+import org.drools.planner.examples.pas.domain.Equipment;
+import org.drools.planner.examples.pas.domain.Gender;
+import org.drools.planner.examples.pas.domain.GenderLimitation;
+import org.drools.planner.examples.pas.domain.Night;
+import org.drools.planner.examples.pas.domain.Patient;
+import org.drools.planner.examples.pas.domain.PatientAdmissionSchedule;
+import org.drools.planner.examples.pas.domain.PreferredPatientEquipment;
+import org.drools.planner.examples.pas.domain.RequiredPatientEquipment;
+import org.drools.planner.examples.pas.domain.Room;
+import org.drools.planner.examples.pas.domain.RoomEquipment;
+import org.drools.planner.examples.pas.domain.RoomSpecialism;
+import org.drools.planner.examples.pas.domain.Specialism;
+
+/**
+ * @author Geoffrey De Smet
+ * @author Wim Vancroonenburg
+ */
+public class PatientAdmissionScheduleSolutionImporter extends AbstractTxtSolutionImporter {
+
+    public static void main(String[] args) {
+        new PatientAdmissionScheduleSolutionImporter().convertAll();
+    }
+
+    public PatientAdmissionScheduleSolutionImporter() {
+        super(new PatientAdmissionScheduleDaoImpl());
+    }
+
+    public TxtInputBuilder createTxtInputBuilder() {
+        return new PatientAdmissionScheduleInputBuilder();
+    }
+
+    public class PatientAdmissionScheduleInputBuilder extends TxtInputBuilder {
+
+        private PatientAdmissionSchedule patientAdmissionSchedule;
+
+        private int specialismListSize;
+        private int departmentListSize;
+        private int equipmentListSize;
+        private int roomListSize;
+        private int bedListSize;
+        private int nightListSize;
+        private int patientListSize;
+
+        private Map<Long, Specialism> idToSpecialismMap = null;
+        private Map<Long, Department> idToDepartmentMap = null;
+        private Map<Integer, Equipment> indexToEquipmentMap = null;
+        private Map<Long, Room> idToRoomMap = null;
+        private Map<Integer, Night> indexToNightMap = null;
+
+        public Solution readSolution() throws IOException {
+            patientAdmissionSchedule = new PatientAdmissionSchedule();
+            patientAdmissionSchedule.setId(0L);
+            readSizes();
+            readEmptyLine();
+            readEmptyLine();
+            readSpecialismList();
+            readEmptyLine();
+            readDepartmentListAndDepartmentSpecialismList();
+            readEmptyLine();
+            readEquipmentList();
+            readEmptyLine();
+            readRoomListAndRoomSpecialismListAndRoomEquipmentList();
+            readEmptyLine();
+            readBedList();
+            readEmptyLine();
+            generateNightList();
+            readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList();
+            readEmptyLine();
+            readConstantLine("END.");
+            // TODO not all nights are planned, only the "planning horizon" nights are planned
+            logger.info("PatientAdmissionSchedule with {} specialisms, {} equipments, {} departments, {} rooms, "
+                    + "{} beds, {} nights, {} patients and {} admissions.",
+                    new Object[]{patientAdmissionSchedule.getSpecialismList().size(),
+                            patientAdmissionSchedule.getEquipmentList().size(),
+                            patientAdmissionSchedule.getDepartmentList().size(),
+                            patientAdmissionSchedule.getRoomList().size(),
+                            patientAdmissionSchedule.getBedList().size(),
+                            patientAdmissionSchedule.getNightList().size(),
+                            patientAdmissionSchedule.getPatientList().size(),
+                            patientAdmissionSchedule.getAdmissionPartList().size()});
+            return patientAdmissionSchedule;
+        }
+
+        private void readSizes() throws IOException {
+            readConstantLine("ARTICLE BENCHMARK DATA SET");
+            roomListSize = readIntegerValue("Rooms:");
+            equipmentListSize = readIntegerValue("Roomproperties:");
+            bedListSize = readIntegerValue("Beds:");
+            departmentListSize = readIntegerValue("Departments:");
+            specialismListSize = readIntegerValue("Specialisms:");
+            patientListSize = readIntegerValue("Patients:");
+            nightListSize = readIntegerValue("Planning horizon:");
+        }
+
+        private void readSpecialismList() throws IOException {
+            readConstantLine("SPECIALISMS:");
+            List<Specialism> specialismList = new ArrayList<Specialism>(specialismListSize);
+            idToSpecialismMap = new HashMap<Long, Specialism>(specialismListSize);
+            for (int i = 0; i < specialismListSize; i++) {
+                String line = bufferedReader.readLine();
+                String[] lineTokens = splitBySpace(line, 2);
+                Specialism specialism = new Specialism();
+                specialism.setId(Long.parseLong(lineTokens[0]));
+                specialism.setName(lineTokens[1]);
+                specialismList.add(specialism);
+                idToSpecialismMap.put(specialism.getId(), specialism);
+            }
+            patientAdmissionSchedule.setSpecialismList(specialismList);
+        }
+
+        private void readDepartmentListAndDepartmentSpecialismList() throws IOException {
+            readConstantLine("DEPARTMENTS:");
+            List<Department> departmentList = new ArrayList<Department>(departmentListSize);
+            idToDepartmentMap = new HashMap<Long, Department>(departmentListSize);
+            List<DepartmentSpecialism> departmentSpecialismList = new ArrayList<DepartmentSpecialism>(
+                    departmentListSize * 5);
+            long departmentSpecialismId = 0L;
+            for (int i = 0; i < departmentListSize; i++) {
+                String line = bufferedReader.readLine();
+                String[] lineTokens = splitByPipeline(line, 2);
+
+                String[] departmentTokens = splitBySpace(lineTokens[0], 4);
+                Department department = new Department();
+                department.setId(Long.parseLong(departmentTokens[0]));
+                department.setName(departmentTokens[1]);
+                int minimumAge = Integer.parseInt(departmentTokens[2]);
+                if (minimumAge != 0) {
+                    department.setMinimumAge(Integer.valueOf(minimumAge));
+                }
+                int maximumAge = Integer.parseInt(departmentTokens[3]);
+                if (maximumAge != 0) {
+                    department.setMaximumAge(Integer.valueOf(maximumAge));
+                }
+                departmentList.add(department);
+                idToDepartmentMap.put(department.getId(), department);
+
+                String[] departmentSpecialismTokens = splitBySpace(lineTokens[1]);
+                if (departmentSpecialismTokens.length % 2 != 0) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain even number of tokens (" + departmentSpecialismTokens.length
+                            + ") after 1st pipeline (|) seperated by a space ( ).");
+                }
+                for (int j = 0; j < departmentSpecialismTokens.length; j += 2) {
+                    long specialismId = Long.parseLong(departmentSpecialismTokens[j + 1]);
+                    if (specialismId != 0) {
+                        DepartmentSpecialism departmentSpecialism = new DepartmentSpecialism();
+                        departmentSpecialism.setId(departmentSpecialismId);
+                        departmentSpecialism.setDepartment(department);
+                        departmentSpecialism.setPriority(Integer.parseInt(departmentSpecialismTokens[j]));
+                        Specialism specialism = idToSpecialismMap.get(specialismId);
+                        if (specialism == null) {
+                            throw new IllegalArgumentException("Read line (" + line
+                                + ") has a non existing specialismId (" + specialismId + ").");
+                        }
+                        departmentSpecialism.setSpecialism(specialism);
+                        departmentSpecialismList.add(departmentSpecialism);
+                        departmentSpecialismId++;
+                    }
+                }
+            }
+            Collections.sort(departmentList);
+            patientAdmissionSchedule.setDepartmentList(departmentList);
+            patientAdmissionSchedule.setDepartmentSpecialismList(departmentSpecialismList);
+        }
+
+        private void readEquipmentList() throws IOException {
+            readConstantLine("ROOMPROPERTIES:");
+            List<Equipment> equipmentList = new ArrayList<Equipment>(equipmentListSize);
+            indexToEquipmentMap = new HashMap<Integer, Equipment>(equipmentListSize);
+            for (int i = 0; i < equipmentListSize; i++) {
+                String line = bufferedReader.readLine();
+                String[] lineTokens = splitBySpace(line, 2);
+                Equipment equipment = new Equipment();
+                equipment.setId(Long.parseLong(lineTokens[0]));
+                equipment.setName(lineTokens[1]);
+                equipmentList.add(equipment);
+                indexToEquipmentMap.put(i, equipment);
+            }
+            patientAdmissionSchedule.setEquipmentList(equipmentList);
+        }
+
+        private void readRoomListAndRoomSpecialismListAndRoomEquipmentList() throws IOException {
+            readConstantLine("ROOMS:");
+            List<Room> roomList = new ArrayList<Room>(roomListSize);
+            idToRoomMap = new HashMap<Long, Room>(roomListSize);
+            List<RoomSpecialism> roomSpecialismList = new ArrayList<RoomSpecialism>(roomListSize * 5);
+            List<RoomEquipment> roomEquipmentList = new ArrayList<RoomEquipment>(roomListSize * 2);
+            long roomSpecialismId = 0L;
+            long roomEquipmentId = 0L;
+            for (int i = 0; i < roomListSize; i++) {
+                String line = bufferedReader.readLine();
+                String[] lineTokens = splitByPipeline(line, 6);
+
+                String[] roomTokens = splitBySpace(lineTokens[0], 2);
+                Room room = new Room();
+                room.setId(Long.parseLong(roomTokens[0]));
+                room.setName(roomTokens[1]);
+                room.setCapacity(Integer.parseInt(lineTokens[1]));
+                room.setDepartment(idToDepartmentMap.get(
+                        Long.parseLong(lineTokens[2])));
+                room.setGenderLimitation(GenderLimitation.valueOfCode(lineTokens[3]));
+                roomList.add(room);
+                idToRoomMap.put(room.getId(), room);
+
+                String[] roomSpecialismTokens = splitBySpace(lineTokens[4]);
+                if (roomSpecialismTokens.length % 2 != 0) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain even number of tokens (" + roomSpecialismTokens.length
+                            + ") after 4th pipeline (|) seperated by a space ( ).");
+                }
+                List<RoomSpecialism> roomSpecialismListOfRoom = new ArrayList<RoomSpecialism>(roomSpecialismTokens.length / 2);
+                for (int j = 0; j < roomSpecialismTokens.length; j += 2) {
+                    int priority = Integer.parseInt(roomSpecialismTokens[j]);
+                    long specialismId = Long.parseLong(roomSpecialismTokens[j + 1]);
+                    if (specialismId != 0) {
+                        RoomSpecialism roomSpecialism = new RoomSpecialism();
+                        roomSpecialism.setId(roomSpecialismId);
+                        roomSpecialism.setRoom(room);
+                        Specialism specialism = idToSpecialismMap.get(specialismId);
+                        if (specialism == null) {
+                            throw new IllegalArgumentException("Read line (" + line
+                                + ") has a non existing specialismId (" + specialismId + ").");
+                        }
+                        roomSpecialism.setSpecialism(specialism);
+                        roomSpecialism.setPriority(priority);
+                        roomSpecialismListOfRoom.add(roomSpecialism);
+                        roomSpecialismList.add(roomSpecialism);
+                        roomSpecialismId++;
+                    }
+                }
+                room.setRoomSpecialismList(roomSpecialismListOfRoom);
+
+                List<RoomEquipment> roomEquipmentListOfRoom = new ArrayList<RoomEquipment>(equipmentListSize);
+                String[] roomEquipmentTokens = splitBySpace(lineTokens[5]);
+                if (roomEquipmentTokens.length != equipmentListSize) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain equal number of tokens (" + roomEquipmentTokens.length
+                            + ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
+                }
+                for (int j = 0; j < roomEquipmentTokens.length; j++) {
+                    int hasEquipment = Integer.parseInt(roomEquipmentTokens[j]);
+                    if (hasEquipment == 1) {
+                        RoomEquipment roomEquipment = new RoomEquipment();
+                        roomEquipment.setId(roomEquipmentId);
+                        roomEquipment.setRoom(room);
+                        roomEquipment.setEquipment(indexToEquipmentMap.get(j));
+                        roomEquipmentListOfRoom.add(roomEquipment);
+                        roomEquipmentList.add(roomEquipment);
+                        roomEquipmentId++;
+                    } else if (hasEquipment != 0) {
+                        throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
+                    }
+                }
+                room.setRoomEquipmentList(roomEquipmentListOfRoom);
+            }
+            Collections.sort(roomList);
+            patientAdmissionSchedule.setRoomList(roomList);
+            patientAdmissionSchedule.setRoomSpecialismList(roomSpecialismList);
+            patientAdmissionSchedule.setRoomEquipmentList(roomEquipmentList);
+        }
+
+        private void readBedList() throws IOException {
+            readConstantLine("BEDS:");
+            List<Bed> bedList = new ArrayList<Bed>(bedListSize);
+            Map<Room, Integer> roomToLastIndexInRoomMap = new HashMap<Room, Integer>(roomListSize);
+            for (int i = 0; i < bedListSize; i++) {
+                String line = bufferedReader.readLine();
+                String[] lineTokens = splitBySpace(line, 2);
+                Bed bed = new Bed();
+                bed.setId(Long.parseLong(lineTokens[0]));
+                Room room = idToRoomMap.get(Long.parseLong(lineTokens[1]));
+                bed.setRoom(room);
+                Integer indexInRoom = roomToLastIndexInRoomMap.get(room);
+                if (indexInRoom == null) {
+                    indexInRoom = 0;
+                } else {
+                    indexInRoom++;
+                }
+                bed.setIndexInRoom(indexInRoom);
+                roomToLastIndexInRoomMap.put(room, indexInRoom);
+                bedList.add(bed);
+            }
+            Collections.sort(bedList);
+            patientAdmissionSchedule.setBedList(bedList);
+        }
+
+        private void generateNightList() {
+            List<Night> nightList = new ArrayList<Night>(nightListSize);
+            indexToNightMap = new HashMap<Integer, Night>(nightListSize);
+            long nightId = 0L;
+            for (int i = 0; i < nightListSize; i++) {
+                Night night = new Night();
+                night.setId(nightId);
+                night.setIndex(i);
+                nightList.add(night);
+                indexToNightMap.put(i, night);
+                nightId++;
+            }
+            patientAdmissionSchedule.setNightList(nightList);
+        }
+
+        private void readPatientListAndAdmissionPartListAndRequiredPatientEquipmentListAndPreferredPatientEquipmentList() throws IOException {
+            readConstantLine("PATIENTS:");
+            List<Patient> patientList = new ArrayList<Patient>(patientListSize);
+            List<AdmissionPart> admissionPartList = new ArrayList<AdmissionPart>(patientListSize);
+            List<RequiredPatientEquipment> requiredPatientEquipmentList = new ArrayList<RequiredPatientEquipment>(patientListSize * equipmentListSize);
+            List<PreferredPatientEquipment> preferredPatientEquipmentList = new ArrayList<PreferredPatientEquipment>(patientListSize * equipmentListSize);
+            long admissionPartId = 0L;
+            long requiredPatientEquipmentId = 0L;
+            long preferredPatientEquipmentId = 0L;
+            for (int i = 0; i < patientListSize; i++) {
+                String line = bufferedReader.readLine();
+                String[] lineTokens = splitByPipeline(line, 6);
+
+                String[] nightTokens = splitBySpace(lineTokens[1], 2);
+                int firstNightIndex = Integer.parseInt(nightTokens[0]);
+                int lastNightIndex = Integer.parseInt(nightTokens[1]);
+                int patientNightListSize = lastNightIndex - firstNightIndex;
+                // A patient with no nights in the planning horizon or no nights at all is ignored
+                if (firstNightIndex >= nightListSize || patientNightListSize == 0) {
+                    continue;
+                }
+
+                String[] patientTokens = splitBySpace(lineTokens[0], 4);
+                Patient patient = new Patient();
+                patient.setId(Long.parseLong(patientTokens[0]));
+                patient.setName(patientTokens[1]);
+                patient.setAge(Integer.parseInt(patientTokens[2]));
+                patient.setGender(Gender.valueOfCode(patientTokens[3]));
+                int preferredMaximumRoomCapacity = Integer.parseInt(lineTokens[3]);
+                patient.setPreferredMaximumRoomCapacity(preferredMaximumRoomCapacity == 0
+                        ? null : preferredMaximumRoomCapacity);
+                patientList.add(patient);
+
+                String[] admissionPartTokens = splitBySpace(lineTokens[2]);
+                if (admissionPartTokens.length % 2 != 1) {
+                }
+                int patientAdmissionPartListSize = Integer.parseInt(admissionPartTokens[0]);
+                if (admissionPartTokens.length != ((patientAdmissionPartListSize * 2) + 1)) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain " + ((patientAdmissionPartListSize * 2) + 1)
+                            + " number of tokens after 2th pipeline (|).");
+                }
+                int nextFirstNightIndex = firstNightIndex;
+                for (int j = 1; j < admissionPartTokens.length; j += 2) {
+                    long specialismId = Long.parseLong(admissionPartTokens[j]);
+                    int admissionPartNightListSize = Integer.parseInt(admissionPartTokens[j + 1]);
+                    if (nextFirstNightIndex >= nightListSize || admissionPartNightListSize == 0) {
+                        nextFirstNightIndex += admissionPartNightListSize;
+                        continue;
+                    }
+                    AdmissionPart admissionPart = new AdmissionPart();
+                    admissionPart.setId(admissionPartId);
+                    admissionPart.setPatient(patient);
+                    Specialism specialism = (specialismId == 0) ? null : idToSpecialismMap.get(specialismId);
+                    if (specialism == null) {
+                        throw new IllegalArgumentException("Read line (" + line
+                            + ") has a non existing specialismId (" + specialismId + ").");
+                    }
+                    admissionPart.setSpecialism(specialism);
+                    int admissionPartFirstNightIndex = nextFirstNightIndex;
+                    Night admissionPartFirstNight = indexToNightMap.get(admissionPartFirstNightIndex);
+                    if (admissionPartFirstNight == null) {
+                        throw new IllegalStateException(
+                                "The admissionPartFirstNight was not found for admissionPartFirstNightIndex("
+                                        + admissionPartFirstNightIndex + ").");
+                    }
+                    admissionPart.setFirstNight(admissionPartFirstNight);
+                    int admissionPartLastNightIndex = nextFirstNightIndex + admissionPartNightListSize - 1;
+                    // TODO Instead of ensureEnoughNights(lastNightIndex);
+                    // the official score function ignores any broken constraints after the planning horizon
+                    if (admissionPartLastNightIndex >= nightListSize) {
+                        admissionPartLastNightIndex = nightListSize - 1;
+                    }
+                    Night admissionPartLastNight = indexToNightMap.get(admissionPartLastNightIndex);
+                    if (admissionPartLastNight == null) {
+                        throw new IllegalStateException(
+                                "The admissionPartLastNight was not found for admissionPartLastNightIndex("
+                                        + admissionPartLastNightIndex + ").");
+                    }
+                    admissionPart.setLastNight(admissionPartLastNight);
+                    admissionPartList.add(admissionPart);
+                    admissionPartId++;
+                    nextFirstNightIndex += admissionPartNightListSize;
+                }
+                int admissionPartNightListSizeSum = nextFirstNightIndex - firstNightIndex;
+                if (patientNightListSize != admissionPartNightListSizeSum) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") has patientNightListSize (" + patientNightListSize
+                            + ") different from admissionPartNightListSizeSum(" + admissionPartNightListSizeSum + ")");
+                }
+
+                String[] requiredPatientEquipmentTokens = splitBySpace(lineTokens[4]);
+                if (requiredPatientEquipmentTokens.length != equipmentListSize) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain equal number of tokens ("
+                            + requiredPatientEquipmentTokens.length
+                            + ") as equipmentListSize (" + equipmentListSize + ") after 4th pipeline (|).");
+                }
+                List<RequiredPatientEquipment> requiredPatientEquipmentOfPatientList
+                        = new ArrayList<RequiredPatientEquipment>(equipmentListSize);
+                for (int j = 0; j < requiredPatientEquipmentTokens.length; j++) {
+                    int hasEquipment = Integer.parseInt(requiredPatientEquipmentTokens[j]);
+                    if (hasEquipment == 1) {
+                        RequiredPatientEquipment requiredPatientEquipment = new RequiredPatientEquipment();
+                        requiredPatientEquipment.setId(requiredPatientEquipmentId);
+                        requiredPatientEquipment.setPatient(patient);
+                        requiredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
+                        requiredPatientEquipmentOfPatientList.add(requiredPatientEquipment);
+                        requiredPatientEquipmentList.add(requiredPatientEquipment);
+                        requiredPatientEquipmentId++;
+                    } else if (hasEquipment != 0) {
+                        throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
+                    }
+                }
+                patient.setRequiredPatientEquipmentList(requiredPatientEquipmentOfPatientList);
+
+                String[] preferredPatientEquipmentTokens = splitBySpace(lineTokens[5]);
+                if (preferredPatientEquipmentTokens.length != equipmentListSize) {
+                    throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to contain equal number of tokens ("
+                            + preferredPatientEquipmentTokens.length
+                            + ") as equipmentListSize (" + equipmentListSize + ") after 5th pipeline (|).");
+                }
+                List<PreferredPatientEquipment> preferredPatientEquipmentOfPatientList
+                        = new ArrayList<PreferredPatientEquipment>(equipmentListSize);
+                for (int j = 0; j < preferredPatientEquipmentTokens.length; j++) {
+                    int hasEquipment = Integer.parseInt(preferredPatientEquipmentTokens[j]);
+                    if (hasEquipment == 1) {
+                        boolean alreadyRequired = (Integer.parseInt(requiredPatientEquipmentTokens[j]) == 1);
+                        // Official spec: if equipment is required
+                        // then a duplicate preffered constraint should be ignored 
+                        if (!alreadyRequired) {
+                            PreferredPatientEquipment preferredPatientEquipment = new PreferredPatientEquipment();
+                            preferredPatientEquipment.setId(preferredPatientEquipmentId);
+                            preferredPatientEquipment.setPatient(patient);
+                            preferredPatientEquipment.setEquipment(indexToEquipmentMap.get(j));
+                            preferredPatientEquipmentOfPatientList.add(preferredPatientEquipment);
+                            preferredPatientEquipmentList.add(preferredPatientEquipment);
+                            preferredPatientEquipmentId++;
+                        }
+                    } else if (hasEquipment != 0) {
+                        throw new IllegalArgumentException("Read line (" + line
+                            + ") is expected to have 0 or 1 hasEquipment (" + hasEquipment + ").");
+                    }
+                }
+                patient.setPreferredPatientEquipmentList(preferredPatientEquipmentOfPatientList);
+            }
+            patientAdmissionSchedule.setPatientList(patientList);
+            patientAdmissionSchedule.setAdmissionPartList(admissionPartList);
+            patientAdmissionSchedule.setRequiredPatientEquipmentList(requiredPatientEquipmentList);
+            patientAdmissionSchedule.setPreferredPatientEquipmentList(preferredPatientEquipmentList);
+        }
+
+//        /**
+//         * hack to make sure there are enough nights
+//         * @param lastNightIndex >= 0
+//         */
+//        private void ensureEnoughNights(int lastNightIndex) {
+//            List<Night> nightList = patientAdmissionSchedule.getNightList();
+//            if (lastNightIndex >= nightList.size()) {
+//                long nightId = nightList.size();
+//                for (int j = nightList.size(); j <= lastNightIndex; j++) {
+//                    Night night = new Night();
+//                    night.setId(nightId);
+//                    night.setIndex(j);
+//                    nightList.add(night);
+//                    indexToNightMap.put(j, night);
+//                    nightId++;
+//                }
+//            }
+//        }
+
+        // ************************************************************************
+        // Helper methods
+        // ************************************************************************
+
+        private String[] splitBySpace(String line) {
+            String[] lineTokens = line.split("\\ ");
+            return lineTokens;
+        }
+
+        private String[] splitBySpace(String line, int numberOfTokens) {
+            String[] lineTokens = line.split("\\ ");
+            if (lineTokens.length != numberOfTokens) {
+                throw new IllegalArgumentException("Read line (" + line
+                        + ") is expected to contain " +  numberOfTokens + " tokens seperated by a space ( ).");
+            }
+            return lineTokens;
+        }
+
+        private String[] splitByPipeline(String line, int numberOfTokens) {
+            String[] lineTokens = line.split("\\|");
+            if (lineTokens.length != numberOfTokens) {
+                throw new IllegalArgumentException("Read line (" + line
+                        + ") is expected to contain " +  numberOfTokens + " tokens seperated by a pipeline (|).");
+            }
+            for (int i = 0; i < lineTokens.length; i++) {
+                lineTokens[i] = lineTokens[i].trim();
+            }
+            return lineTokens;
+        }
+
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/AbstractTravelingTournamentApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/AbstractTravelingTournamentApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/AbstractTravelingTournamentApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,6 +1,8 @@
 package org.drools.planner.examples.travelingtournament.app;
 
 import org.drools.planner.examples.common.app.CommonApp;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.swingui.SolutionPanel;
 import org.drools.planner.examples.travelingtournament.swingui.TravelingTournamentPanel;
 

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/simple/SimpleTravelingTournamentApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/simple/SimpleTravelingTournamentApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/simple/SimpleTravelingTournamentApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -20,15 +20,15 @@
     }
 
     @Override
-    protected SolutionDao createSolutionDao() {
-        return new SimpleTravelingTournamentDaoImpl();
-    }
-
-    @Override
     protected Solver createSolver() {
         XmlSolverConfigurer configurer = new XmlSolverConfigurer();
         configurer.configure(SOLVER_CONFIG);
         return configurer.buildSolver();
     }
 
+    @Override
+    protected SolutionDao createSolutionDao() {
+        return new SimpleTravelingTournamentDaoImpl();
+    }
+
 }

Modified: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/smart/SmartTravelingTournamentApp.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/smart/SmartTravelingTournamentApp.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/app/smart/SmartTravelingTournamentApp.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -2,9 +2,13 @@
 
 import org.drools.planner.config.XmlSolverConfigurer;
 import org.drools.planner.core.Solver;
+import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
+import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
 import org.drools.planner.examples.common.persistence.SolutionDao;
 import org.drools.planner.examples.travelingtournament.app.AbstractTravelingTournamentApp;
 import org.drools.planner.examples.travelingtournament.persistence.smart.SmartTravelingTournamentDaoImpl;
+import org.drools.planner.examples.travelingtournament.persistence.smart.SmartTravelingTournamentSolutionExporter;
+import org.drools.planner.examples.travelingtournament.persistence.smart.SmartTravelingTournamentSolutionImporter;
 
 /**
  * @author Geoffrey De Smet
@@ -20,15 +24,25 @@
     }
 
     @Override
+    protected Solver createSolver() {
+        XmlSolverConfigurer configurer = new XmlSolverConfigurer();
+        configurer.configure(SOLVER_CONFIG);
+        return configurer.buildSolver();
+    }
+
+    @Override
     protected SolutionDao createSolutionDao() {
         return new SmartTravelingTournamentDaoImpl();
     }
 
     @Override
-    protected Solver createSolver() {
-        XmlSolverConfigurer configurer = new XmlSolverConfigurer();
-        configurer.configure(SOLVER_CONFIG);
-        return configurer.buildSolver();
+    protected AbstractSolutionImporter createSolutionImporter() {
+        return new SmartTravelingTournamentSolutionImporter();
     }
 
+    @Override
+    protected AbstractSolutionExporter createSolutionExporter() {
+        return new SmartTravelingTournamentSolutionExporter();
+    }
+
 }

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,115 +0,0 @@
-package org.drools.planner.examples.travelingtournament.persistence;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.drools.planner.examples.common.persistence.AbstractTxtInputConverter;
-import org.drools.planner.examples.common.persistence.SolutionDao;
-import org.drools.planner.examples.travelingtournament.domain.Day;
-import org.drools.planner.examples.travelingtournament.domain.Match;
-import org.drools.planner.examples.travelingtournament.domain.Team;
-import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public abstract class TravelingTournamentInputConverter extends AbstractTxtInputConverter {
-
-    protected TravelingTournamentInputConverter(SolutionDao solutionDao) {
-        super(solutionDao);
-    }
-
-    public abstract class TravelingTournamentInputBuilder extends TxtInputBuilder {
-
-        public Solution readSolution() throws IOException {
-            TravelingTournament travelingTournament = new TravelingTournament();
-            travelingTournament.setId(0L);
-            int n = readN();
-            List<Team> teamList = readTeamList(n);
-            travelingTournament.setTeamList(teamList);
-            List<Day> dayList = constructDayList(n);
-            travelingTournament.setDayList(dayList);
-            List<List<Integer>> outerDistanceList = readOuterDistanceList();
-            List<Match> matchList = constructMatchListAndSetDistancesInTeamList(teamList, outerDistanceList);
-            travelingTournament.setMatchList(matchList);
-            initializeMatchDays(travelingTournament);
-            return travelingTournament;
-        }
-
-        private int readN() throws IOException {
-            return Integer.parseInt(bufferedReader.readLine());
-        }
-
-        private List<Team> readTeamList(int n) throws IOException {
-            List<Team> teamList = new ArrayList<Team>();
-            for (int i = 0; i < n; i++) {
-                Team team = new Team();
-                team.setId((long) i);
-                team.setName(bufferedReader.readLine());
-                team.setDistanceToTeamMap(new HashMap<Team, Integer>());
-                teamList.add(team);
-            }
-            return teamList;
-        }
-
-        private List<List<Integer>> readOuterDistanceList() throws IOException {
-            List<List<Integer>> outerDistanceList = new ArrayList<List<Integer>>();
-            String line = bufferedReader.readLine();
-            while (line != null && !line.replaceAll("\\s+", "").equals("")) {
-                StringTokenizer tokenizer = new StringTokenizer(line.replaceAll("\\s+", " ").trim());
-                List<Integer> innerDistanceList = new ArrayList<Integer>();
-                while (tokenizer.hasMoreTokens()) {
-                    int distance = Integer.parseInt(tokenizer.nextToken());
-                    innerDistanceList.add(distance);
-                }
-                outerDistanceList.add(innerDistanceList);
-                line = bufferedReader.readLine();
-            }
-            return outerDistanceList;
-        }
-
-        private List<Day> constructDayList(int n) {
-            List<Day> dayList = new ArrayList<Day>();
-            int daySize = (n - 1) * 2; // Play vs each team (except itself) twice (home and away)
-            for (int i = 0; i < daySize; i++) {
-                Day day = new Day();
-                day.setId((long) i);
-                day.setIndex(i);
-                dayList.add(day);
-            }
-            return dayList;
-        }
-
-        private List<Match> constructMatchListAndSetDistancesInTeamList(List<Team> teamList, List<List<Integer>> outerDistanceList) {
-            List<Match> matchList = new ArrayList<Match>();
-            int i = 0;
-            long matchId = 0;
-            for (Team homeTeam : teamList) {
-                int j = 0;
-                for (Team awayTeam : teamList) {
-                    int distance = outerDistanceList.get(i).get(j);
-                    homeTeam.getDistanceToTeamMap().put(awayTeam, distance);
-                    if (i != j) {
-                        Match match = new Match();
-                        match.setId(matchId);
-                        matchId++;
-                        match.setHomeTeam(homeTeam);
-                        match.setAwayTeam(awayTeam);
-                        matchList.add(match);
-                    }
-                    j++;
-                }
-                i++;
-            }
-            return matchList;
-        }
-
-        protected abstract void initializeMatchDays(TravelingTournament travelingTournament);
-
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/TravelingTournamentSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,115 @@
+package org.drools.planner.examples.travelingtournament.persistence;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionImporter;
+import org.drools.planner.examples.common.persistence.SolutionDao;
+import org.drools.planner.examples.travelingtournament.domain.Day;
+import org.drools.planner.examples.travelingtournament.domain.Match;
+import org.drools.planner.examples.travelingtournament.domain.Team;
+import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public abstract class TravelingTournamentSolutionImporter extends AbstractTxtSolutionImporter {
+
+    protected TravelingTournamentSolutionImporter(SolutionDao solutionDao) {
+        super(solutionDao);
+    }
+
+    public abstract class TravelingTournamentInputBuilder extends TxtInputBuilder {
+
+        public Solution readSolution() throws IOException {
+            TravelingTournament travelingTournament = new TravelingTournament();
+            travelingTournament.setId(0L);
+            int n = readN();
+            List<Team> teamList = readTeamList(n);
+            travelingTournament.setTeamList(teamList);
+            List<Day> dayList = constructDayList(n);
+            travelingTournament.setDayList(dayList);
+            List<List<Integer>> outerDistanceList = readOuterDistanceList();
+            List<Match> matchList = constructMatchListAndSetDistancesInTeamList(teamList, outerDistanceList);
+            travelingTournament.setMatchList(matchList);
+            initializeMatchDays(travelingTournament);
+            return travelingTournament;
+        }
+
+        private int readN() throws IOException {
+            return Integer.parseInt(bufferedReader.readLine());
+        }
+
+        private List<Team> readTeamList(int n) throws IOException {
+            List<Team> teamList = new ArrayList<Team>();
+            for (int i = 0; i < n; i++) {
+                Team team = new Team();
+                team.setId((long) i);
+                team.setName(bufferedReader.readLine());
+                team.setDistanceToTeamMap(new HashMap<Team, Integer>());
+                teamList.add(team);
+            }
+            return teamList;
+        }
+
+        private List<List<Integer>> readOuterDistanceList() throws IOException {
+            List<List<Integer>> outerDistanceList = new ArrayList<List<Integer>>();
+            String line = bufferedReader.readLine();
+            while (line != null && !line.replaceAll("\\s+", "").equals("")) {
+                StringTokenizer tokenizer = new StringTokenizer(line.replaceAll("\\s+", " ").trim());
+                List<Integer> innerDistanceList = new ArrayList<Integer>();
+                while (tokenizer.hasMoreTokens()) {
+                    int distance = Integer.parseInt(tokenizer.nextToken());
+                    innerDistanceList.add(distance);
+                }
+                outerDistanceList.add(innerDistanceList);
+                line = bufferedReader.readLine();
+            }
+            return outerDistanceList;
+        }
+
+        private List<Day> constructDayList(int n) {
+            List<Day> dayList = new ArrayList<Day>();
+            int daySize = (n - 1) * 2; // Play vs each team (except itself) twice (home and away)
+            for (int i = 0; i < daySize; i++) {
+                Day day = new Day();
+                day.setId((long) i);
+                day.setIndex(i);
+                dayList.add(day);
+            }
+            return dayList;
+        }
+
+        private List<Match> constructMatchListAndSetDistancesInTeamList(List<Team> teamList, List<List<Integer>> outerDistanceList) {
+            List<Match> matchList = new ArrayList<Match>();
+            int i = 0;
+            long matchId = 0;
+            for (Team homeTeam : teamList) {
+                int j = 0;
+                for (Team awayTeam : teamList) {
+                    int distance = outerDistanceList.get(i).get(j);
+                    homeTeam.getDistanceToTeamMap().put(awayTeam, distance);
+                    if (i != j) {
+                        Match match = new Match();
+                        match.setId(matchId);
+                        matchId++;
+                        match.setHomeTeam(homeTeam);
+                        match.setAwayTeam(awayTeam);
+                        matchList.add(match);
+                    }
+                    j++;
+                }
+                i++;
+            }
+            return matchList;
+        }
+
+        protected abstract void initializeMatchDays(TravelingTournament travelingTournament);
+
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,39 +0,0 @@
-package org.drools.planner.examples.travelingtournament.persistence.simple;
-
-import java.util.List;
-
-import org.drools.planner.examples.travelingtournament.domain.Day;
-import org.drools.planner.examples.travelingtournament.domain.Match;
-import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
-import org.drools.planner.examples.travelingtournament.persistence.TravelingTournamentInputConverter;
-
-/**
- * @author Geoffrey De Smet
- */
-public class SimpleTravelingTournamentInputConverter extends TravelingTournamentInputConverter {
-
-    public static void main(String[] args) {
-        new SimpleTravelingTournamentInputConverter().convertAll();
-    }
-
-    public SimpleTravelingTournamentInputConverter() {
-        super(new SimpleTravelingTournamentDaoImpl());
-    }
-
-    public TxtInputBuilder createTxtInputBuilder() {
-        return new SimpleTravelingTournament();
-    }
-
-    public class SimpleTravelingTournament extends TravelingTournamentInputBuilder {
-
-        protected void initializeMatchDays(TravelingTournament travelingTournament) {
-            List<Match> matchList = travelingTournament.getMatchList();
-            List<Day> dayList = travelingTournament.getDayList();
-            for (Match match : matchList) {
-                match.setDay(dayList.get(0));
-            }
-        }
-
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/simple/SimpleTravelingTournamentSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,39 @@
+package org.drools.planner.examples.travelingtournament.persistence.simple;
+
+import java.util.List;
+
+import org.drools.planner.examples.travelingtournament.domain.Day;
+import org.drools.planner.examples.travelingtournament.domain.Match;
+import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
+import org.drools.planner.examples.travelingtournament.persistence.TravelingTournamentSolutionImporter;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class SimpleTravelingTournamentSolutionImporter extends TravelingTournamentSolutionImporter {
+
+    public static void main(String[] args) {
+        new SimpleTravelingTournamentSolutionImporter().convertAll();
+    }
+
+    public SimpleTravelingTournamentSolutionImporter() {
+        super(new SimpleTravelingTournamentDaoImpl());
+    }
+
+    public TxtInputBuilder createTxtInputBuilder() {
+        return new SimpleTravelingTournament();
+    }
+
+    public class SimpleTravelingTournament extends TravelingTournamentInputBuilder {
+
+        protected void initializeMatchDays(TravelingTournament travelingTournament) {
+            List<Match> matchList = travelingTournament.getMatchList();
+            List<Day> dayList = travelingTournament.getDayList();
+            for (Match match : matchList) {
+                match.setDay(dayList.get(0));
+            }
+        }
+
+    }
+
+}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentInputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentInputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentInputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,73 +0,0 @@
-package org.drools.planner.examples.travelingtournament.persistence.smart;
-
-import java.util.List;
-
-import org.drools.planner.examples.travelingtournament.domain.Match;
-import org.drools.planner.examples.travelingtournament.domain.Team;
-import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
-import org.drools.planner.examples.travelingtournament.persistence.TravelingTournamentInputConverter;
-
-/**
- * @author Geoffrey De Smet
- */
-public class SmartTravelingTournamentInputConverter extends TravelingTournamentInputConverter {
-
-    public static void main(String[] args) {
-        new SmartTravelingTournamentInputConverter().convertAll();
-    }
-
-    public SmartTravelingTournamentInputConverter() {
-        super(new SmartTravelingTournamentDaoImpl());
-    }
-
-    public TxtInputBuilder createTxtInputBuilder() {
-        return new SmartTravelingTournamentInputBuilder();
-    }
-
-    public class SmartTravelingTournamentInputBuilder extends TravelingTournamentInputBuilder {
-
-        /**
-         * Canonical pattern initialization (see papers).
-         * @param travelingTournament the traveling tournament
-         */
-        protected void initializeMatchDays(TravelingTournament travelingTournament) {
-            int n = travelingTournament.getN();
-            for (int i = 0; i < (n - 1); i++) {
-                initializeMatchPairs(travelingTournament, (n - 1), i, i);
-            }
-            for (int startA = 1, startB = (n - 2); startA < (n - 1); startA += 2, startB -= 2) {
-                for (int i = 0; i < (n - 1); i++) {
-                    int a = (startA + i) % (n - 1);
-                    int b = (startB + i) % (n - 1);
-                    initializeMatchPairs(travelingTournament, a, b, i);
-                }
-            }
-        }
-
-        private void initializeMatchPairs(TravelingTournament travelingTournament, int a, int b, int i) {
-            if ((i % 6) >= 3) { // Might not be a 100% the canonical pattern
-                // Swap them
-                int oldA = a;
-                a = b;
-                b = oldA;
-            }
-            Team aTeam = travelingTournament.getTeamList().get(a);
-            Team bTeam = travelingTournament.getTeamList().get(b);
-            Match m1 = findMatch(travelingTournament.getMatchList(), aTeam, bTeam);
-            m1.setDay(travelingTournament.getDayList().get(i));
-            Match m2 = findMatch(travelingTournament.getMatchList(), bTeam, aTeam);
-            m2.setDay(travelingTournament.getDayList().get(i + travelingTournament.getN() - 1));
-        }
-
-        private Match findMatch(List<Match> matchList, Team homeTeam, Team awayTeam) {
-            for (Match match : matchList) {
-                if (match.getHomeTeam().equals(homeTeam) && match.getAwayTeam().equals(awayTeam)) {
-                    return match;
-                }
-            }
-            throw new IllegalStateException("Nothing found for: " + homeTeam + " and " + awayTeam);
-        }
-
-    }
-
-}

Deleted: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentOutputConverter.java
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentOutputConverter.java	2010-04-02 16:24:22 UTC (rev 32371)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentOutputConverter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -1,84 +0,0 @@
-package org.drools.planner.examples.travelingtournament.persistence.smart;
-
-import java.io.IOException;
-
-import org.drools.planner.examples.common.persistence.AbstractTxtOutputConverter;
-import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
-import org.drools.planner.examples.travelingtournament.domain.Team;
-import org.drools.planner.examples.travelingtournament.domain.Match;
-import org.drools.planner.examples.travelingtournament.domain.Day;
-import org.drools.planner.core.solution.Solution;
-
-/**
- * @author Geoffrey De Smet
- */
-public class SmartTravelingTournamentOutputConverter extends AbstractTxtOutputConverter {
-
-    private static final String OUTPUT_FILE_SUFFIX = ".trick.txt";
-
-    public static void main(String[] args) {
-        new SmartTravelingTournamentOutputConverter().convertAll();
-    }
-
-    public SmartTravelingTournamentOutputConverter() {
-        super(new SmartTravelingTournamentDaoImpl());
-    }
-
-    @Override
-    protected String getOutputFileSuffix() {
-        return OUTPUT_FILE_SUFFIX;
-    }
-
-    public TxtOutputBuilder createTxtOutputBuilder() {
-        return new SmartTravelingTournamentOutputBuilder();
-    }
-
-    public class SmartTravelingTournamentOutputBuilder extends TxtOutputBuilder {
-
-        private TravelingTournament travelingTournament;
-
-        public void setSolution(Solution solution) {
-            travelingTournament = (TravelingTournament) solution;
-        }
-
-        public void writeSolution() throws IOException {
-            int maximumTeamNameLength = 0;
-            for (Team team : travelingTournament.getTeamList()) {
-                if (team.getName().length() > maximumTeamNameLength) {
-                    maximumTeamNameLength = team.getName().length();
-                }
-            }
-            for (Team team : travelingTournament.getTeamList()) {
-                bufferedWriter.write(String.format("%-" + (maximumTeamNameLength + 3) + "s", team.getName()));
-            }
-            bufferedWriter.write("\n");
-            for (Team team : travelingTournament.getTeamList()) {
-                bufferedWriter.write(String.format("%-" + (maximumTeamNameLength + 3) + "s", team.getName().replaceAll("[\\w\\d]", "-")));
-            }
-            bufferedWriter.write("\n");
-            for (Day day : travelingTournament.getDayList()) {
-                for (Team team : travelingTournament.getTeamList()) {
-                    // this could be put in a hashmap first for performance
-                    boolean opponentIsHome = false;
-                    Team opponentTeam = null;
-                    for (Match match : travelingTournament.getMatchList()) {
-                        if (match.getDay().equals(day)) {
-                            if (match.getHomeTeam().equals(team)) {
-                                opponentIsHome = false;
-                                opponentTeam = match.getAwayTeam();
-                            } else  if (match.getAwayTeam().equals(team)) {
-                                opponentIsHome = true;
-                                opponentTeam = match.getHomeTeam();
-                            }
-                        }
-                    }
-                    String opponentName = (opponentIsHome ? "@" : "") + opponentTeam.getName();
-                    bufferedWriter.write(String.format("%-" + (maximumTeamNameLength + 3) + "s", opponentName));
-                }
-                bufferedWriter.write("\n");
-            }
-        }
-
-    }
-
-}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionExporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentOutputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionExporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionExporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,84 @@
+package org.drools.planner.examples.travelingtournament.persistence.smart;
+
+import java.io.IOException;
+
+import org.drools.planner.examples.common.persistence.AbstractTxtSolutionExporter;
+import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
+import org.drools.planner.examples.travelingtournament.domain.Team;
+import org.drools.planner.examples.travelingtournament.domain.Match;
+import org.drools.planner.examples.travelingtournament.domain.Day;
+import org.drools.planner.core.solution.Solution;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class SmartTravelingTournamentSolutionExporter extends AbstractTxtSolutionExporter {
+
+    private static final String OUTPUT_FILE_SUFFIX = ".trick.txt";
+
+    public static void main(String[] args) {
+        new SmartTravelingTournamentSolutionExporter().convertAll();
+    }
+
+    public SmartTravelingTournamentSolutionExporter() {
+        super(new SmartTravelingTournamentDaoImpl());
+    }
+
+    @Override
+    protected String getOutputFileSuffix() {
+        return OUTPUT_FILE_SUFFIX;
+    }
+
+    public TxtOutputBuilder createTxtOutputBuilder() {
+        return new SmartTravelingTournamentOutputBuilder();
+    }
+
+    public class SmartTravelingTournamentOutputBuilder extends TxtOutputBuilder {
+
+        private TravelingTournament travelingTournament;
+
+        public void setSolution(Solution solution) {
+            travelingTournament = (TravelingTournament) solution;
+        }
+
+        public void writeSolution() throws IOException {
+            int maximumTeamNameLength = 0;
+            for (Team team : travelingTournament.getTeamList()) {
+                if (team.getName().length() > maximumTeamNameLength) {
+                    maximumTeamNameLength = team.getName().length();
+                }
+            }
+            for (Team team : travelingTournament.getTeamList()) {
+                bufferedWriter.write(String.format("%-" + (maximumTeamNameLength + 3) + "s", team.getName()));
+            }
+            bufferedWriter.write("\n");
+            for (Team team : travelingTournament.getTeamList()) {
+                bufferedWriter.write(String.format("%-" + (maximumTeamNameLength + 3) + "s", team.getName().replaceAll("[\\w\\d]", "-")));
+            }
+            bufferedWriter.write("\n");
+            for (Day day : travelingTournament.getDayList()) {
+                for (Team team : travelingTournament.getTeamList()) {
+                    // this could be put in a hashmap first for performance
+                    boolean opponentIsHome = false;
+                    Team opponentTeam = null;
+                    for (Match match : travelingTournament.getMatchList()) {
+                        if (match.getDay().equals(day)) {
+                            if (match.getHomeTeam().equals(team)) {
+                                opponentIsHome = false;
+                                opponentTeam = match.getAwayTeam();
+                            } else  if (match.getAwayTeam().equals(team)) {
+                                opponentIsHome = true;
+                                opponentTeam = match.getHomeTeam();
+                            }
+                        }
+                    }
+                    String opponentName = (opponentIsHome ? "@" : "") + opponentTeam.getName();
+                    bufferedWriter.write(String.format("%-" + (maximumTeamNameLength + 3) + "s", opponentName));
+                }
+                bufferedWriter.write("\n");
+            }
+        }
+
+    }
+
+}

Copied: labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionImporter.java (from rev 32306, labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentInputConverter.java)
===================================================================
--- labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionImporter.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-planner/drools-planner-examples/src/main/java/org/drools/planner/examples/travelingtournament/persistence/smart/SmartTravelingTournamentSolutionImporter.java	2010-04-02 19:37:03 UTC (rev 32372)
@@ -0,0 +1,73 @@
+package org.drools.planner.examples.travelingtournament.persistence.smart;
+
+import java.util.List;
+
+import org.drools.planner.examples.travelingtournament.domain.Match;
+import org.drools.planner.examples.travelingtournament.domain.Team;
+import org.drools.planner.examples.travelingtournament.domain.TravelingTournament;
+import org.drools.planner.examples.travelingtournament.persistence.TravelingTournamentSolutionImporter;
+
+/**
+ * @author Geoffrey De Smet
+ */
+public class SmartTravelingTournamentSolutionImporter extends TravelingTournamentSolutionImporter {
+
+    public static void main(String[] args) {
+        new SmartTravelingTournamentSolutionImporter().convertAll();
+    }
+
+    public SmartTravelingTournamentSolutionImporter() {
+        super(new SmartTravelingTournamentDaoImpl());
+    }
+
+    public TxtInputBuilder createTxtInputBuilder() {
+        return new SmartTravelingTournamentInputBuilder();
+    }
+
+    public class SmartTravelingTournamentInputBuilder extends TravelingTournamentInputBuilder {
+
+        /**
+         * Canonical pattern initialization (see papers).
+         * @param travelingTournament the traveling tournament
+         */
+        protected void initializeMatchDays(TravelingTournament travelingTournament) {
+            int n = travelingTournament.getN();
+            for (int i = 0; i < (n - 1); i++) {
+                initializeMatchPairs(travelingTournament, (n - 1), i, i);
+            }
+            for (int startA = 1, startB = (n - 2); startA < (n - 1); startA += 2, startB -= 2) {
+                for (int i = 0; i < (n - 1); i++) {
+                    int a = (startA + i) % (n - 1);
+                    int b = (startB + i) % (n - 1);
+                    initializeMatchPairs(travelingTournament, a, b, i);
+                }
+            }
+        }
+
+        private void initializeMatchPairs(TravelingTournament travelingTournament, int a, int b, int i) {
+            if ((i % 6) >= 3) { // Might not be a 100% the canonical pattern
+                // Swap them
+                int oldA = a;
+                a = b;
+                b = oldA;
+            }
+            Team aTeam = travelingTournament.getTeamList().get(a);
+            Team bTeam = travelingTournament.getTeamList().get(b);
+            Match m1 = findMatch(travelingTournament.getMatchList(), aTeam, bTeam);
+            m1.setDay(travelingTournament.getDayList().get(i));
+            Match m2 = findMatch(travelingTournament.getMatchList(), bTeam, aTeam);
+            m2.setDay(travelingTournament.getDayList().get(i + travelingTournament.getN() - 1));
+        }
+
+        private Match findMatch(List<Match> matchList, Team homeTeam, Team awayTeam) {
+            for (Match match : matchList) {
+                if (match.getHomeTeam().equals(homeTeam) && match.getAwayTeam().equals(awayTeam)) {
+                    return match;
+                }
+            }
+            throw new IllegalStateException("Nothing found for: " + homeTeam + " and " + awayTeam);
+        }
+
+    }
+
+}



More information about the jboss-svn-commits mailing list