diff --git a/rtd_yeastx/.classpath b/rtd_yeastx/.classpath
index 4f59ee85a035bcfdf1e0ebda06ea56bac6407856..6dd1e778a74d21fa8ae98dadc7c7b75e43abc82b 100644
--- a/rtd_yeastx/.classpath
+++ b/rtd_yeastx/.classpath
@@ -7,7 +7,6 @@
 	<classpathentry kind="lib" path="/libraries/commons-lang/commons-lang.jar" sourcepath="/libraries/commons-lang/src.zip"/>
 	<classpathentry kind="lib" path="/libraries/cisd-base/cisd-base.jar" sourcepath="/libraries/cisd-base/cisd-base-src.zip"/>
 	<classpathentry kind="lib" path="/libraries/postgresql/postgresql.jar" sourcepath="/libraries/postgresql/postgresql-src.zip"/>
-	<classpathentry kind="lib" path="/libraries/eodsql/eodsql.jar" sourcepath="/libraries/eodsql/eodsql_src.zip"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/datastore_server"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/openbis"/>
@@ -19,5 +18,7 @@
 	<classpathentry kind="lib" path="/libraries/cisd-base/cisd-base-test.jar" sourcepath="/libraries/cisd-base/cisd-base-src.zip"/>
 	<classpathentry kind="lib" path="/libraries/mail/mail.jar"/>
 	<classpathentry kind="lib" path="/libraries/restrictionchecker/restrictions.jar"/>
+	<classpathentry kind="lib" path="/libraries/spring/spring.jar" sourcepath="/libraries/spring/src.jar"/>
+	<classpathentry kind="lib" path="/libraries/eodsql/eodsql.jar" sourcepath="/libraries/eodsql/eodsql_src.zip"/>
 	<classpathentry kind="output" path="targets/classes"/>
 </classpath>
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/DBFactory.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/DBUtils.java
similarity index 72%
rename from rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/DBFactory.java
rename to rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/DBUtils.java
index e3ad8353745f533e576d6d1a612bfe2792618cb6..cca5144be55435c39f0c6f969d21310bf24e3028 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/DBFactory.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/DBUtils.java
@@ -16,20 +16,19 @@
 
 package ch.systemsx.cisd.yeastx.db;
 
-import java.sql.Connection;
-import java.sql.SQLException;
-
 import net.lemnik.eodsql.QueryTool;
+import net.lemnik.eodsql.TransactionQuery;
 
 import ch.systemsx.cisd.dbmigration.DBMigrationEngine;
 import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
 
 /**
- * Factory for database connections.
+ * Database utilities. Call {@link #init(DatabaseConfigurationContext)} before working with the
+ * database.
  * 
  * @author Bernd Rinn
  */
-public class DBFactory
+public class DBUtils
 {
     /** Current version of the database. */
     public static final String DATABASE_VERSION = "001";
@@ -39,21 +38,6 @@ public class DBFactory
         QueryTool.getTypeMap().put(float[].class, new FloatArrayMapper());
     }
 
-    private final DatabaseConfigurationContext context;
-
-    public DBFactory(DatabaseConfigurationContext context)
-    {
-        this.context = context;
-        DBMigrationEngine.createOrMigrateDatabaseAndGetScriptProvider(context, DATABASE_VERSION);
-    }
-
-    public Connection getConnection() throws SQLException
-    {
-        final Connection conn = context.getDataSource().getConnection();
-        conn.setAutoCommit(false);
-        return conn;
-    }
-
     public static DatabaseConfigurationContext createDefaultDBContext()
     {
         final DatabaseConfigurationContext context = new DatabaseConfigurationContext();
@@ -67,11 +51,36 @@ public class DBFactory
     }
 
     /**
-     * Returns the data access object for the generic tables of the data mart.
+     * Checks the database specified by <var>context</var> and migrates it to the current version if
+     * necessary.
+     */
+    public static void init(DatabaseConfigurationContext context)
+    {
+        DBMigrationEngine.createOrMigrateDatabaseAndGetScriptProvider(context, DATABASE_VERSION);
+    }
+
+    /**
+     * Rolls backs and closes the given <var>transactionOrNull</var>, if it is not <code>null</code>
+     * .
+     */
+    public static void rollbackAndClose(TransactionQuery transactionOrNull)
+    {
+        if (transactionOrNull != null)
+        {
+            transactionOrNull.rollback();
+            transactionOrNull.close();
+        }
+    }
+
+    /**
+     * Closes the given <var>transactionOrNull</var>, if it is not <code>null</code> .
      */
