diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptor.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptor.java
index 18571940cb5f9c1c8f47b1bcfddead315be4ff3e..d23d8e9b4013d497465a516ca4abedb96ed1a1ea 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptor.java
@@ -30,6 +30,7 @@ import ch.systemsx.cisd.openbis.dss.generic.server.ConfigParameters;
 import ch.systemsx.cisd.openbis.dss.generic.server.EncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.server.SessionTokenManager;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IPluginTaskInfoProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSourceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ManagedAuthentication;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DssPropertyParametersUtil;
 import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
@@ -87,10 +88,13 @@ public class OpenBISAuthenticationInterceptor implements MethodInterceptor
 
     private final IETLLIMSService service;
 
+    private final IDataSourceProvider dataSourceProvider;
+
     public OpenBISAuthenticationInterceptor(SessionTokenManager sessionTokenManager,
             IETLLIMSService service, IPluginTaskInfoProvider pluginTaskParameters,
-            OpenBISSessionHolder sessionHolder)
+            IDataSourceProvider dataSourceProvider, OpenBISSessionHolder sessionHolder)
     {
+        this.dataSourceProvider = dataSourceProvider;
         assert sessionTokenManager != null : "Unspecified session token manager.";
         assert service != null : "Given IETLLIMSService implementation can not be null.";
         assert pluginTaskParameters != null : "Unspecified plugin tasks";
@@ -156,6 +160,8 @@ public class OpenBISAuthenticationInterceptor implements MethodInterceptor
         dataStoreServerInfo.setServicesDescriptions(pluginTaskDescriptions);
         dataStoreServerInfo.setArchiverConfigured(archiverConfigured);
         dataStoreServerInfo.setTimeoutInMinutes(timeoutInMinutes);
+        dataStoreServerInfo.setDataSourceDefinitions(dataSourceProvider.getAllDataSourceDefinitions());
+        
         service.registerDataStoreServer(sessionToken, dataStoreServerInfo);
     }
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSourceProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSourceProvider.java
index d7e20b1b55f66a1c3b9a61a6ddcdd92dfe77d479..b3b48e0bd9e9f6246c6248a6715718cbf3a4bd1b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSourceProvider.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DataSourceProvider.java
@@ -16,7 +16,9 @@
 
 package ch.systemsx.cisd.openbis.dss.generic.shared;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
@@ -32,6 +34,9 @@ import ch.systemsx.cisd.common.properties.PropertyUtils;
 import ch.systemsx.cisd.common.properties.PropertyParametersUtil.SectionProperties;
 import ch.systemsx.cisd.common.reflection.ClassUtils;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DssPropertyParametersUtil;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceWithDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.util.IDataSourceFactory;
 
 /**
  * Stores and provides access to data sources defined in properties file.
@@ -75,14 +80,17 @@ public class DataSourceProvider implements IDataSourceProvider
     private static final Logger operationLog =
             LogFactory.getLogger(LogCategory.OPERATION, DataSourceProvider.class);
 
-    private final Map<String, DataSource> dataSources;
+    private final Map<String, DataSourceWithDefinition> dataSources;
+    
+    private final List<DataSourceDefinition> dataSourceDefinitions =
+            new ArrayList<DataSourceDefinition>();
 
     public static final String DATA_SOURCE_KEY = "data-source";
 
     private DataSourceProvider()
     {
         Properties properties = DssPropertyParametersUtil.loadServiceProperties();
-        dataSources = new HashMap<String, DataSource>();
+        dataSources = new HashMap<String, DataSourceWithDefinition>();
         SectionProperties[] props =
                 PropertyParametersUtil
                         .extractSectionProperties(properties, Constants.DATA_SOURCES_KEY, false);
@@ -97,7 +105,13 @@ public class DataSourceProvider implements IDataSourceProvider
             {
                 IDataSourceFactory factory =
                         ClassUtils.create(IDataSourceFactory.class, dataSourceFactoryClass);
-                DataSource dataSource = factory.create(dataSourceProperties);
+                DataSourceWithDefinition dataSource = factory.create(dataSourceProperties);
+                DataSourceDefinition definition = dataSource.getDefinitionOrNull();
+                if (definition != null)
+                {
+                    definition.setCode(dataSourceName);
+                    dataSourceDefinitions.add(definition);
+                }
                 dataSources.put(dataSourceName, dataSource);
                 if (operationLog.isInfoEnabled())
                 {
@@ -124,14 +138,14 @@ public class DataSourceProvider implements IDataSourceProvider
     @Override
     public DataSource getDataSource(String name) throws IllegalArgumentException
     {
-        DataSource result = dataSources.get(name);
+        DataSourceWithDefinition result = dataSources.get(name);
         if (result == null)
         {
             String message = "Data source '" + name + "' has not been configured.";
             throw new IllegalArgumentException(message);
         } else
         {
-            return result;
+            return result.getDataSource();
         }
     }
 
@@ -145,6 +159,12 @@ public class DataSourceProvider implements IDataSourceProvider
         return getDataSource(extractDataSourceName(properties));
     }
 
+    @Override
+    public List<DataSourceDefinition> getAllDataSourceDefinitions()
+    {
+        return dataSourceDefinitions;
+    }
+
     /**
      * Extracts data source name ({@link #DATA_SOURCE_KEY}) from properties.
      */
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DefaultDataSourceFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DefaultDataSourceFactory.java
index ad60a328c613118ac15f1efa9be115c344a03a9f..420dd295b6945fdcad57efda3a75f84aa55657f3 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DefaultDataSourceFactory.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/DefaultDataSourceFactory.java
@@ -25,6 +25,9 @@ import ch.systemsx.cisd.common.reflection.BeanUtils;
 import ch.systemsx.cisd.common.reflection.ClassUtils;
 import ch.systemsx.cisd.dbmigration.DBMigrationEngine;
 import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceWithDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.util.IDataSourceFactory;
 
 /**
  * Creates a {@link DataSource} using {@link DatabaseConfigurationContext} and given properties. The
@@ -39,7 +42,7 @@ public class DefaultDataSourceFactory implements IDataSourceFactory
     public static final String VERSION_HOLDER_CLASS_KEY = "version-holder-class";
 
     @Override
-    public DataSource create(Properties dbProps)
+    public DataSourceWithDefinition create(Properties dbProps)
     {
         DatabaseConfigurationContext context =
                 BeanUtils.createBean(DatabaseConfigurationContext.class, dbProps);
@@ -59,6 +62,7 @@ public class DefaultDataSourceFactory implements IDataSourceFactory
             String version = versionHolder.getDatabaseVersion();
             DBMigrationEngine.createOrMigrateDatabaseAndGetScriptProvider(context, version);
         }
-        return context.getDataSource();
+        return new DataSourceWithDefinition(context.getDataSource(),
+                DataSourceDefinition.createFromContext(context));
     }
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceProvider.java
index b0cf222503d4227e86875fa8cd33d36893faf172..bfc680bffc05982db06eca191f6ddd5a8079c7e6 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceProvider.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceProvider.java
@@ -16,10 +16,13 @@
 
 package ch.systemsx.cisd.openbis.dss.generic.shared;
 
+import java.util.List;
 import java.util.Properties;
 
 import javax.sql.DataSource;
 
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
+
 /**
  * A provider for data sources.
  * 
@@ -39,5 +42,10 @@ public interface IDataSourceProvider
      * source by calling {@link #getDataSource(String)}.
      */
     public DataSource getDataSource(Properties properties);