-    public static IGenericDAO getDAO(Connection conn)
+    public static void close(TransactionQuery transactionOrNull)
     {
-        return QueryTool.getQuery(conn, IGenericDAO.class);
+        if (transactionOrNull != null)
+        {
+            transactionOrNull.close();
+        }
     }
 
     /**
@@ -84,7 +93,8 @@ public class DBFactory
         DMSampleDTO sample = dao.getSampleByPermId(dataSet.getSample().getPermId());
         if (sample == null)
         {
-            DMExperimentDTO experiment = dao.getExperimentByPermId(dataSet.getExperiment().getPermId());
+            DMExperimentDTO experiment =
+                    dao.getExperimentByPermId(dataSet.getExperiment().getPermId());
             if (experiment == null)
             {
                 experiment = dataSet.getExperiment();
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/IGenericDAO.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/IGenericDAO.java
index 04e25d50e164bd8e9edfe7c58a8e948c67d840e2..0faa99e2ba33e01027a4cf651e06737535a080b8 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/IGenericDAO.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/db/IGenericDAO.java
@@ -16,15 +16,15 @@
 
 package ch.systemsx.cisd.yeastx.db;
 
-import net.lemnik.eodsql.BaseQuery;
 import net.lemnik.eodsql.Select;
+import net.lemnik.eodsql.TransactionQuery;
 
 /**
  * Interface for the "generic" methods (i.e. experiment, sample and data set).
  * 
  * @author Bernd Rinn
  */
-public interface IGenericDAO extends BaseQuery
+public interface IGenericDAO extends TransactionQuery
 {
 
     @Select("select * from EXPERIMENTS where PERM_ID = ?{1}")
@@ -39,6 +39,9 @@ public interface IGenericDAO extends BaseQuery
     @Select("select * from SAMPLES where PERM_ID = ?{1}")
     public DMSampleDTO getSampleByPermId(String samplePermId);
 
+    @Select("select DS.* from DATA_SETS DS JOIN SAMPLES S on DS.SAMP_ID = S.ID where S.PERM_ID = ?{1}")
+    public DMDataSetDTO[] listDataSetsForSample(String samplePermId);
+
     @Select("select * from SAMPLES where ID = ?{1}")
     public DMSampleDTO getSampleById(long id);
 
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/EICML2Database.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/EICML2Database.java
index e82fe396aaa1af195a5411cc2476c4c8bdd5e858..d4ee22aa905b2d68b84fe047d30636f534a94714 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/EICML2Database.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/EICML2Database.java
@@ -18,19 +18,20 @@ package ch.systemsx.cisd.yeastx.eicml;
 
 import java.io.File;
 import java.io.IOException;
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.sql.DataSource;
 import javax.xml.parsers.ParserConfigurationException;
 
 import net.lemnik.eodsql.QueryTool;
+import net.lemnik.eodsql.TransactionQuery;
 
 import org.xml.sax.SAXException;
 
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
-import ch.systemsx.cisd.yeastx.db.DBFactory;
+import ch.systemsx.cisd.yeastx.db.DBUtils;
 import ch.systemsx.cisd.yeastx.db.DMDataSetDTO;
 import ch.systemsx.cisd.yeastx.eicml.EICMLParser.IChromatogramObserver;
 import ch.systemsx.cisd.yeastx.eicml.EICMLParser.IMSRunObserver;
@@ -45,11 +46,6 @@ public class EICML2Database
 
     private final static int CHROMATOGRAM_BATCH_SIZE = 100;
 
-    public static IEICMSRunDAO getDAO(Connection conn)
-    {
-        return QueryTool.getQuery(conn, IEICMSRunDAO.class);
-    }
-
     private static void addChromatograms(IEICMSRunDAO dao, long eicMLId,
             List<ChromatogramDTO> chromatograms, int threshold)
     {
@@ -60,19 +56,26 @@ public class EICML2Database
         }
     }
 
+    private final IEICMSRunDAO dao;
+
+    public EICML2Database(DataSource datasource)
+    {
+        this.dao = QueryTool.getQuery(datasource, IEICMSRunDAO.class);
+    }
+
     /**
      * Method for uploading an <var>eicMLFile</var> to the database.
      */
-    public static void uploadEicMLFile(final Connection conn, final File eicMLFile,
-            final DMDataSetDTO dataSet) throws SQLException
+    public void uploadEicMLFile(final File eicMLFile, final DMDataSetDTO dataSet)
     {
         final long[] eicMLId = new long[1];
         final List<ChromatogramDTO> chromatograms =
                 new ArrayList<ChromatogramDTO>(CHROMATOGRAM_BATCH_SIZE);
+        TransactionQuery transaction = null;
         try
         {
-            DBFactory.createDataSet(DBFactory.getDAO(conn), dataSet);
-            final IEICMSRunDAO dao = getDAO(conn);
+            transaction = dao;
+            DBUtils.createDataSet(dao, dataSet);
             new EICMLParser(eicMLFile.getPath(), new IMSRunObserver()
                 {
                     public void observe(EICMSRunDTO run)
@@ -94,17 +97,11 @@ public class EICML2Database
                     }
                 });
             addChromatograms(dao, eicMLId[0], chromatograms, 1);
-            conn.commit();
+            transaction.close(true);
         } catch (Throwable th)
         {
-            conn.rollback();
-            if (th instanceof SQLException)
-            {
-                throw (SQLException) th;
-            } else
-            {
-                throw CheckedExceptionTunnel.wrapIfNecessary(th);
-            }
+            DBUtils.rollbackAndClose(transaction);
+            throw CheckedExceptionTunnel.wrapIfNecessary(th);
         }
     }
 
@@ -112,20 +109,15 @@ public class EICML2Database
             IOException, SQLException
     {
         final long start = System.currentTimeMillis();
-        final Connection conn = new DBFactory(DBFactory.createDefaultDBContext()).getConnection();
-        try
-        {
-            final String dir = args[0];
-            int permId = 0;
-            for (String f : new File(dir).list(new EICMLFilenameFilter()))
-            {
-                uploadEicMLFile(conn, new File(dir, f), new DMDataSetDTO(
-                        Integer.toString(++permId), "sample1", "the sample name", "experiment1",
-                        "the experiment name"));
-            }
-        } finally
+        final EICML2Database eicML2Database =
+                new EICML2Database(DBUtils.createDefaultDBContext().getDataSource());
+        final String dir = args[0];
+        int permId = 0;
+        for (String f : new File(dir).list(new EICMLFilenameFilter()))
         {
-            conn.close();
+            eicML2Database.uploadEicMLFile(new File(dir, f), new DMDataSetDTO(
+                    Integer.toString(++permId), "sample1", "the sample name", "experiment1",
+                    "the experiment name"));
         }
         System.out.println((System.currentTimeMillis() - start) / 1000.0);
     }
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/IEICMSRunDAO.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/IEICMSRunDAO.java
index 7fff59b2f0fb08a65c2d40cc1f87b6c0c71b8c6d..f11191925f3c343b3983bba1628e6730a1af2787 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/IEICMSRunDAO.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/IEICMSRunDAO.java
@@ -18,7 +18,8 @@ package ch.systemsx.cisd.yeastx.eicml;
 
 import java.util.List;
 
-import net.lemnik.eodsql.BaseQuery;
+import ch.systemsx.cisd.yeastx.db.IGenericDAO;
+
 import net.lemnik.eodsql.DataIterator;
 import net.lemnik.eodsql.Select;
 import net.lemnik.eodsql.Update;
@@ -28,7 +29,7 @@ import net.lemnik.eodsql.Update;
  * 
  * @author Bernd Rinn
  */