+    
+    /**
+     * Returns all data source definitions. Note, that not all data sources have a definition.
+     */
+    public List<DataSourceDefinition> getAllDataSourceDefinitions();
 
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/SimpleDataSourceFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/SimpleDataSourceFactory.java
index dce0fa8d6af06d3d3b1138835d84a136b60b3f35..65c2632e9e8689ea7cd596e37a8ce38ac9cadb8c 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/SimpleDataSourceFactory.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/SimpleDataSourceFactory.java
@@ -21,6 +21,8 @@ import java.util.Properties;
 import javax.sql.DataSource;
 
 import ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceWithDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.util.IDataSourceFactory;
 
 /**
  * Creates a commons-dbcp {@link DataSource} using its standard properties.
@@ -31,11 +33,11 @@ public class SimpleDataSourceFactory implements IDataSourceFactory
 {
 
     @Override
-    public DataSource create(Properties dbProps)
+    public DataSourceWithDefinition create(Properties dbProps)
     {
         SimpleDatabaseConfigurationContext context =
                 new SimpleDatabaseConfigurationContext(dbProps);
 
-        return context.getDataSource();
+        return new DataSourceWithDefinition(context.getDataSource(), null);
     }
 }
diff --git a/datastore_server/source/java/dssApplicationContext.xml b/datastore_server/source/java/dssApplicationContext.xml
index 2471731203a85a2e34f509c25274a65d62f9f0be..8883e1790d43b17e8b12f82dd32b4ed9bb302ba5 100644
--- a/datastore_server/source/java/dssApplicationContext.xml
+++ b/datastore_server/source/java/dssApplicationContext.xml
@@ -61,6 +61,7 @@
 	        <constructor-arg ref="etl-lims-service"/>
 	        <constructor-arg ref="plugin-tasks" />
 	        <constructor-arg ref="sessionHolder" />
+	        <constructor-arg ref="data-source-provider" />
 	        <property name="username" value="${username}"/>
 	        <property name="password" value="${password}"/>
 	        <property name="port" value="${port}"/>
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptorTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptorTest.java
index 2a1bf6c06dd5045fcd71a686f1a9e350a6a967d1..727cd0e4b5a2739437cd2a19647f1d1867d4975f 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptorTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/openbisauth/OpenBISAuthenticationInterceptorTest.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.generic.server.openbisauth;
 import static org.testng.AssertJUnit.assertEquals;
 
 import java.io.File;
+import java.util.Arrays;
 
 import org.aopalliance.intercept.MethodInvocation;
 import org.hamcrest.BaseMatcher;
@@ -32,9 +33,11 @@ import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.common.exceptions.InvalidSessionException;
 import ch.systemsx.cisd.openbis.dss.generic.server.SessionTokenManager;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSourceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.PluginUtilTest;
 import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataStoreServerInfo;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
 import ch.systemsx.cisd.openbis.generic.shared.dto.OpenBISSessionHolder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
 
@@ -66,18 +69,23 @@ public class OpenBISAuthenticationInterceptorTest
 
     private OpenBISSessionHolder sessionHolder;
 
+    private IDataSourceProvider dataSourceProvider;
+
     @BeforeMethod
     public void setUp()
     {
         context = new Mockery();
         limsService = context.mock(IETLLIMSService.class);
         methodInvocation = context.mock(MethodInvocation.class);
+        dataSourceProvider = context.mock(IDataSourceProvider.class);
         
         sessionHolder = new OpenBISSessionHolder();
         sessionHolder.setDataStoreCode(DATA_STORE_CODE);
 
-        interceptor = new OpenBISAuthenticationInterceptor(new SessionTokenManager(), limsService, 
-                        PluginUtilTest.createPluginTaskProviders(new File(".")), sessionHolder);
+        interceptor =
+                new OpenBISAuthenticationInterceptor(new SessionTokenManager(), limsService,
+                        PluginUtilTest.createPluginTaskProviders(new File(".")),
+                        dataSourceProvider, sessionHolder);
 
         interceptor.setUsername(LIMS_USER);
         interceptor.setPassword(LIMS_PASSWORD);
@@ -103,6 +111,9 @@ public class OpenBISAuthenticationInterceptorTest
                     will(throwException(new InvalidSessionException("error")));
                     setUpAuthenticationExpectations(this);
                     one(methodInvocation).proceed();
+                    
+                    one(dataSourceProvider).getAllDataSourceDefinitions();
+                    will(returnValue(Arrays.asList(DataSourceDefinition.fromString("code=a"))));
                 }
             });
 
@@ -121,6 +132,9 @@ public class OpenBISAuthenticationInterceptorTest
                 {
                     setUpAuthenticationExpectations(this);
                     one(methodInvocation).proceed();
+                    
+                    one(dataSourceProvider).getAllDataSourceDefinitions();
+                    will(returnValue(Arrays.asList(DataSourceDefinition.fromString("code=a"))));
                 }
             });
 
@@ -171,7 +185,8 @@ public class OpenBISAuthenticationInterceptorTest
                                 && info.getServicesDescriptions()
                                         .getProcessingServiceDescriptions().size() == 0
                                 && info.getServicesDescriptions().getReportingServiceDescriptions()
-                                        .size() == 0;
+                                        .size() == 0
+                                && info.getDataSourceDefinitions().toString().equals("[code=a\t]");
                     }
                     return false;
                 }
diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseEngine.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseEngine.java
index fc6f2e50fcca26aecf4bc727fbeb076a69f88e24..023387c73c5d2224ccc6ad72f2c71e19c14af41c 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseEngine.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/DatabaseEngine.java
@@ -47,6 +47,8 @@ public enum DatabaseEngine
             "jdbc:h2:{0}{1};DB_CLOSE_DELAY=-1", "file:db/", "sa", null);
 
     private static Map<String, DatabaseEngine> engines = initEngineMap();
+    
+    private static Map<String, DatabaseEngine> enginesByDriverClass = initEnginesByDriverClassMap();
 
     private final String code;
 
@@ -197,6 +199,30 @@ public enum DatabaseEngine
         }
         return engine;
     }
+    
+    /**
+     * Returns the database engine for specified driver class.
+     * 
+     * @throws IllegalArgumentException if no engine could be found.
+     */
+    public static DatabaseEngine getEngineForDriverClass(String driverClassName)
+    {
+        final DatabaseEngine engine = enginesByDriverClass.get(driverClassName);
+        if (engine == null)
+        {
+            throw new IllegalArgumentException("No database engine with driver class "
+                    + driverClassName + " found.");
+        }
+        return engine;
+    }
+    
+    /**
+     * Returns <code>true</code> if a {@link DatabaseEngine} for specified driver class exists.
+     */
+    public static boolean hasEngineForDriverClass(String driverClassName)
+    {
+        return enginesByDriverClass.get(driverClassName) != null;
+    }
 
     private static Map<String, DatabaseEngine> initEngineMap()
     {
@@ -208,4 +234,14 @@ public enum DatabaseEngine
         return map;
     }
 
+    private static Map<String, DatabaseEngine> initEnginesByDriverClassMap()
+    {
+        final Map<String, DatabaseEngine> map = new HashMap<String, DatabaseEngine>();
+        for (DatabaseEngine engine : values())
+        {
+            map.put(engine.driverClass, engine);
+        }
+        return map;
+    }
+    
 }
diff --git a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SimpleDatabaseConfigurationContext.java b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SimpleDatabaseConfigurationContext.java
index ce8cc8419414b76a3cc47dca570c0fff66bf76db..a00f4ed142fa372186726a62a1edb9abd50239b2 100644
--- a/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SimpleDatabaseConfigurationContext.java
+++ b/dbmigration/source/java/ch/systemsx/cisd/dbmigration/SimpleDatabaseConfigurationContext.java
@@ -47,13 +47,13 @@ public class SimpleDatabaseConfigurationContext implements DisposableBean
     private static final Logger operationLog =
             LogFactory.getLogger(LogCategory.OPERATION, SimpleDatabaseConfigurationContext.class);
 
-    static final String DRIVER_KEY = "database-driver";
+    public static final String DRIVER_KEY = "database-driver";
 
-    static final String URL_KEY = "database-url";
+    public static final String URL_KEY = "database-url";
 
-    static final String USER_KEY = "database-username";
+    public static final String USER_KEY = "database-username";
 
-    static final String PASSWORD_KEY = "database-password";
+    public static final String PASSWORD_KEY = "database-password";
 
     static final String MAX_IDLE_KEY = "database-max-idle-connections";
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
index ffdc4659f50133c54292c221658ec874b201c6b8..986506ae2b27884fde706ae1483f6ba506b45739 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ETLService.java
@@ -100,6 +100,7 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataSetTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataStoreDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataStoreDataSourceManager;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityPropertyTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IEntityTypeDAO;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IMetaprojectDAO;
@@ -261,6 +262,8 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements
 
     private final IDataStoreServiceRegistrator dataStoreServiceRegistrator;
 
+    private final IDataStoreDataSourceManager dataSourceManager;
+
     private IServiceConversationClientManagerLocal conversationClient;
 
     private IServiceConversationServerManagerLocal conversationServer;
@@ -270,11 +273,12 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements
             ICommonBusinessObjectFactory boFactory, IDataStoreServiceFactory dssFactory,
             TrustedCrossOriginDomainsProvider trustedOriginDomainProvider,
             IETLEntityOperationChecker entityOperationChecker,
-            IDataStoreServiceRegistrator dataStoreServiceRegistrator)
+            IDataStoreServiceRegistrator dataStoreServiceRegistrator,
+            IDataStoreDataSourceManager dataSourceManager)
     {
         this(authenticationService, sessionManager, daoFactory, null, boFactory, dssFactory,
                 trustedOriginDomainProvider, entityOperationChecker, dataStoreServiceRegistrator,
-                new DefaultSessionManager<Session>(new SessionFactory(),
+                dataSourceManager, new DefaultSessionManager<Session>(new SessionFactory(),
                         new LogMessagePrefixGenerator(), new DummyAuthenticationService(),
                         new RequestContextProviderAdapter(new IRequestContextProvider()
                             {
@@ -293,6 +297,7 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements
             TrustedCrossOriginDomainsProvider trustedOriginDomainProvider,
             IETLEntityOperationChecker entityOperationChecker,
             IDataStoreServiceRegistrator dataStoreServiceRegistrator,
+            IDataStoreDataSourceManager dataSourceManager,
             ISessionManager<Session> sessionManagerForEntityOperation)
     {
         super(authenticationService, sessionManager, daoFactory, propertiesBatchManager, boFactory);
@@ -301,6 +306,7 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements
         this.trustedOriginDomainProvider = trustedOriginDomainProvider;
         this.entityOperationChecker = entityOperationChecker;
         this.dataStoreServiceRegistrator = dataStoreServiceRegistrator;
+        this.dataSourceManager = dataSourceManager;
         this.sessionManagerForEntityOperation = sessionManagerForEntityOperation;
     }
 
@@ -354,6 +360,7 @@ public class ETLService extends AbstractCommonServer<IETLLIMSService> implements
         dataStoreDAO.createOrUpdateDataStore(dataStore);
         dataStoreServiceRegistrator.setServiceDescriptions(dataStore,
                 info.getServicesDescriptions());
+        dataSourceManager.handle(info.getDataStoreCode(), info.getDataSourceDefinitions());
 
         conversationClient.setDataStoreInformation(dssURL, info.getTimeoutInMinutes());
         conversationServer.setDataStoreInformation(info.getDataStoreCode(), dssURL,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProvider.java
index a23dfc458ca7a68292051b848f814ee79d319ec1..7bf852bc58dee53f73070a08c7255287ac85f21f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProvider.java
@@ -16,23 +16,48 @@
 
 package ch.systemsx.cisd.openbis.generic.server.dataaccess;
 
+import static ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext.DRIVER_KEY;
+import static ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext.PASSWORD_KEY;
+import static ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext.URL_KEY;
+import static ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext.USER_KEY;
+
+import java.io.File;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.EnumMap;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Properties;
+import java.util.Set;
+import java.util.regex.Pattern;
 
 import javax.annotation.Resource;
 import javax.sql.DataSource;
 
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
 import org.springframework.beans.factory.InitializingBean;
 
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
-import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.properties.ExtendedProperties;
 import ch.systemsx.cisd.common.properties.PropertyParametersUtil;
 import ch.systemsx.cisd.common.properties.PropertyParametersUtil.SectionProperties;
+import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
 import ch.systemsx.cisd.common.spring.ExposablePropertyPlaceholderConfigurer;
+import ch.systemsx.cisd.dbmigration.DatabaseEngine;
+import ch.systemsx.cisd.dbmigration.MonitoringDataSource;
 import ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceWithDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.util.IDataSourceFactory;
 
 /**
  * Data source provider based on configuration per Data Store Server.
@@ -40,22 +65,50 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  * @author Franz-Josef Elmer
  */
 public class DataStoreServerBasedDataSourceProvider implements IDataSourceProvider,
-        InitializingBean
+        IDataStoreDataSourceManager, InitializingBean
 {
     public static final String ROOT_KEY = "dss-based-data-source-provider";
 
     public static final String DATA_STORE_SERVERS_KEY = "data-store-servers";
 
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            DataStoreServerBasedDataSourceProvider.class);
+
     @Resource(name = ExposablePropertyPlaceholderConfigurer.PROPERTY_CONFIGURER_BEAN_NAME)
     private ExposablePropertyPlaceholderConfigurer configurer;
 
+    private Map<String, DataSource> dataSourcesByKey = new HashMap<String, DataSource>();
+
+    private Map<Mapping, DataSource> dataSourcesByMapping = new HashMap<Mapping, DataSource>();
+
+    private Map<String, Properties> configParametersByKeys = new HashMap<String, Properties>();
+
     private final IDAOFactory daoFactory;
 
-    private Map<String, DataSource> dataSources;
+    private final MappingManager mappingManager;
+
+    private final IDataSourceFactory dataSourceFactory;
+
+    public DataStoreServerBasedDataSourceProvider(IDAOFactory daoFactory,
+            String dssDataSourceMappingFilePath)
+    {
+        this(daoFactory, dssDataSourceMappingFilePath, new IDataSourceFactory()
+            {
+                @Override
+                public DataSourceWithDefinition create(Properties props)
+                {
+                    return new DataSourceWithDefinition(new SimpleDatabaseConfigurationContext(
+                            props).getDataSource(), null);
+                }
+            });
+    }
 
-    public DataStoreServerBasedDataSourceProvider(IDAOFactory daoFactory)
+    DataStoreServerBasedDataSourceProvider(IDAOFactory daoFactory,
+            String dssDataSourceMappingFilePath, IDataSourceFactory dataSourceFactory)
     {
         this.daoFactory = daoFactory;
+        this.dataSourceFactory = dataSourceFactory;
+        mappingManager = new MappingManager(dssDataSourceMappingFilePath);
     }
 
     @Override
@@ -66,47 +119,513 @@ public class DataStoreServerBasedDataSourceProvider implements IDataSourceProvid
 
     void init(Properties props)
     {
-        dataSources = new HashMap<String, DataSource>();
         SectionProperties[] sectionsProperties =
                 PropertyParametersUtil.extractSectionProperties(props, DATA_STORE_SERVERS_KEY,
                         false);
         for (SectionProperties sectionProperties : sectionsProperties)
         {
             String key = sectionProperties.getKey().toUpperCase();
-            Properties properties = sectionProperties.getProperties();
-            SimpleDatabaseConfigurationContext context =
-                    new SimpleDatabaseConfigurationContext(properties);
-            dataSources.put(key, context.getDataSource());
+            configParametersByKeys.put(key, sectionProperties.getProperties());
+        }
+        mappingManager.init(configParametersByKeys);
+        Map<String, List<DataSourceDefinition>> originalDataSourceDefinitions =
+                new HashMap<String, List<DataSourceDefinition>>();
+        List<DataStorePE> dataStores = daoFactory.getDataStoreDAO().listDataStores();
+        for (DataStorePE dataStore : dataStores)
+        {
+            String code = dataStore.getCode();
+            List<DataSourceDefinition> definitions =
+                    DataSourceDefinition.listFromString(dataStore
+                            .getSerializedDataSourceDefinitions());
+            originalDataSourceDefinitions.put(code, definitions);
+        }
+        for (Entry<String, List<DataSourceDefinition>> entry : originalDataSourceDefinitions
+                .entrySet())
+        {
+            String dataStoreCode = entry.getKey();
+            mappingManager.handle(dataStoreCode, entry.getValue());
+            clearDataSourceCaches(dataStoreCode);
         }
     }
 
     @Override
-    public DataSource getDataSourceByDataSetCode(String dataSetCode, String technology)
+    public synchronized DataSource getDataSourceByDataStoreServerCode(String dssCode,
+            String technology)
     {
-        DataPE dataSet = daoFactory.getDataDAO().tryToFindDataSetByCode(dataSetCode);
-        if (dataSet == null)
+        String normalizedDssCode = dssCode.toUpperCase();
+        String moduleCode = technology.toUpperCase();
+        String key = normalizedDssCode + "[" + moduleCode + "]";
+        DataSource dataSource = dataSourcesByKey.get(key);
+        if (dataSource == null)
         {
-            throw new UserFailureException("Unknown data set: " + dataSetCode);
+            dataSource = createDataSource(normalizedDssCode, moduleCode);
+            dataSourcesByKey.put(key, dataSource);
         }
-        return getDataSourceByDataStoreServerCode(dataSet.getDataStore().getCode(), technology);
+        return dataSource;
     }
 
-    @Override
-    public DataSource getDataSourceByDataStoreServerCode(String dssCode, String technology)
+    private DataSource createDataSource(String dataStoreCode, String moduleCode)
     {
-        DataSource dataSource =
-                dataSources.get(dssCode.toUpperCase() + "[" + technology.toUpperCase() + "]");
+        Mapping mapping = mappingManager.getMapping(dataStoreCode, moduleCode);
+        DataSource dataSource = dataSourcesByMapping.get(mapping);
         if (dataSource == null)
         {
-            dataSource = dataSources.get(dssCode.toUpperCase());
+            dataSource = createDataSource(mapping);
+            dataSourcesByMapping.put(mapping, dataSource);
         }
-        if (dataSource == null)
+        return dataSource;
+    }
+
+    private DataSource createDataSource(Mapping mapping)
+    {
+        Properties properties = configParametersByKeys.get(mapping.configKey);
+        if (properties == null)
         {
-            throw new ConfigurationFailureException(
-                    "No data source configured for Data Store Server '" + dssCode
-                            + "' and technology '" + technology + "'.");
+            throw new ConfigurationFailureException("No data source configured for '"
+                    + mapping.configKey + "'.");
         }
-        return dataSource;
+        properties = ExtendedProperties.createWith(properties);
+        DataSourceDefinition definitionOrNull = mapping.definitionOrNull;
+        Properties props = createMergedProperties(properties, definitionOrNull);
+        return dataSourceFactory.create(props).getDataSource();
+    }
+
+    private Properties createMergedProperties(Properties properties,
+            DataSourceDefinition definitionOrNull)
+    {
+        Properties props = ExtendedProperties.createWith(properties);
+        if (definitionOrNull != null)
+        {
+            if (properties.getProperty(DRIVER_KEY) == null)
+            {
+                props.setProperty(DRIVER_KEY, definitionOrNull.getDriverClassName());
+            }
+            if (properties.getProperty(USER_KEY) == null)
+            {
+                props.setProperty(USER_KEY, definitionOrNull.getUsername());
+            }
+            if (properties.getProperty(PASSWORD_KEY) == null)
+            {
+                props.setProperty(PASSWORD_KEY, definitionOrNull.getPassword());
+            }
+            if (properties.getProperty(URL_KEY) == null)
+            {
+                DatabaseEngine engine =
+                        DatabaseEngine.getEngineForDriverClass(definitionOrNull
+                                .getDriverClassName());
+                String url =
+                        engine.getURL(definitionOrNull.getHostPart(), definitionOrNull.getSid());
+                props.setProperty(URL_KEY, url);
+            }
+        }
+        return props;
+    }
+
+    @Override
+    public synchronized void handle(String dataStoreCode,
+            List<DataSourceDefinition> dataSourceDefinitions)
+    {
+        IDataStoreDAO dataStoreDAO = daoFactory.getDataStoreDAO();
+        DataStorePE dataStore = dataStoreDAO.tryToFindDataStoreByCode(dataStoreCode);
+        if (dataStore == null)
+        {
+            throw new EnvironmentFailureException("Unknown data store: " + dataStoreCode);
+        }
+        assertMandatoryAttributesDefined(dataSourceDefinitions);
+        dataStore.setSerializedDataSourceDefinitions(DataSourceDefinition
+                .toString(dataSourceDefinitions));
+        dataStoreDAO.createOrUpdateDataStore(dataStore);
+        mappingManager.handle(dataStoreCode, dataSourceDefinitions);
+        clearDataSourceCaches(dataStoreCode);
+    }
+
+    private void clearDataSourceCaches(String dataStoreCode)
+    {
+        LinkedList<Entry<Mapping, DataSource>> entries =
+                new LinkedList<Entry<Mapping, DataSource>>(dataSourcesByMapping.entrySet());
+        dataSourcesByMapping.clear();
+        for (Entry<Mapping, DataSource> entry : entries)
+        {
+            Mapping mapping = entry.getKey();
+            DataSource dataSource = entry.getValue();
+            if (dataStoreCode.equals(mapping.dataStoreCode))
+            {
+                if (dataSource instanceof MonitoringDataSource)
+                {
+                    try
+                    {
+                        ((MonitoringDataSource) dataSource).close();
+                    } catch (SQLException ex)
+                    {
+                        DataSourceDefinition definition = mapping.definitionOrNull;
+                        if (definition == null)
+                        {
+                            operationLog.warn("Couldn't close data source for " + mapping.configKey
+                                    + ".");
+                        } else
+                        {
+                            operationLog
+                                    .warn("Couldn't close data source for database "
+                                            + definition.getSid() + " on "
+                                            + definition.getHostPart() + ".");
+                        }
+                    }
+                }
+            } else
+            {
+                dataSourcesByMapping.put(mapping, dataSource);
+            }
+        }
+        dataSourcesByKey.clear();
+    }
+
+    private void assertMandatoryAttributesDefined(List<DataSourceDefinition> definitions)
+    {
+        StringBuilder errors = new StringBuilder();
+        for (DataSourceDefinition definition : definitions)
+        {
+            CommaSeparatedListBuilder builder = new CommaSeparatedListBuilder();
+            if (StringUtils.isBlank(definition.getCode()))
+            {
+                builder.append("code");
+            }
+            if (StringUtils.isBlank(definition.getHostPart()))
+            {
+                builder.append("hostPart");
+            }
+            if (StringUtils.isBlank(definition.getSid()))
+            {
+                builder.append("sid");
+            }
+            String driverClassName = definition.getDriverClassName();
+            if (driverClassName == null
+                    || DatabaseEngine.hasEngineForDriverClass(driverClassName) == false)
+            {
+                builder.append("driverClassName");
+            }
+            String error = builder.toString();
+            if (error.length() > 0)
+            {
+                errors.append("\n").append(error).append("[").append(definition).append("]");
+            }
+        }
+        if (errors.length() > 0)
+        {
+            throw new EnvironmentFailureException(
+                    "Some data source definitions have missing or wrong mandatory attributes: "
+                            + errors);
+        }
+    }
+
+    private static final class MappingManager
+    {
+        private final String mappingFilePath;
+
+        private List<MappingEntry> mappingEntries;
+
+        private Map<String, Properties> configs;
+
+        private Map<String, Map<String, DataSourceDefinition>> dataSourceDefinitionsByCodes =
+                new HashMap<String, Map<String, DataSourceDefinition>>();
+
+        public MappingManager(String mappingFilePath)
+        {
+            this.mappingFilePath = mappingFilePath;
+        }
+
+        public void init(Map<String, Properties> propertiesByKey)
+        {
+            mappingEntries = parse(mappingFilePath);
+            configs = propertiesByKey;
+        }
+
+        private static List<MappingEntry> parse(String mappingFilePath)
+        {
+            List<MappingEntry> mappingEntries = new ArrayList<MappingEntry>();
+            File file = new File(mappingFilePath);
+            if (file.isFile())
+            {
+                List<String> lines = FileUtilities.loadToStringList(file);
+                StringBuilder builder = new StringBuilder();
+                for (int i = 0; i < lines.size(); i++)
+                {
+                    String line = lines.get(i);
+                    if (StringUtils.isBlank(line) || line.startsWith("#"))
+                    {
+                        continue;
+                    }
+                    try
+                    {
+                        mappingEntries.add(parseLine(line));
+                    } catch (Exception e)
+                    {
+                        builder.append("\nLine ").append(i + 1).append(": ").append(e.getMessage());
+                    }
+                }
+                if (builder.length() > 0)
+                {
+                    throw new ConfigurationFailureException("Error(s) in mapping file "
+                            + mappingFilePath + ":" + builder);
+                }
+            }
+            return mappingEntries;
+        }
+
+        private static MappingEntry parseLine(String line)
+        {
+            int indexOfEqualSign = line.indexOf('=');
+            if (indexOfEqualSign < 0)
+            {
+                throw new IllegalArgumentException("Missing '='");
+            }
+            String[] description = line.substring(0, indexOfEqualSign).trim().split("\\.");
+            if (description.length != 3)
+            {
+                throw new IllegalArgumentException(
+                        "Mapping description should have three parts separated by '.'");
+            }
+            Pattern dssCodePattern = createPattern(description[0].toUpperCase());
+            Pattern dataSourceCodePattern = createPattern(description[1].toUpperCase());
+            String type = description[2];
+            String value = line.substring(indexOfEqualSign + 1).trim();
+            return new MappingEntry(dssCodePattern, dataSourceCodePattern, type, value);
+        }
+
+        private static Pattern createPattern(String wildcardPattern)
+        {
+            String regex = wildcardPattern.replace("*", ".*");
+            return Pattern.compile(regex);
+        }
+
+        public Mapping getMapping(String dataStoreCode, String moduleCode)
+        {
+            String configKey = dataStoreCode + "[" + moduleCode + "]";
+            String dataSourceCode = null;
+            Map<Type, String> replacementsByType = new EnumMap<Type, String>(Type.class);
+            for (MappingEntry mappingEntry : mappingEntries)
+            {
+                String value = mappingEntry.value;
+                if (mappingEntry.matches(dataStoreCode, moduleCode) && value != null)
+                {
+                    Type type = mappingEntry.type;
+                    switch (type)
+                    {
+                        case CONFIG:
+                            configKey =
+                                    value.replace("[*]", "[" + moduleCode + "]").replace("*",
+                                            dataStoreCode);
+                            break;
+                        case DATA_SOURCE:
+                            dataSourceCode = value;
+                            break;
+                        default:
+                            replacementsByType.put(type, value);
+                    }
+                }
+            }
+            DataSourceDefinition definition =
+                    getDefinitionsOrNull(dataStoreCode, dataSourceCode, replacementsByType);
+            if (configs.containsKey(configKey) == false)
+            {
+                if (configs.containsKey(dataStoreCode) == false)
+                {
+                    throw new EnvironmentFailureException("Couldn't find data source core plugin '"
+                            + configKey + "' nor '" + dataStoreCode + "'.");
+                }
+                configKey = dataStoreCode;
+            }
+            return new Mapping(dataStoreCode, configKey, definition);
+        }
+
+        private DataSourceDefinition getDefinitionsOrNull(String dataStoreCode,
+                String dataSourceCode, Map<Type, String> replacementsByType)
+        {
+            if (dataSourceCode == null)
+            {
+                return null;
+            }
+            Map<String, DataSourceDefinition> definitionsByCode =
+                    dataSourceDefinitionsByCodes.get(dataStoreCode);
+            if (definitionsByCode == null)
+            {
+                return null;
+            }
+            DataSourceDefinition definition = definitionsByCode.get(dataSourceCode);
+            if (definition != null)
+            {
+                definition = definition.clone();
+                Set<Entry<Type, String>> entrySet = replacementsByType.entrySet();
+                for (Entry<Type, String> entry : entrySet)
+                {
+                    entry.getKey().modify(definition, entry.getValue());
+                }
+            }
+            return definition;
+        }
+
+        public void handle(String dataStoreCode, List<DataSourceDefinition> dataSourceDefinitions)
+        {
+            Map<String, DataSourceDefinition> definitionsByCode =
+                    dataSourceDefinitionsByCodes.get(dataStoreCode);
+            if (definitionsByCode == null)
+            {
+                definitionsByCode = new HashMap<String, DataSourceDefinition>();
+                dataSourceDefinitionsByCodes.put(dataStoreCode, definitionsByCode);
+            }
+            for (DataSourceDefinition definition : dataSourceDefinitions)
+            {
+                definitionsByCode.put(definition.getCode(), definition);
+            }
+        }
+
+        private static final class MappingEntry
+        {
+            private final Pattern dssCodePattern;
+
+            private final Pattern moduleCodePattern;
+
+            private final Type type;
+
+            private final String value;
+
+            public MappingEntry(Pattern dssCodePattern, Pattern moduleCodePattern, String typeName,
+                    String value)
+            {
+                this.dssCodePattern = dssCodePattern;
+                this.moduleCodePattern = moduleCodePattern;
+                type = Type.getType(typeName);
+                this.value = type.valueInUpperCase ? value.toUpperCase() : value;
+            }
+
+            public boolean matches(String dataStoreCode, String moduleCode)
+            {
+                if (dssCodePattern.matcher(dataStoreCode).matches() == false)
+                {
+                    return false;
+                }
+                return moduleCodePattern.matcher(moduleCode).matches();
+            }
+        }
+
+        private static enum Type
+        {
+            HOST_PART("host-part")
+            {
+                @Override
+                public void modify(DataSourceDefinition definition, String value)
+                {
+                    definition.setHostPart(value);
+                }
+            },
+            USERNAME("username")
+            {
+                @Override
+                public void modify(DataSourceDefinition definition, String value)
+                {
+                    definition.setUsername(value);
+                }
+            },
+            PASSWORD("password")
+            {
+                @Override
+                public void modify(DataSourceDefinition definition, String value)
+                {
+                    definition.setPassword(value);
+                }
+            },
+            SID("sid")
+            {
+                @Override
+                public void modify(DataSourceDefinition definition, String value)
+                {
+                    definition.setSid(value);
+                }
+            },
+            CONFIG("config", true), DATA_SOURCE("data-source-code");
+
+            static Type getType(String typeName)
+            {
+                Type[] values = Type.values();
+                CommaSeparatedListBuilder builder = new CommaSeparatedListBuilder();
+                for (Type type : values)
+                {
+                    if (type.name.equals(typeName))
+                    {
+                        return type;
+                    }
+                    builder.append(type.name);
+                }
+
+                throw new IllegalArgumentException("Unknown type '" + typeName
+                        + "', possible values are: " + builder);
+            }
+
+            private final String name;
+
+            private final boolean valueInUpperCase;
+
+            private Type(String name)
+            {
+                this(name, false);
+            }
+
+            private Type(String name, boolean valueInUpperCase)
+            {
+                this.name = name;
+                this.valueInUpperCase = valueInUpperCase;
+            }
+
+            public void modify(DataSourceDefinition definition, String value)
+            {
+            }
+        }
+    }
+
+    private static final class Mapping
+    {
+        private final String dataStoreCode;
+
+        private final String configKey;
+
+        private final DataSourceDefinition definitionOrNull;
+
+        public Mapping(String dataStoreCode, String configKey, DataSourceDefinition definitionOrNull)
+        {
+            this.dataStoreCode = dataStoreCode;
+            this.configKey = configKey;
+            this.definitionOrNull = definitionOrNull;
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            if (obj instanceof Mapping == false)
+            {
+                return false;
+            }
+            Mapping that = (Mapping) obj;
+            return this.configKey.equals(that.configKey)
+                    && (this.definitionOrNull == null ? null == that.definitionOrNull
+                            : this.definitionOrNull.equals(that.definitionOrNull));
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int sum = definitionOrNull == null ? 0 : definitionOrNull.hashCode();
+            return 37 * sum + configKey.hashCode();
+        }
+
+        @Override
+        public String toString()
+        {
+            return configKey + "[" + (definitionOrNull == null ? "?" : definitionOrNull) + "]";
+        }
+
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSourceProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSourceProvider.java
index 1029fe68deed5a2041bcf209cf11f8faa74c6289..3113ab225ba6f18a0cc4fee04b1cdb07fade23a2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSourceProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataSourceProvider.java
@@ -28,15 +28,6 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
  */
 public interface IDataSourceProvider
 {
-    /**
-     * Returns an appropriated data source for specified data set code and technology.
-     * 
-     * @throws IllegalArgumentException if getting data source by data set code isn't supported for
-     *             the specified technology.
-     * @throws UserFailureException if the specified data set doesn't exist.
-     */
-    public DataSource getDataSourceByDataSetCode(String dataSetCode, String technology);
-
     /**
      * Returns an appropriated data source for specified data store server code and technology.
      * 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataStoreDataSourceManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataStoreDataSourceManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e55215c9b1a717660e69edb8acdcb460ea582598
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IDataStoreDataSourceManager.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server.dataaccess;
+
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
+
+/**
+ * Handles data sources provided by DSS.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public interface IDataStoreDataSourceManager
+{
+    /**
+     * Handles specified data source definitions received from specified data store.
+     */
+    public void handle(String dataStoreCode, List<DataSourceDefinition> dataSourceDefinitions);
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceDefinition.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceDefinition.java
new file mode 100644
index 0000000000000000000000000000000000000000..23444811ea85c6c886e62a783c312c853f820973
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceDefinition.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.shared.dto;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
+import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+
+/**
+ * Data source definition.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class DataSourceDefinition implements Serializable, Cloneable
+{
+    private static final String DEFINITIONS_DELIM = "\n";
+
+    private static final String ATTRIBUTE_DELIM = "\t";
+
+    private static final long serialVersionUID = IServer.VERSION;
+
+    /**
+     * Creates an instance based on specified context object.
+     */
+    public static DataSourceDefinition createFromContext(DatabaseConfigurationContext context)
+    {
+        DataSourceDefinition definition = new DataSourceDefinition();
+        definition.setDriverClassName(context.getDatabaseEngine().getDriverClass());
+        definition.setHostPart(context.getUrlHostPart());
+        definition.setSid(context.getDatabaseName());
+        definition.setUsername(context.getOwner());
+        definition.setPassword(context.getPassword());
+        return definition;
+    }
+
+    /**
+     * Creates a list of definitions from specified string which could be the output of
+     * {@link #toString(List)}.
+     */
+    public static List<DataSourceDefinition> listFromString(String serializedDefinitions)
+    {
+        List<DataSourceDefinition> result = new ArrayList<DataSourceDefinition>();
+        if (StringUtils.isBlank(serializedDefinitions) == false)
+        {
+            String[] definitions = serializedDefinitions.split(DEFINITIONS_DELIM);
+            for (String definition : definitions)
+            {
+                result.add(fromString(definition));
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Creates a string representation of specified definition. It can be used as an input of
+     * {@link #listFromString(String)}.
+     */
+    public static String toString(List<DataSourceDefinition> definitions)
+    {
+        StringBuilder builder = new StringBuilder();
+        for (DataSourceDefinition definition : definitions)
+        {
+            builder.append(definition).append(DEFINITIONS_DELIM);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * Creates an instance from the specified string. The input could be the output of
+     * {@link #toString()}.
+     */
+    public static DataSourceDefinition fromString(String serializedDefinition)
+    {
+        DataSourceDefinition result = new DataSourceDefinition();
+        String[] split = serializedDefinition.split(ATTRIBUTE_DELIM);
+        for (String definition : split)
+        {
+            int indexOfEqualsSign = definition.indexOf('=');
+            if (indexOfEqualsSign < 0)
+            {
+                throw new IllegalArgumentException("Missing '=': " + definition);
+            }
+            String key = definition.substring(0, indexOfEqualsSign);
+            String value = definition.substring(indexOfEqualsSign + 1);
+            String setter = "set" + StringUtils.capitalize(key);
+            try
+            {
+                Method method = DataSourceDefinition.class.getMethod(setter, String.class);
+                method.invoke(result, value);
+            } catch (Exception ex)
+            {
+                throw new IllegalArgumentException("Invalid attribute '" + key + "'.", ex);
+            }
+        }
+        return result;
+    }
+
+    private String code;
+
+    private String driverClassName;
+
+    private String hostPart;
+
+    private String sid; // aka database name
+
+    private String username;
+
+    private String password;
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public void setCode(String code)
+    {
+        this.code = code;
+    }
+
+    public String getDriverClassName()
+    {
+        return driverClassName;
+    }
+
+    public void setDriverClassName(String driverClassName)
+    {
+        this.driverClassName = driverClassName;
+    }
+
+    public String getHostPart()
+    {
+        return hostPart;
+    }
+
+    public void setHostPart(String hostPart)
+    {
+        this.hostPart = hostPart;
+    }
+
+    public String getSid()
+    {
+        return sid;
+    }
+
+    public void setSid(String sid)
+    {
+        this.sid = sid;
+    }
+
+    public String getUsername()
+    {
+        return username;
+    }
+
+    public void setUsername(String username)
+    {
+        this.username = username;
+    }
+
+    public String getPassword()
+    {
+        return password;
+    }
+
+    public void setPassword(String password)
+    {
+        this.password = password;
+    }
+
+    @Override
+    public DataSourceDefinition clone()
+    {
+        try
+        {
+            return (DataSourceDefinition) super.clone();
+        } catch (CloneNotSupportedException ex)
+        {
+            throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj instanceof DataSourceDefinition == false)
+        {
+            return false;
+        }
+        DataSourceDefinition that = (DataSourceDefinition) obj;
+        return equals(this.code, that.code) && equals(this.driverClassName, that.driverClassName)
+                && equals(this.hostPart, that.hostPart) && equals(this.sid, that.sid)
+                && equals(this.username, that.username) && equals(this.password, that.password);
+    }
+
+    private boolean equals(String thisStringOrNull, String thatStringOrNull)
+    {
+        return thisStringOrNull == null ? thisStringOrNull == thatStringOrNull : thisStringOrNull
+                .equals(thatStringOrNull);
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int sum = hashCode(0, code);
+        sum = hashCode(sum, driverClassName);
+        sum = hashCode(sum, hostPart);
+        sum = hashCode(sum, sid);
+        sum = hashCode(sum, username);
+        sum = hashCode(sum, password);
+        return sum;
+    }
+
+    private int hashCode(int sum, String attribute)
+    {
+        return attribute == null ? 37 * sum : 37 * sum + attribute.hashCode();
+    }
+
+    /**
+     * Returns this instance as a string which allows reconstruction by applying
+     * {@link #fromString(String)}.
+     */
+    @Override
+    public String toString()
+    {
+        StringBuilder builder = new StringBuilder();
+        add(builder, "code");
+        add(builder, "driverClassName");
+        add(builder, "hostPart");
+        add(builder, "sid");
+        add(builder, "username");
+        add(builder, "password");
+        return builder.toString();
+    }
+
+    private void add(StringBuilder builder, String attributeName)
+    {
+        String getter = "get" + StringUtils.capitalize(attributeName);
+        try
+        {
+            Method method = DataSourceDefinition.class.getMethod(getter);
+            Object value = method.invoke(this);
+            if (value != null)
+            {
+                builder.append(attributeName).append('=').append(value).append(ATTRIBUTE_DELIM);
+            }
+        } catch (Exception ex)
+        {
+            throw new IllegalArgumentException("Invalid attribute '" + attributeName + "'.", ex);
+        }
+
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceWithDefinition.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceWithDefinition.java
new file mode 100644
index 0000000000000000000000000000000000000000..5cc522d68978cff93a693df356eca0b1fa5d34f6
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceWithDefinition.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.shared.dto;
+
+import javax.sql.DataSource;
+
+
+/**
+ * Bean for a {@link DataSource} together with its {@link DataSourceDefinition}.
+ *
+ * @author Franz-Josef Elmer
+ */
+public class DataSourceWithDefinition
+{
+    private final DataSource dataSource;
+    private final DataSourceDefinition definition;
+
+    public DataSourceWithDefinition(DataSource dataSource, DataSourceDefinition definitionOrNull)
+    {
+        if (dataSource == null)
+        {
+            throw new IllegalArgumentException("Unspecified data source.");
+        }
+        this.dataSource = dataSource;
+        this.definition = definitionOrNull;
+    }
+
+    public DataSource getDataSource()
+    {
+        return dataSource;
+    }
+
+    public DataSourceDefinition getDefinitionOrNull()
+    {
+        return definition;
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataStoreServerInfo.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataStoreServerInfo.java
index ed023659be616e1643a9bfbcf6831aced48ab59e..5f858101c4e5d0c589d1615f278d9397c87e3f07 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataStoreServerInfo.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataStoreServerInfo.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.generic.shared.dto;
 
 import java.io.Serializable;
+import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -54,6 +55,8 @@ public class DataStoreServerInfo implements Serializable
 
     private DatastoreServiceDescriptions servicesDescriptions;
 
+    private List<DataSourceDefinition> dataSourceDefinitions;
+
     private boolean archiverConfigured;
 
     private int timeoutInMinutes;
@@ -142,4 +145,14 @@ public class DataStoreServerInfo implements Serializable
         this.timeoutInMinutes = timeoutInMinutes;
     }
 
+    public List<DataSourceDefinition> getDataSourceDefinitions()
+    {
+        return dataSourceDefinitions;
+    }
+
+    public void setDataSourceDefinitions(List<DataSourceDefinition> dataSourceDefinitions)
+    {
+        this.dataSourceDefinitions = dataSourceDefinitions;
+    }
+
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/IDataSourceFactory.java
similarity index 55%
rename from datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceFactory.java
rename to openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/IDataSourceFactory.java
index fe5ff95eb7b9ef8fe703ac1eae716dba07ca536f..10037320e3e34fb9228b83042c4874507a72284a 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSourceFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/IDataSourceFactory.java
@@ -13,13 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package ch.systemsx.cisd.openbis.dss.generic.shared;
+package ch.systemsx.cisd.openbis.generic.shared.util;
 
 import java.util.Properties;
 
-import javax.sql.DataSource;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceWithDefinition;
 
-interface IDataSourceFactory
+/**
+ * Factory of a {@link DataSourceWithDefinition}.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public interface IDataSourceFactory
 {
-    DataSource create(Properties dbProps);
+    /**
+     * Creates a data source optional definition from specified properties. Note, that if the
+     * definition is provided its code attribute might be undefined.
+     */
+    public DataSourceWithDefinition create(Properties dbProps);
 }
\ No newline at end of file
diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml
index 2656059f3259b3aa4ead3cb1a879ef65758423ea..bf4e1fb663c24fe92c8b41a7787708dbea4f1b0c 100644
--- a/openbis/source/java/genericApplicationContext.xml
+++ b/openbis/source/java/genericApplicationContext.xml
@@ -117,7 +117,13 @@
           class="ch.systemsx.cisd.openbis.generic.server.DataStoreServiceRegistrator">
         <constructor-arg ref="dao-factory" />
     </bean>
-          
+
+    <bean id="dss-based-data-source-provider" 
+          class="ch.systemsx.cisd.openbis.generic.server.dataaccess.DataStoreServerBasedDataSourceProvider">
+        <constructor-arg ref="dao-factory" />
+        <constructor-arg value="etc/dss-datasource-mapping" />
+    </bean>
+    
     <!-- 
         // Common
     -->
@@ -198,6 +204,7 @@
         <constructor-arg ref="trusted-origin-domain-provider" />
         <constructor-arg ref="etl-entity-operation-checker" />
         <constructor-arg ref="data-store-service-registrator" />
+        <constructor-arg ref="dss-based-data-source-provider" />
         <property name="conversationClient" ref="service-conversation-client-manager" />
         <property name="conversationServer" ref="service-conversation-server-manager" />
     </bean>
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java
index af48d604111ec832cc9b27cc788a55a99ce3a8ad..9a878b07e8bd904c5032b58767c43c1bdb2ad7f8 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/ETLServiceTest.java
@@ -43,6 +43,7 @@ import ch.systemsx.cisd.openbis.generic.server.business.IDataStoreServiceFactory
 import ch.systemsx.cisd.openbis.generic.server.business.IServiceConversationClientManagerLocal;
 import ch.systemsx.cisd.openbis.generic.server.business.IServiceConversationServerManagerLocal;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDataStoreDataSourceManager;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.PersistencyResources;
 import ch.systemsx.cisd.openbis.generic.shared.AbstractServerTestCase;
 import ch.systemsx.cisd.openbis.generic.shared.CommonTestUtils;
@@ -95,6 +96,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataStoreServicePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatastoreServiceDescriptions;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
@@ -167,6 +169,8 @@ public class ETLServiceTest extends AbstractServerTestCase
 
     private PersonPE sessionPerson;
 
+    private IDataStoreDataSourceManager dataSourceManager;
+
     @Override
     @BeforeMethod
     @SuppressWarnings("unchecked")
@@ -178,6 +182,7 @@ public class ETLServiceTest extends AbstractServerTestCase
         dataStoreService = context.mock(IDataStoreService.class);
         entityOperationChecker = context.mock(IETLEntityOperationChecker.class);
         dataStoreServiceRegistrator = context.mock(IDataStoreServiceRegistrator.class);
+        dataSourceManager = context.mock(IDataStoreDataSourceManager.class);
         conversationClient = context.mock(IServiceConversationClientManagerLocal.class);
         conversationServer = context.mock(IServiceConversationServerManagerLocal.class);
         sessionManagerForEntityOperations =
@@ -307,6 +312,8 @@ public class ETLServiceTest extends AbstractServerTestCase
                     will(returnValue(IDataStoreService.VERSION));
 
                     allowing(dataStoreDAO).createOrUpdateDataStore(with(dataStoreRecordingMatcher));
+
+                    one(dataSourceManager).handle(DSS_CODE, info.getDataSourceDefinitions());
                 }
             });
 
@@ -374,6 +381,8 @@ public class ETLServiceTest extends AbstractServerTestCase
                     will(returnValue(IDataStoreService.VERSION));
 
                     allowing(dataStoreDAO).createOrUpdateDataStore(with(dataStoreRecordingMatcher));
+
+                    one(dataSourceManager).handle(DSS_CODE, info.getDataSourceDefinitions());
                 }
             });
 
@@ -1510,7 +1519,7 @@ public class ETLServiceTest extends AbstractServerTestCase
         ETLService etlService =
                 new ETLService(authenticationService, sessionManager, daoFactory,
                         propertiesBatchManager, boFactory, dssfactory, null,
-                        entityOperationChecker, dataStoreServiceRegistrator,
+                        entityOperationChecker, dataStoreServiceRegistrator, dataSourceManager,
                         sessionManagerForEntityOperations);
         etlService.setConversationClient(conversationClient);
         etlService.setConversationServer(conversationServer);
@@ -1534,6 +1543,10 @@ public class ETLServiceTest extends AbstractServerTestCase
         DatastoreServiceDescriptions services =
                 new DatastoreServiceDescriptions(reporting, processing);
         info.setServicesDescriptions(services);
+        DataSourceDefinition dataSourceDefinition = new DataSourceDefinition();
+        dataSourceDefinition.setCode("my_db");
+        dataSourceDefinition.setDriverClassName("my.class");
+        info.setDataSourceDefinitions(Arrays.asList(dataSourceDefinition));
         return info;
     }
 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProviderTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProviderTest.java
index 1f6c4d9dbe513b9a6615151b2caae89145e815c4..581d2c7657d9e9a72dd78b84965d910104e31fcb 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProviderTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/DataStoreServerBasedDataSourceProviderTest.java
@@ -18,45 +18,96 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess;
 
 import static ch.systemsx.cisd.openbis.generic.server.dataaccess.DataStoreServerBasedDataSourceProvider.DATA_STORE_SERVERS_KEY;
 
+import java.io.File;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map.Entry;
 import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
 
 import javax.sql.DataSource;
 
-import org.apache.commons.dbcp.BasicDataSource;
+import org.jmock.Expectations;
 import org.jmock.Mockery;
-import org.testng.AssertJUnit;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
+import ch.systemsx.cisd.dbmigration.DatabaseEngine;
+import ch.systemsx.cisd.dbmigration.MonitoringDataSource;
+import ch.systemsx.cisd.dbmigration.SimpleDatabaseConfigurationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSourceWithDefinition;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.util.IDataSourceFactory;
 
 /**
  * @author Franz-Josef Elmer
  */
-public class DataStoreServerBasedDataSourceProviderTest extends AssertJUnit
+public class DataStoreServerBasedDataSourceProviderTest extends AbstractFileSystemTestCase
 {
+    private static final String DRIVER_CLASS = DatabaseEngine.POSTGRESQL.getDriverClass();
+
+    private static class MockDataSource extends MonitoringDataSource
+    {
+        private final Properties properties;
+
+        private boolean closed;
+
+        MockDataSource(Properties properties)
+        {
+            this.properties = properties;
+        }
+
+        @Override
+        public synchronized void close() throws SQLException
+        {
+            closed = true;
+        }
+    }
+
     private Mockery context;
 
-    private IDAOFactory daoFactory;
+    private IDAOFactory daofactory;
 
-    private DataStoreServerBasedDataSourceProvider dataSourceProvider;
+    private File mappingFile;
 
+    private IDataStoreDAO dataStoreDAO;
+
+    private Properties props;
+
+    @Override
     @BeforeMethod
     public void setUp()
     {
         context = new Mockery();
-        daoFactory = context.mock(IDAOFactory.class);
-        dataSourceProvider = new DataStoreServerBasedDataSourceProvider(daoFactory);
-        Properties props = new Properties();
-        props.setProperty(DATA_STORE_SERVERS_KEY, "dss1, dss2[tech1], dss2[tech2]");
-        props.setProperty("dss1.database-driver", "org.postgresql.Driver");
-        props.setProperty("dss1.database-url", "jdbc:postgresql://localhost/db1");
-        props.setProperty("dss2[tech1].database-driver", "org.postgresql.Driver");
-        props.setProperty("dss2[tech1].database-url", "jdbc:postgresql://localhost/db21");
-        props.setProperty("dss2[tech2].database-driver", "org.postgresql.Driver");
-        props.setProperty("dss2[tech2].database-url", "jdbc:postgresql://localhost/db22");
-        dataSourceProvider.init(props);
+        daofactory = context.mock(IDAOFactory.class);
+        dataStoreDAO = context.mock(IDataStoreDAO.class);
+        mappingFile = new File(workingDirectory, "mapping.txt");
+        context.checking(new Expectations()
+            {
+                {
+                    allowing(daofactory).getDataStoreDAO();
+                    will(returnValue(dataStoreDAO));
+                }
+            });
+        DataSourceConfigBuilder builder = new DataSourceConfigBuilder();
+        builder.plugin("dss1", null).driver("org.postgresql.Driver")
+                .url("jdbc:postgresql://localhost/db1");
+        builder.plugin("dss2", "tech1").driver("org.postgresql.Driver")
+                .url("jdbc:postgresql://localhost/db21");
+        builder.plugin("dss2", "tech2").driver("org.postgresql.Driver")
+                .url("jdbc:postgresql://localhost/db22");
+        props = builder.get();
     }
 
     @AfterMethod
@@ -68,40 +119,288 @@ public class DataStoreServerBasedDataSourceProviderTest extends AssertJUnit
     @Test
     public void testGetDataSourceByDataStoreServerCode()
     {
-        assertURL("jdbc:postgresql://localhost/db1",
-                dataSourceProvider.getDataSourceByDataStoreServerCode("dss1", "my-tech"));
-        assertURL("jdbc:postgresql://localhost/db21",
-                dataSourceProvider.getDataSourceByDataStoreServerCode("dss2", "tech1"));
-        assertURL("jdbc:postgresql://localhost/db22",
-                dataSourceProvider.getDataSourceByDataStoreServerCode("dss2", "tech2"));
+        prepareListDataStores();
+        DataStoreServerBasedDataSourceProvider dataSourceProvider = createDataSourceProvider();
 
+        DataSource dataSource =
+                dataSourceProvider.getDataSourceByDataStoreServerCode("dss1", "my-tech");
+
+        assertDataSourceProps("[database-driver=org.postgresql.Driver, "
+                + "database-url=jdbc:postgresql://localhost/db1]", dataSource);
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testGetDataSourceByDataStoreServerCodeAndModuleCode()
+    {
+        prepareListDataStores();
+        DataStoreServerBasedDataSourceProvider dataSourceProvider = createDataSourceProvider();
+
+        DataSource dataSource =
+                dataSourceProvider.getDataSourceByDataStoreServerCode("dss2", "tech1");
+
+        assertDataSourceProps("[database-driver=org.postgresql.Driver, "
+                + "database-url=jdbc:postgresql://localhost/db21]", dataSource);
         context.assertIsSatisfied();
     }
 
     @Test
     public void testGetDataSourceByDataStoreServerCodeNotFound()
     {
+        prepareListDataStores();
+        DataStoreServerBasedDataSourceProvider dataSourceProvider = createDataSourceProvider();
+
         try
         {
             dataSourceProvider.getDataSourceByDataStoreServerCode("dss2", "my-tech");
-            fail("ConfigurationFailureException expected");
-        } catch (ConfigurationFailureException ex)
+            fail("EnvironmentFailureException expected");
+        } catch (EnvironmentFailureException ex)
         {
-            assertEquals(
-                    "No data source configured for Data Store Server 'dss2' and technology 'my-tech'.",
+            assertEquals("Couldn't find data source core plugin 'DSS2[MY-TECH]' nor 'DSS2'.",
                     ex.getMessage());
         }
 
         context.assertIsSatisfied();
     }
 
-    void assertURL(String expectedURL, DataSource dataSource)
+    /**
+     * This use case simulates the following use case:
+     * <ol>
+     * <li>Three DSS instances all using imaging_db
+     * <li>DSS1 and DSS2 using a DB at AS.
+     * <li>DSS3 using a DB at DSS.
+     * </ol>
+     * The data source instances for DSS1 and DSS2 should be the same.
+     */
+    @Test
+    public void testThreeDssDBOneAtDSSTwoOnAS()
     {
-        assertNotNull(dataSource);
-        if (dataSource instanceof BasicDataSource)
+        DataSourceConfigBuilder builder = new DataSourceConfigBuilder();
+        builder.plugin("all", "screening").property("key", "all[screening]");
+        props = builder.get();
+        FileUtilities.writeToFile(mappingFile, "# example mapping file\n"
+                + "*.proteomics.config = all[proteomics]\n"
+                + "*.proteomics.data-source-code = proteomics_db\n"
+                + "*.screening.config = all[screening]\n"
+                + "*.screening.data-source-code = imaging_db\n"
+                + "*.screening.host-part = localhost:1234\n" + "*.screening.username = openbis\n"
+                + "*.screening.password = abcd\n" + "DSS3.screening.host-part = a.b.c\n");
+        DataStorePE dss1 =
+                dataStore(
+                        "DSS1",
+                        new DataSourceDefinitionBuilder().code("imaging_db")
+                                .driverClassName(DRIVER_CLASS).hostPart("abc").sid("imaging_dev")
+                                .username("dss1").password("42").get());
+        DataStorePE dss2 =
+                dataStore(
+                        "DSS2",
+                        new DataSourceDefinitionBuilder().code("imaging_db")
+                                .driverClassName(DRIVER_CLASS).hostPart("123").sid("imaging_dev")
+                                .username("dss2").password("42").get());
+        DataStorePE dss3 =
+                dataStore(
+                        "DSS3",
+                        new DataSourceDefinitionBuilder().code("imaging_db")
+                                .driverClassName(DRIVER_CLASS).hostPart("def").sid("imaging_dev")
+                                .username("dss3").password("42").get());
+        prepareListDataStores(dss1, dss2, dss3);
+        DataStoreServerBasedDataSourceProvider dataSourceProvider = createDataSourceProvider();
+
+        DataSource ds1 = dataSourceProvider.getDataSourceByDataStoreServerCode("dss1", "screening");
+        DataSource ds2 = dataSourceProvider.getDataSourceByDataStoreServerCode("dss2", "screening");
+        DataSource ds3 = dataSourceProvider.getDataSourceByDataStoreServerCode("dss3", "screening");
+
+        assertDataSourceProps("[database-driver=org.postgresql.Driver, "
+                + "database-password=abcd, "
+                + "database-url=jdbc:postgresql://localhost:1234/imaging_dev, "
+                + "database-username=openbis, " + "key=all[screening]]", ds1);
+        assertDataSourceProps("[database-driver=org.postgresql.Driver, "
+                + "database-password=abcd, "
+                + "database-url=jdbc:postgresql://localhost:1234/imaging_dev, "
+                + "database-username=openbis, " + "key=all[screening]]", ds2);
+        assertSame(ds1, ds2);
+        assertDataSourceProps("[database-driver=org.postgresql.Driver, "
+                + "database-password=abcd, " + "database-url=jdbc:postgresql://a.b.c/imaging_dev, "
+                + "database-username=openbis, " + "key=all[screening]]", ds3);
+
+        context.assertIsSatisfied();
+    }
+
+    private void assertDataSourceProps(String expectedProps, DataSource dataSource)
+    {
+        Set<Entry<Object, Object>> entrySet = ((MockDataSource) dataSource).properties.entrySet();
+        List<Entry<Object, Object>> sortedProps = new ArrayList<Entry<Object, Object>>(entrySet);
+        Collections.sort(sortedProps, new Comparator<Entry<Object, Object>>()
+            {
+                @Override
+                public int compare(Entry<Object, Object> o1, Entry<Object, Object> o2)
+                {
+                    return o1.getKey().toString().compareTo(o2.getKey().toString());
+                }
+            });
+        assertEquals(expectedProps, sortedProps.toString());
+    }
+
+    private void prepareListDataStores(final DataStorePE... dataStores)
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(dataStoreDAO).listDataStores();
+                    will(returnValue(Arrays.asList(dataStores)));
+                }
+            });
+    }
+
+    private DataStorePE dataStore(String code, DataSourceDefinition... definitions)
+    {
+        DataStorePE dataStore = new DataStorePE();
+        dataStore.setCode(code);
+        String serializedDefinitions = DataSourceDefinition.toString(Arrays.asList(definitions));
+        dataStore.setSerializedDataSourceDefinitions(serializedDefinitions);
+        return dataStore;
+    }
+
+    private DataStoreServerBasedDataSourceProvider createDataSourceProvider()
+    {
+        DataStoreServerBasedDataSourceProvider dataSourceProvider =
+                new DataStoreServerBasedDataSourceProvider(daofactory, mappingFile.getPath(),
+                        new IDataSourceFactory()
+                            {
+                                @Override
+                                public DataSourceWithDefinition create(Properties dbProps)
+                                {
+                                    return new DataSourceWithDefinition(
+                                            new MockDataSource(dbProps), null);
+                                }
+                            });
+        dataSourceProvider.init(props);
+        return dataSourceProvider;
+    }
+
+    private static final class DataSourceDefinitionBuilder
+    {
+        private DataSourceDefinition definition = new DataSourceDefinition();
+
+        DataSourceDefinition get()
         {
-            BasicDataSource basicDataSource = (BasicDataSource) dataSource;
-            assertEquals(expectedURL, basicDataSource.getUrl());
+            return definition;
+        }
+
+        DataSourceDefinitionBuilder code(String code)
+        {
+            definition.setCode(code);
+            return this;
+        }
+
+        DataSourceDefinitionBuilder driverClassName(String driverClassName)
+        {
+            definition.setDriverClassName(driverClassName);
+            return this;
+        }
+
+        DataSourceDefinitionBuilder hostPart(String hostPart)
+        {
+            definition.setHostPart(hostPart);
+            return this;
+        }
+
+        DataSourceDefinitionBuilder sid(String sid)
+        {
+            definition.setSid(sid);
+            return this;
+        }
+
+        DataSourceDefinitionBuilder username(String username)
+        {
+            definition.setUsername(username);
+            return this;
+        }
+
+        DataSourceDefinitionBuilder password(String password)
+        {
+            definition.setPassword(password);
+            return this;
+        }
+    }
+
+    private static final class DataSourceConfigBuilder
+    {
+        private final Set<String> pluginKeys = new TreeSet<String>();
+
+        private final Properties properties = new Properties();
+
+        public Properties get()
+        {
+            CommaSeparatedListBuilder builder = new CommaSeparatedListBuilder();
+            for (String pluginKey : pluginKeys)
+            {
+                builder.append(pluginKey);
+            }
+            properties.setProperty(DATA_STORE_SERVERS_KEY, builder.toString());
+            return properties;
+        }
+
+        public SubConfigBuilder plugin(String dataStoreCode, String moduleCodeOrNull)
+        {
+            return new SubConfigBuilder(this, pluginkey(dataStoreCode, moduleCodeOrNull));
+        }
+
+        public DataSourceConfigBuilder property(String pluginKey, String key, String value)
+        {
+            pluginKeys.add(pluginKey);
+            return property(pluginKey + "." + key, value);
+        }
+
+        public DataSourceConfigBuilder property(String key, String value)
+        {
+            properties.setProperty(key, value);
+            return this;
+        }
+
+        private String pluginkey(String dataStoreCode, String moduleCodeOrNull)
+        {
+            return dataStoreCode + (moduleCodeOrNull == null ? "" : "[" + moduleCodeOrNull + "]");
+        }
+    }
+
+    private static final class SubConfigBuilder
+    {
+        private final DataSourceConfigBuilder builder;
+
+        private final String pluginKey;
+
+        SubConfigBuilder(DataSourceConfigBuilder builder, String pluginKey)
+        {
+            this.builder = builder;
+            this.pluginKey = pluginKey;
+        }
+
+        public SubConfigBuilder driver(String value)
+        {
+            return property(SimpleDatabaseConfigurationContext.DRIVER_KEY, value);
+        }
+
+        public SubConfigBuilder url(String value)
+        {
+            return property(SimpleDatabaseConfigurationContext.URL_KEY, value);
+        }
+
+        public SubConfigBuilder user(String value)
+        {
+            return property(SimpleDatabaseConfigurationContext.USER_KEY, value);
+        }
+
+        public SubConfigBuilder password(String value)
+        {
+            return property(SimpleDatabaseConfigurationContext.PASSWORD_KEY, value);
+        }
+
+        public SubConfigBuilder property(String key, String value)
+        {
+            builder.property(pluginKey, key, value);
+            return this;
         }
     }
+
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceDefinitionTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceDefinitionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..346c4013c20654aca478b2dfe0e07fa22df4ce4a
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSourceDefinitionTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.shared.dto;
+
+import java.util.List;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class DataSourceDefinitionTest extends AssertJUnit
+{
+    @Test
+    public void testToString()
+    {
+        DataSourceDefinition definition = new DataSourceDefinition();
+        definition.setCode("ABC");
+        definition.setDriverClassName("my.driver");
+        definition.setPassword("</[?a&\"'");
+
+        assertEquals("code=ABC\tdriverClassName=my.driver\tpassword=</[?a&\"'\t",
+                definition.toString());
+    }
+
+    @Test
+    public void testFromString()
+    {
+        String example = "code=Alpha\thostPart=abc:8889\tsid=my_db\tpassword=1=2^2&<7>?\"abc\"\t";
+
+        DataSourceDefinition definition = DataSourceDefinition.fromString(example);
+
+        assertEquals("Alpha", definition.getCode());
+        assertEquals("my_db", definition.getSid());
+        assertEquals(null, definition.getDriverClassName());
+        assertEquals("abc:8889", definition.getHostPart());
+        assertEquals(null, definition.getUsername());
+        assertEquals("1=2^2&<7>?\"abc\"", definition.getPassword());
+        assertEquals(example, definition.toString());
+    }
+
+    @Test
+    public void testListFromString()
+    {
+        String examples = "code=a\tsid=my_db\t\ncode=b\tusername=einstein\t\n";
+
+        List<DataSourceDefinition> definitions = DataSourceDefinition.listFromString(examples);
+
+        assertEquals("[code=a\tsid=my_db\t, code=b\tusername=einstein\t]", definitions.toString());
+        assertEquals(examples, DataSourceDefinition.toString(definitions));
+    }
+
+    @Test
+    public void testListFromEmptyString()
+    {
+        List<DataSourceDefinition> definitions = DataSourceDefinition.listFromString("");
+
+        assertEquals("[]", definitions.toString());
+    }
+
+    @Test
+    public void testCreateFromContext()
+    {
+        DatabaseConfigurationContext context = new DatabaseConfigurationContext();
+        context.setDatabaseEngineCode("postgresql");
+        context.setUrlHostPart("my-db:4711");
+        context.setBasicDatabaseName("openbis");
+        context.setDatabaseKind("dev");
+        context.setOwner("albert");
+        context.setPassword("Einstein");
+        DataSourceDefinition definition = DataSourceDefinition.createFromContext(context);
+
+        assertEquals("driverClassName=org.postgresql.Driver\thostPart=my-db:4711\t"
+                + "sid=openbis_dev\tusername=albert\tpassword=Einstein\t", definition.toString());
+    }
+}
diff --git a/rtd_phosphonetx/source/java/proteomics-plugin-applicationContext.xml b/rtd_phosphonetx/source/java/proteomics-plugin-applicationContext.xml
index 59a6dcaf5320bc073c9eb81ddcc17d5e059d485e..9051fee4dd0cc826dd4abe93c00053717f1831ac 100644
--- a/rtd_phosphonetx/source/java/proteomics-plugin-applicationContext.xml
+++ b/rtd_phosphonetx/source/java/proteomics-plugin-applicationContext.xml
@@ -7,11 +7,6 @@
                         http://www.springframework.org/schema/tx
                         http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
     
-    <bean id="dss-based-data-source-provider" class="ch.systemsx.cisd.openbis.generic.server.dataaccess.DataStoreServerBasedDataSourceProvider">
-        <constructor-arg ref="dao-factory"/>
-    </bean>
-    
-    
     <bean id="proteomics-dao-factory"
           class="ch.systemsx.cisd.openbis.plugin.proteomics.server.dataaccess.db.PhosphoNetXDAOFactory">
         <constructor-arg ref="dss-based-data-source-provider"/>
diff --git a/screening/source/java/screening-plugin-applicationContext.xml b/screening/source/java/screening-plugin-applicationContext.xml
index 0bf118996a2ac41364ffd1061ecf1ff6037ae6e5..55dac4fadbe848f2947e300c2e61e380229f575b 100644
--- a/screening/source/java/screening-plugin-applicationContext.xml
+++ b/screening/source/java/screening-plugin-applicationContext.xml
@@ -7,10 +7,6 @@
                         http://www.springframework.org/schema/tx
                         http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
 
-    <bean id="dss-based-data-source-provider" class="ch.systemsx.cisd.openbis.generic.server.dataaccess.DataStoreServerBasedDataSourceProvider">
-        <constructor-arg ref="dao-factory"/>
-    </bean>
-    
     <bean id="screening-dao-factory"
           class="ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.db.ScreeningDAOFactory">
         <constructor-arg ref="dss-based-data-source-provider"/>