-public interface IEICMSRunDAO extends BaseQuery
+public interface IEICMSRunDAO extends IGenericDAO
 {
     final String ALL_EIC_MSRUN_COLUMNS =
             "EIC_MS_RUNS.ID, EIC_MS_RUNS.EXPE_ID, EIC_MS_RUNS.SAMP_ID, EIC_MS_RUNS.DS_ID, "
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/ListChromatogramLabels.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/ListChromatogramLabels.java
index e5b50a783bdc0a89b65b606ab3dbac6667ba6ad9..26766eb781758431b71a40dbfcdf686e5caadaea 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/ListChromatogramLabels.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/eicml/ListChromatogramLabels.java
@@ -16,12 +16,14 @@
 
 package ch.systemsx.cisd.yeastx.eicml;
 
-import java.sql.Connection;
 import java.sql.SQLException;
 
-import ch.systemsx.cisd.yeastx.db.DBFactory;
-
 import net.lemnik.eodsql.DataIterator;
+import net.lemnik.eodsql.QueryTool;
+import net.lemnik.eodsql.TransactionQuery;
+
+import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
+import ch.systemsx.cisd.yeastx.db.DBUtils;
 
 /**
  * A method for listing all chromatogram labels of all runs.
@@ -33,10 +35,13 @@ public class ListChromatogramLabels
 
     public static void main(String[] args) throws SQLException
     {
-        final Connection conn = new DBFactory(DBFactory.createDefaultDBContext()).getConnection();
+        final DatabaseConfigurationContext context = DBUtils.createDefaultDBContext();
+        DBUtils.init(context);
+        TransactionQuery transaction = null;
         try
         {
-            final IEICMSRunDAO dao = EICML2Database.getDAO(conn);
+            final IEICMSRunDAO dao = QueryTool.getQuery(context.getDataSource(), IEICMSRunDAO.class);
+            transaction = dao;
             if (args.length > 0)
             {
                 for (String fn : args)
@@ -54,7 +59,7 @@ public class ListChromatogramLabels
             }
         } finally
         {
-            conn.close();
+            DBUtils.close(transaction);
         }
     }
 
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/ML2DatabaseUploader.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/ML2DatabaseUploader.java
index b9178b0da466fda78a2c936232920701d09e4c66..83d63f7dac025fed0b49c8576bb7c93273d28ee2 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/ML2DatabaseUploader.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/etl/ML2DatabaseUploader.java
@@ -17,7 +17,6 @@
 package ch.systemsx.cisd.yeastx.etl;
 
 import java.io.File;
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Properties;
 import java.util.Set;
@@ -32,7 +31,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
-import ch.systemsx.cisd.yeastx.db.DBFactory;
+import ch.systemsx.cisd.yeastx.db.DBUtils;
 import ch.systemsx.cisd.yeastx.db.DMDataSetDTO;
 import ch.systemsx.cisd.yeastx.eicml.EICML2Database;
 import ch.systemsx.cisd.yeastx.fiaml.FIAML2Database;
@@ -47,8 +46,10 @@ public class ML2DatabaseUploader
 {
     private static final String DATABASE_PROPERTIES_PREFIX = "database.";
 
-    private final Connection connection;
-
+    private final EICML2Database eicML2Database;
+    
+    private final FIAML2Database fiaML2Database;
+    
     private final String uniqueSampleNamePropertyCode;
 
     private final String uniqueExperimentNamePropertyCode;
@@ -58,28 +59,17 @@ public class ML2DatabaseUploader
         final Properties dbProps =
                 ExtendedProperties.getSubset(properties, DATABASE_PROPERTIES_PREFIX, true);
         final DatabaseConfigurationContext dbContext =
-                (dbProps.isEmpty() ? DBFactory.createDefaultDBContext() : BeanUtils.createBean(
+                (dbProps.isEmpty() ? DBUtils.createDefaultDBContext() : BeanUtils.createBean(
                         DatabaseConfigurationContext.class, dbProps));
-        this.connection = getDatabaseConnection(dbContext);
+        DBUtils.init(dbContext);
+        this.eicML2Database = new EICML2Database(dbContext.getDataSource());
+        this.fiaML2Database = new FIAML2Database(dbContext.getDataSource());
         this.uniqueExperimentNamePropertyCode =
                 DatasetMappingResolver.getUniqueExperimentNamePropertyCode(properties);
         this.uniqueSampleNamePropertyCode =
                 DatasetMappingResolver.getUniqueSampleNamePropertyCode(properties);
     }
 
-    private static Connection getDatabaseConnection(DatabaseConfigurationContext dbContext)
-            throws EnvironmentFailureException
-    {
-        try
-        {
-            return new DBFactory(dbContext).getConnection();
-        } catch (SQLException e)
-        {
-            throw EnvironmentFailureException.fromTemplate(e,
-                    "Cannot connect to the database which stores transformed mzXML files.");
-        }
-    }
-
     /** uploads files with recognized extensions to the additional database */
     public void upload(File dataSet, DataSetInformation dataSetInformation)
             throws EnvironmentFailureException
@@ -111,14 +101,14 @@ public class ML2DatabaseUploader
             throws SQLException
     {
         DMDataSetDTO openbisBacklink = createBacklink(dataSetInformation);
-        EICML2Database.uploadEicMLFile(connection, dataSet, openbisBacklink);
+        eicML2Database.uploadEicMLFile(dataSet, openbisBacklink);
     }
 
     private void translateFIA(File dataSet, DataSetInformation dataSetInformation)
             throws SQLException
     {
         DMDataSetDTO openbisBacklink = createBacklink(dataSetInformation);
-        FIAML2Database.uploadFiaMLFile(connection, dataSet, openbisBacklink);
+        fiaML2Database.uploadFiaMLFile(dataSet, openbisBacklink);
     }
 
     private DMDataSetDTO createBacklink(DataSetInformation dataSetInformation)
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/FIAML2Database.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/FIAML2Database.java
index 2d0db836a53216d554b89c58109f54845ab86459..fdfffd19bcf79e89b9dfc8ee6165f6a5d3702d3d 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/FIAML2Database.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/FIAML2Database.java
@@ -17,14 +17,18 @@
 package ch.systemsx.cisd.yeastx.fiaml;
 
 import java.io.File;
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Iterator;
 
+import javax.sql.DataSource;
+
 import net.lemnik.eodsql.QueryTool;
+import net.lemnik.eodsql.TransactionQuery;
+
+import org.springframework.dao.DataAccessException;
 
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
-import ch.systemsx.cisd.yeastx.db.DBFactory;
+import ch.systemsx.cisd.yeastx.db.DBUtils;
 import ch.systemsx.cisd.yeastx.db.DMDataSetDTO;
 import ch.systemsx.cisd.yeastx.fiaml.FIAMLParser.IMSRunObserver;
 
@@ -38,11 +42,6 @@ public class FIAML2Database
 
     private final static int PROFILE_CHUNK_SIZE = 250;
 
-    public static IFIAMSRunDAO getDAO(Connection conn)
-    {
-        return QueryTool.getQuery(conn, IFIAMSRunDAO.class);
-    }
-
     private static Iterable<ProfileDTO> profileChunk(final FIAMSRunDataDTO runData)
     {
         return new Iterable<ProfileDTO>()
@@ -78,16 +77,24 @@ public class FIAML2Database
             };
     }
 
+    private final IFIAMSRunDAO dao;
+
+    public FIAML2Database(DataSource datasource)
+    {
+        this.dao = QueryTool.getQuery(datasource, IFIAMSRunDAO.class);
+    }
+
     /**
      * Method for uploading an <var>fiaMLFile</var> to the database.
      */
-    public static void uploadFiaMLFile(final Connection conn, final File fiaMLFile,
-            final DMDataSetDTO dataSet) throws SQLException
+    public void uploadFiaMLFile(final File fiaMLFile, final DMDataSetDTO dataSet)
+            throws SQLException
     {
+        TransactionQuery transaction = null;
         try
         {
-            DBFactory.createDataSet(DBFactory.getDAO(conn), dataSet);
-            final IFIAMSRunDAO dao = getDAO(conn);
+            transaction = dao;
+            DBUtils.createDataSet(dao, dataSet);
             new FIAMLParser(fiaMLFile.getPath(), new IMSRunObserver()
                 {
                     public void observe(FIAMSRunDTO run, FIAMSRunDataDTO runData)
@@ -96,44 +103,38 @@ public class FIAML2Database
                         run.setSampleId(dataSet.getSampleId());
                         run.setDataSetId(dataSet.getId());
                         final long fiaMsRunId = dao.addMSRun(run);
-                        getDAO(conn).addProfiles(fiaMsRunId, profileChunk(runData));
-                        getDAO(conn)
-                                .addCentroids(fiaMsRunId, runData.getCentroidMz(),
-                                        runData.getCentroidIntensities(),
-                                        runData.getCentroidCorrelations());
+                        dao.addProfiles(fiaMsRunId, profileChunk(runData));
+                        dao.addCentroids(fiaMsRunId, runData.getCentroidMz(), runData
+                                .getCentroidIntensities(), runData.getCentroidCorrelations());
                     }
                 });
-            conn.commit();
+            transaction.close(true);
         } catch (Throwable th)
         {
-            conn.rollback();
-            if (th instanceof SQLException)
+            try
             {
-                throw (SQLException) th;
-            } else
+                DBUtils.rollbackAndClose(transaction);
+            } catch (DataAccessException ex)
             {
-                throw CheckedExceptionTunnel.wrapIfNecessary(th);
+                // Avoid this exception shadowing the original exception.
             }
+            throw CheckedExceptionTunnel.wrapIfNecessary(th);
         }
     }
 
     public static void main(String[] args) throws SQLException
     {
         final long start = System.currentTimeMillis();
-        final Connection conn = new DBFactory(DBFactory.createDefaultDBContext()).getConnection();
-        try
-        {
-            final String dir = args[0];
-            int permId = 0;
-            for (String f : new File(dir).list(new FIAMLFilenameFilter()))
-            {
-                System.out.println(f);
-                uploadFiaMLFile(conn, new File(dir, f), new DMDataSetDTO(Integer.toString(++permId),
-                        "sample perm id", "sample name", "experiment perm id", "experiment name"));
-            }
-        } finally
+        final FIAML2Database fiaML2Database =
+                new FIAML2Database(DBUtils.createDefaultDBContext().getDataSource());
+        final String dir = args[0];
+        int permId = 0;
+        for (String f : new File(dir).list(new FIAMLFilenameFilter()))
         {
-            conn.close();
+            System.out.println(f);
+            fiaML2Database.uploadFiaMLFile(new File(dir, f), new DMDataSetDTO(Integer
+                    .toString(++permId), "sample perm id", "sample name", "experiment perm id",
+                    "experiment name"));
         }
         System.out.println((System.currentTimeMillis() - start) / 1000.0);
     }
diff --git a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/IFIAMSRunDAO.java b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/IFIAMSRunDAO.java
index f8de0f12da5c9fed258390ccf10da6e6ffe0a762..1d7c17b2ee0f45279590eef47b81225ab21c86d6 100644
--- a/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/IFIAMSRunDAO.java
+++ b/rtd_yeastx/source/java/ch/systemsx/cisd/yeastx/fiaml/IFIAMSRunDAO.java
@@ -16,7 +16,8 @@
 
 package ch.systemsx.cisd.yeastx.fiaml;
 
-import net.lemnik.eodsql.BaseQuery;
+import ch.systemsx.cisd.yeastx.db.IGenericDAO;
+
 import net.lemnik.eodsql.DataIterator;
 import net.lemnik.eodsql.Select;
 import net.lemnik.eodsql.Update;
@@ -26,7 +27,7 @@ import net.lemnik.eodsql.Update;
  * 
  * @author Bernd Rinn
  */
-public interface IFIAMSRunDAO extends BaseQuery
+public interface IFIAMSRunDAO extends IGenericDAO
 {
     final String ALL_FIA_MSRUN_COLUMNS =
             "FIA_MS_RUNS.ID, FIA_MS_RUNS.EXPE_ID, "
diff --git a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/db/AbstractDBTest.java b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/db/AbstractDBTest.java
index 379ecbc97eb3a69a7601683a6230cf9fdecadf53..5362ec35c8b06aadaa5818eb6dc2717efaaf2184 100644
--- a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/db/AbstractDBTest.java
+++ b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/db/AbstractDBTest.java
@@ -16,19 +16,14 @@
 
 package ch.systemsx.cisd.yeastx.db;
 
-import java.sql.Connection;
 import java.sql.SQLException;
 
-import net.lemnik.eodsql.QueryTool;
+import javax.sql.DataSource;
 
-import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
 
 import ch.systemsx.cisd.common.logging.LogInitializer;
 import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
-import ch.systemsx.cisd.yeastx.eicml.IEICMSRunDAO;
-import ch.systemsx.cisd.yeastx.fiaml.IFIAMSRunDAO;
 
 /**
  * Abstract test case for database related unit testing.
@@ -42,40 +37,16 @@ public abstract class AbstractDBTest
         LogInitializer.init();
     }
     
-    protected Connection conn;
+    protected DataSource datasource;
     
     @BeforeClass(alwaysRun = true)
     public void setUpClass() throws SQLException
     {
-        final DatabaseConfigurationContext context = DBFactory.createDefaultDBContext();
+        final DatabaseConfigurationContext context = DBUtils.createDefaultDBContext();
         context.setDatabaseKind("dbtest");
         context.setCreateFromScratch(true);
-        new DBFactory(context).getConnection();
-    }
-
-    @BeforeMethod(alwaysRun = true)
-    public void setUpMethod() throws SQLException
-    {
-        final DatabaseConfigurationContext context = DBFactory.createDefaultDBContext();
-        context.setDatabaseKind("dbtest");
-        conn = new DBFactory(context).getConnection();
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void closeConnection() throws SQLException
-    {
-        conn.close();
-        conn = null;
-    }
-    
-    protected IEICMSRunDAO getEICMLDAO()
-    {
-        return QueryTool.getQuery(conn, IEICMSRunDAO.class);
-    }
-
-    protected IFIAMSRunDAO getFIAMLDAO()
-    {
-        return QueryTool.getQuery(conn, IFIAMSRunDAO.class);
+        DBUtils.init(context);
+        datasource = context.getDataSource();
     }
 
 }
diff --git a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/EICMLTest.java b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/EICMLTest.java
index 890c878184a26cd3e964e081be7277382467f38d..a66cedc8ef04ff63908de3864a8f1612a8628fd0 100644
--- a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/EICMLTest.java
+++ b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/EICMLTest.java
@@ -24,6 +24,7 @@ import java.sql.SQLException;
 import java.text.ParseException;
 
 import net.lemnik.eodsql.DataIterator;
+import net.lemnik.eodsql.QueryTool;
 
 import org.apache.commons.lang.ArrayUtils;
 import org.testng.annotations.BeforeMethod;
@@ -45,13 +46,14 @@ public class EICMLTest extends AbstractDBTest
     @BeforeMethod(alwaysRun = true)
     public void setDAO() throws SQLException
     {
-        eicmlDAO = getEICMLDAO();
+        eicmlDAO = QueryTool.getQuery(datasource, IEICMSRunDAO.class);
     }
 
     @Test
     public void testUploadEicML() throws SQLException
     {
-        EICML2Database.uploadEicMLFile(conn, new File("resource/examples/example.eicML"),
+        EICML2Database db = new EICML2Database(datasource);
+        db.uploadEicMLFile(new File("resource/examples/example.eicML"),
                 new DMDataSetDTO("data set perm id", "sample perm id", "sample name",
                         "experiment perm id", "experiment name"));
     }
@@ -138,7 +140,6 @@ public class EICMLTest extends AbstractDBTest
         assertEquals(17L, run.getMsRunId().longValue());
         assertEquals(32L, run.getSetId().longValue());
         assertEquals("???", run.getOperator());
-        runs.close(); // Shoudn't be necessary, just to be sure.
         final DataIterator<ChromatogramDTO> chromatograms = eicmlDAO.getChromatogramsForRun(run);
         int count = 0;
         while (chromatograms.hasNext())
@@ -148,6 +149,5 @@ public class EICMLTest extends AbstractDBTest
             ++count;
         }
         assertEquals(run.getChromCount(), count);
-        chromatograms.close(); // Shoudn't be necessary, just to be sure.
     }
 }
diff --git a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/ReadChromatogramsPerformanceTest.java b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/ReadChromatogramsPerformanceTest.java
index ba7fb6d009ce2c27f4b6faf1b5db54d83b784b08..54147631f26ab312e612c1df6fe0c1fc438b6fde 100644
--- a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/ReadChromatogramsPerformanceTest.java
+++ b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/eicml/ReadChromatogramsPerformanceTest.java
@@ -16,10 +16,13 @@
 
 package ch.systemsx.cisd.yeastx.eicml;
 
-import java.sql.Connection;
 import java.sql.SQLException;
 
-import ch.systemsx.cisd.yeastx.db.DBFactory;
+import net.lemnik.eodsql.QueryTool;
+import net.lemnik.eodsql.TransactionQuery;
+
+import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
+import ch.systemsx.cisd.yeastx.db.DBUtils;
 
 /**
  * A performance test of reading all chromatograms from the database.
@@ -31,11 +34,13 @@ public class ReadChromatogramsPerformanceTest
 
     public static void main(String[] args) throws SQLException
     {
-        final Connection conn = new DBFactory(DBFactory.createDefaultDBContext()).getConnection();
+        final DatabaseConfigurationContext context = DBUtils.createDefaultDBContext();
+        DBUtils.init(context);
+        TransactionQuery transaction = null;
         long start = System.currentTimeMillis();
         try
         {
-            final IEICMSRunDAO dao = EICML2Database.getDAO(conn);
+            final IEICMSRunDAO dao = QueryTool.getQuery(context.getDataSource(), IEICMSRunDAO.class);
             for (EICMSRunDTO run : dao.getMsRuns())
             {
                 // We need to iterate over the chromatograms to make sure they are really read.
@@ -47,7 +52,7 @@ public class ReadChromatogramsPerformanceTest
             }
         } finally
         {
-            conn.close();
+            DBUtils.close(transaction);
         }
         System.out.println((System.currentTimeMillis() - start) / 1000.0f);
     }
diff --git a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/fiaml/FIAMLTest.java b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/fiaml/FIAMLTest.java
index 6b22e445e0d142c1de224b02c2b626fec18ed680..cfb4ed22690da413011a2d06e4f6be27786373f7 100644
--- a/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/fiaml/FIAMLTest.java
+++ b/rtd_yeastx/sourceTest/java/ch/systemsx/cisd/yeastx/fiaml/FIAMLTest.java
@@ -16,21 +16,26 @@
 
 package ch.systemsx.cisd.yeastx.fiaml;
 
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertFalse;
+
 import java.io.File;
 import java.sql.SQLException;
 
 import net.lemnik.eodsql.DataIterator;
+import net.lemnik.eodsql.QueryTool;
 
+import org.springframework.dao.DataIntegrityViolationException;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.yeastx.db.AbstractDBTest;
+import ch.systemsx.cisd.yeastx.db.DBUtils;
 import ch.systemsx.cisd.yeastx.db.DMDataSetDTO;
 
-import static org.testng.AssertJUnit.*;
-
 /**
- * A test for thhe fiaML tables.
+ * A test for the fiaML tables.
  * 
  * @author Bernd Rinn
  */
@@ -41,26 +46,33 @@ public class FIAMLTest extends AbstractDBTest
     @BeforeMethod(alwaysRun = true)
     public void setDAO() throws SQLException
     {
-        fiamsDAO = getFIAMLDAO();
+        fiamsDAO = QueryTool.getQuery(datasource, IFIAMSRunDAO.class);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void close()
+    {
+        fiamsDAO.close();
     }
 
-    @Test(groups = "broken")
+    @Test
     public void testUploadFiaML() throws SQLException
     {
-        FIAML2Database.uploadFiaMLFile(conn, new File("resource/examples/example.fiaML"),
+        FIAML2Database fiaML2Database = new FIAML2Database(datasource);
+        fiaML2Database.uploadFiaMLFile(new File("resource/examples/example.fiaML"),
                 new DMDataSetDTO("data set perm id", "sample perm id", "sample name",
                         "experiment perm id", "experiment name"));
     }
 
-    @Test(groups = "broken", dependsOnMethods = "testUploadFiaML")
+    @Test(dependsOnMethods = "testUploadFiaML")
     public void testGetMsRuns()
     {
         final DataIterator<FIAMSRunDTO> runs = fiamsDAO.getMsRuns();
         final FIAMSRunDTO run = runs.next();
         assertFalse(runs.hasNext());
         assertEquals(686, run.getProfileCount());
-        runs.close(); // Shoudn't be necessary, just to be sure.
         final DataIterator<ProfileDTO> profiles = fiamsDAO.getProfilesForRun(run);
+        assertFalse(profiles.isClosed());
         int count = 0;
         while (profiles.hasNext())
         {
@@ -70,7 +82,6 @@ public class FIAMLTest extends AbstractDBTest
             ++count;
         }
         assertEquals(686, count);
-        profiles.close(); // Shoudn't be necessary, just to be sure.
         final DataIterator<CentroidDTO> centroids = fiamsDAO.getCentroidsForRun(run);
         count = 0;
         while (centroids.hasNext())
@@ -81,7 +92,46 @@ public class FIAMLTest extends AbstractDBTest
             ++count;
         }
         assertEquals(556, count);
-        centroids.close(); // Shoudn't be necessary, just to be sure.
+        fiamsDAO.close();
+    }
+
+    @Test(dependsOnMethods = "testGetMsRuns")
+    public void testUploadFiaMLFileTwiceWithOneDAO() throws SQLException
+    {
+        FIAML2Database fiaML2Database = new FIAML2Database(datasource);
+        fiaML2Database.uploadFiaMLFile(new File("resource/examples/example.fiaML"),
+                new DMDataSetDTO("data set perm id2", "sample perm id2", "sample name",
+                        "experiment perm id2", "experiment name"));
+        fiaML2Database.uploadFiaMLFile(new File("resource/examples/example.fiaML"),
+                new DMDataSetDTO("data set perm id3", "sample perm id", "sample name",
+                        "experiment perm id", "experiment name"));
+    }
+
+    @Test(dependsOnMethods = "testUploadFiaMLFileTwiceWithOneDAO", expectedExceptions = DataIntegrityViolationException.class)
+    public void testCreateSameDataSetTwiceFailing() throws SQLException
+    {
+        try
+        {
+            DBUtils.createDataSet(fiamsDAO, new DMDataSetDTO("data set perm id 4",
+                    "sample perm id4", "sample name", "experiment perm id", "experiment name"));
+            // This will fail with a DataIntegrityViolationException.
+            DBUtils.createDataSet(fiamsDAO, new DMDataSetDTO("data set perm id 4",
+                    "sample perm id4", "sample name", "experiment perm id", "experiment name"));
+        } catch (RuntimeException ex)
+        {
+            // This isn't actually necessary for PostgreSQL, but e.g. Oracle does commit a
+            // transaction when no explicit rollback is given.
+            fiamsDAO.rollback();
+            throw ex;
+        }
+    }
+
+    @Test(dependsOnMethods = "testCreateSameDataSetTwiceFailing")
+    public void testDataSets() throws SQLException
+    {
+        assertEquals(2, fiamsDAO.listDataSetsForSample("sample perm id").length);
+        assertEquals(1, fiamsDAO.listDataSetsForSample("sample perm id2").length);
+        assertEquals(0, fiamsDAO.listDataSetsForSample("sample perm id4").length);
     }
 
 }