fixes issue 34816: Support a second database for reporting
authorCarlos Aristu <carlos.aristu@openbravo.com>
Mon, 23 Jan 2017 12:55:58 +0100
changeset 31348 84e7958bae79
parent 31262 5a063205e766 (current diff)
parent 31347 df1cf5322dcf (diff)
child 31349 1f57a0054d99
fixes issue 34816: Support a second database for reporting
--- a/modules/org.openbravo.apachejdbcconnectionpool/src/org/openbravo/apachejdbcconnectionpool/ConnectionInitializerInterceptor.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/modules/org.openbravo.apachejdbcconnectionpool/src/org/openbravo/apachejdbcconnectionpool/ConnectionInitializerInterceptor.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2014-2016 Openbravo SLU
+ * All portions are Copyright (C) 2014-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -38,6 +38,8 @@
 public class ConnectionInitializerInterceptor extends JdbcInterceptor implements
     PoolInterceptorProvider {
 
+  private static final String INITIALIZED = "OB_INITIALIZED";
+
   String rbdms = (String) OBPropertiesProvider.getInstance().getOpenbravoProperties()
       .get("bbdd.rdbms");
 
@@ -49,9 +51,11 @@
   public void reset(ConnectionPool parent, PooledConnection con) {
     if (con != null) {
       HashMap<Object, Object> attributes = con.getAttributes();
-      Boolean connectionInitialized = (Boolean) attributes.get("OB_INITIALIZED");
+      Boolean connectionInitialized = (Boolean) attributes.get(INITIALIZED);
       if (connectionInitialized == null || connectionInitialized == false) {
-        SessionInfo.initDB(con.getConnection(), rbdms);
+        if (!isReadOnlyPool(parent)) {
+          SessionInfo.initDB(con.getConnection(), rbdms);
+        }
         PreparedStatement pstmt = null;
         try {
           final Properties props = OBPropertiesProvider.getInstance().getOpenbravoProperties();
@@ -69,11 +73,18 @@
             throw new OBException(e);
           }
         }
-        attributes.put("OB_INITIALIZED", true);
+        attributes.put(INITIALIZED, true);
       }
     }
   }
 
+  private boolean isReadOnlyPool(ConnectionPool connectionPool) {
+    if (connectionPool == null || connectionPool.getPoolProperties().isDefaultReadOnly() == null) {
+      return false;
+    }
+    return connectionPool.getPoolProperties().isDefaultReadOnly();
+  }
+
   @Override
   public String getPoolInterceptorsClassNames() {
     String fullClassName = this.getClass().getName();
--- a/modules/org.openbravo.apachejdbcconnectionpool/src/org/openbravo/apachejdbcconnectionpool/JdbcExternalConnectionPool.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/modules/org.openbravo.apachejdbcconnectionpool/src/org/openbravo/apachejdbcconnectionpool/JdbcExternalConnectionPool.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2014-2016 Openbravo SLU
+ * All portions are Copyright (C) 2014-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -19,12 +19,15 @@
 package org.openbravo.apachejdbcconnectionpool;
 
 import java.sql.Connection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 import javax.naming.Context;
 import javax.naming.InitialContext;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.tomcat.jdbc.pool.DataSource;
 import org.apache.tomcat.jdbc.pool.PoolProperties;
 import org.openbravo.base.exception.OBException;
@@ -37,16 +40,19 @@
 
 /**
  * JdbcExternalConnectionPool manages all the functionality of the Apache JDBC Connection Pool. This
- * class provides convenience methods to get a connection, close the pool and other actions.
+ * class can handle different pools (data sources) at the same time. All these pools are eventually
+ * making use of the Apache JDBC Connection Pool. This class provides convenience methods to get a
+ * connection from a pool, close the different pools and other actions.
  */
 public class JdbcExternalConnectionPool extends ExternalConnectionPool {
 
   final static private Logger log = LoggerFactory.getLogger(JdbcExternalConnectionPool.class);
 
-  private DataSource dataSource = null;
+  private Map<String, DataSource> availableDataSources = null;
+  private DataSource defaultDataSource = null;
 
   /**
-   * This method loads all the interceptors of apache jdbc connection pool injected with weld.
+   * This method loads all the interceptors of Apache JDBC Connection Pool injected with weld.
    */
   @Override
   public void loadInterceptors(List<PoolInterceptorProvider> interceptors) {
@@ -54,30 +60,75 @@
     for (PoolInterceptorProvider interceptor : interceptors) {
       currentInterceptors += interceptor.getPoolInterceptorsClassNames();
     }
-    this.getDataSource().setJdbcInterceptors(currentInterceptors);
+    for (DataSource ds : availableDataSources.values()) {
+      ds.setJdbcInterceptors(currentInterceptors);
+    }
   }
 
   /**
-   * Gets the data source of apache jdbc connection pool.
+   * Gets the default data source, which was obtained from the Apache JDBC Connection Pool.
+   * 
+   * @return the {@code DataSource} of the default pool
    */
   public DataSource getDataSource() {
+    if (defaultDataSource == null) {
+      defaultDataSource = availableDataSources.get(DEFAULT_POOL);
+    }
+    return defaultDataSource;
+  }
+
+  /**
+   * This method provides a connection from the default pool. The connection pool is initialized in
+   * the first call to this method.
+   * 
+   * a {@code Connection} retrieved from the default pool
+   */
+  @Override
+  public Connection getConnection() {
+    if (availableDataSources == null) {
+      initPool();
+    }
+    return getConnectionFromDS(getDataSource());
+  }
+
+  /**
+   * This method provides a connection from the pool whose name is specified as parameter. The
+   * connection pool is initialized in the first call to this method.
+   * 
+   * @param poolName
+   *          the name of the pool used to retrieve the connection
+   * @return a {@code Connection} retrieved from the pool passed as parameter
+   */
+  @Override
+  public Connection getConnection(String poolName) {
+    if (availableDataSources == null) {
+      initPool();
+    }
+    DataSource ds = getDataSourceByName(poolName);
+    return getConnectionFromDS(ds);
+  }
+
+  private DataSource getDataSourceByName(String poolName) {
+    if (DEFAULT_POOL.equals(poolName)) {
+      return getDataSource();
+    }
+    DataSource dataSource = availableDataSources.get(poolName);
+    if (dataSource == null) {
+      log.debug(
+          "Connection pool with name {} is not available, using default connection pool to retrieve the connection",
+          poolName);
+      dataSource = getDataSource();
+    }
     return dataSource;
   }
 
-  /**
-   * This method provided a connection of apache jdbc connection pool. Apache jdbc connection pool
-   * is initialized in the first call to this method.
-   */
-  @Override
-  public Connection getConnection() {
-    if (dataSource == null) {
-      initPool();
-    }
+  private Connection getConnectionFromDS(DataSource datasource) {
     Connection connection = null;
     try {
-      connection = dataSource.getConnection();
+      connection = datasource.getConnection();
+
       // All connections are setting autoCommit to true. DAL is taking into account his logical and
-      // DAL is setting autoCommint to false to maintain transactional way of working.
+      // DAL is setting autoCommit to false to maintain transactional way of working.
       connection.setAutoCommit(true);
     } catch (Exception e) {
       log.error("Error while retrieving connection: ", e);
@@ -87,23 +138,36 @@
   }
 
   private void initPool() {
-    dataSource = new DataSource();
-    dataSource.setPoolProperties(getPoolProperties());
+    availableDataSources = new HashMap<>(1);
+    DataSource defaultDS = new DataSource();
+    defaultDS.setPoolProperties(getPoolProperties(""));
+    availableDataSources.put(DEFAULT_POOL, defaultDS);
+
+    if (isReadOnlyPoolDefined()) {
+      PoolProperties p = getPoolProperties("readonly");
+      p.setDefaultReadOnly(true);
+
+      log.info("Read only pool: " + p.getUrl());
+
+      DataSource ro = new DataSource();
+      ro.setPoolProperties(p);
+      availableDataSources.put(READONLY_POOL, ro);
+    }
   }
 
-  private PoolProperties getPoolProperties() {
-    Properties poolPropertiesConfig = OBPropertiesProvider.getInstance().getOpenbravoProperties();
+  private PoolProperties getPoolProperties(String poolName) {
+    Properties props = OBPropertiesProvider.getInstance().getOpenbravoProperties();
 
     PoolProperties poolProperties = new PoolProperties();
 
     poolProperties.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"
         + "org.openbravo.apachejdbcconnectionpool.ConnectionInitializerInterceptor;");
 
-    if (SessionFactoryController.isJNDIModeOn(poolPropertiesConfig)) {
+    if (SessionFactoryController.isJNDIModeOn(props)) {
       try {
         Context initctx = new InitialContext();
         Context ctx = (Context) initctx.lookup("java:/comp/env");
-        javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup(poolPropertiesConfig
+        javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup(props
             .getProperty("JNDI.resourceName"));
         poolProperties.setDataSource(ds);
         return poolProperties;
@@ -113,12 +177,12 @@
       }
     }
 
-    String obUrl = poolPropertiesConfig.getProperty("bbdd.url");
-    String sid = poolPropertiesConfig.getProperty("bbdd.sid");
-    String driver = poolPropertiesConfig.getProperty("bbdd.driver");
-    String username = poolPropertiesConfig.getProperty("bbdd.user");
-    String password = poolPropertiesConfig.getProperty("bbdd.password");
-    String rbdms = poolPropertiesConfig.getProperty("bbdd.rdbms");
+    String obUrl = getStringProperty(props, "bbdd.url", poolName);
+    String sid = getStringProperty(props, "bbdd.sid", poolName);
+    String driver = getStringProperty(props, "bbdd.driver", poolName);
+    String username = getStringProperty(props, "bbdd.user", poolName);
+    String password = getStringProperty(props, "bbdd.password", poolName);
+    String rbdms = getStringProperty(props, "bbdd.rdbms", poolName);
 
     if ("POSTGRE".equals(rbdms)) {
       poolProperties.setUrl(obUrl + "/" + sid);
@@ -129,124 +193,138 @@
     poolProperties.setUsername(username);
     poolProperties.setPassword(password);
 
-    if (poolPropertiesConfig.getProperty("db.pool.initialSize") != null) {
-      poolProperties.setInitialSize(getIntProperty(poolPropertiesConfig, "db.pool.initialSize"));
+    if (getStringProperty(props, "db.pool.initialSize", poolName) != null) {
+      poolProperties.setInitialSize(getIntProperty(props, "db.pool.initialSize", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.maxActive") != null) {
-      poolProperties.setMaxActive(getIntProperty(poolPropertiesConfig, "db.pool.maxActive"));
+    if (getStringProperty(props, "db.pool.maxActive", poolName) != null) {
+      poolProperties.setMaxActive(getIntProperty(props, "db.pool.maxActive", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.minIdle") != null) {
-      poolProperties.setMinIdle(getIntProperty(poolPropertiesConfig, "db.pool.minIdle"));
+    if (getStringProperty(props, "db.pool.minIdle", poolName) != null) {
+      poolProperties.setMinIdle(getIntProperty(props, "db.pool.minIdle", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.timeBetweenEvictionRunsMillis") != null) {
-      poolProperties.setTimeBetweenEvictionRunsMillis(getIntProperty(poolPropertiesConfig,
-          "db.pool.timeBetweenEvictionRunsMillis"));
+    if (getStringProperty(props, "db.pool.timeBetweenEvictionRunsMillis", poolName) != null) {
+      poolProperties.setTimeBetweenEvictionRunsMillis(getIntProperty(props,
+          "db.pool.timeBetweenEvictionRunsMillis", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.minEvictableIdleTimeMillis") != null) {
-      poolProperties.setMinEvictableIdleTimeMillis(getIntProperty(poolPropertiesConfig,
-          "db.pool.minEvictableIdleTimeMillis"));
+    if (getStringProperty(props, "db.pool.minEvictableIdleTimeMillis", poolName) != null) {
+      poolProperties.setMinEvictableIdleTimeMillis(getIntProperty(props,
+          "db.pool.minEvictableIdleTimeMillis", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.removeAbandoned") != null) {
-      poolProperties.setRemoveAbandoned(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.removeAbandoned"));
+    if (getStringProperty(props, "db.pool.removeAbandoned", poolName) != null) {
+      poolProperties.setRemoveAbandoned(getBooleanProperty(props, "db.pool.removeAbandoned",
+          poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.testWhileIdle") != null) {
-      poolProperties.setTestWhileIdle(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.testWhileIdle"));
+    if (getStringProperty(props, "db.pool.testWhileIdle", poolName) != null) {
+      poolProperties.setTestWhileIdle(getBooleanProperty(props, "db.pool.testWhileIdle", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.testOnBorrow") != null) {
-      poolProperties.setTestOnBorrow(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.testOnBorrow"));
+    if (getStringProperty(props, "db.pool.testOnBorrow", poolName) != null) {
+      poolProperties.setTestOnBorrow(getBooleanProperty(props, "db.pool.testOnBorrow", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.testOnReturn") != null) {
-      poolProperties.setTestOnReturn(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.testOnReturn"));
+    if (getStringProperty(props, "db.pool.testOnReturn", poolName) != null) {
+      poolProperties.setTestOnReturn(getBooleanProperty(props, "db.pool.testOnReturn", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.validationInterval") != null) {
-      poolProperties.setValidationInterval(getIntProperty(poolPropertiesConfig,
-          "db.pool.validationInterval"));
+    if (getStringProperty(props, "db.pool.validationInterval", poolName) != null) {
+      poolProperties.setValidationInterval(getIntProperty(props, "db.pool.validationInterval",
+          poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.validationQuery") != null) {
+    if (getStringProperty(props, "db.pool.validationQuery", poolName) != null) {
+      poolProperties.setValidationQuery(getStringProperty(props, "db.pool.validationQuery",
+          poolName));
+    }
+    if (getStringProperty(props, "db.pool.defaultTransactionIsolation", poolName) != null) {
+      poolProperties.setDefaultTransactionIsolation(getIntProperty(props,
+          "db.pool.defaultTransactionIsolation", poolName));
+    }
+    if (getStringProperty(props, "db.pool.maxIdle", poolName) != null) {
+      poolProperties.setMaxIdle(getIntProperty(props, "db.pool.maxIdle", poolName));
+    }
+    if (getStringProperty(props, "db.pool.maxWait", poolName) != null) {
+      poolProperties.setMaxWait(getIntProperty(props, "db.pool.maxWait", poolName));
+    }
+    if (getStringProperty(props, "db.pool.numTestsPerEvictionRun", poolName) != null) {
+      poolProperties.setNumTestsPerEvictionRun(getIntProperty(props,
+          "db.pool.numTestsPerEvictionRun", poolName));
+    }
+    if (getStringProperty(props, "db.pool.removeAbandonedTimeout", poolName) != null) {
+      poolProperties.setRemoveAbandonedTimeout(getIntProperty(props,
+          "db.pool.removeAbandonedTimeout", poolName));
+    }
+    if (getStringProperty(props, "db.pool.accessToUnderlyingConnectionAllowed", poolName) != null) {
+      poolProperties.setAccessToUnderlyingConnectionAllowed(getBooleanProperty(props,
+          "db.pool.accessToUnderlyingConnectionAllowed", poolName));
+    }
+    if (getStringProperty(props, "db.pool.defaultAutoCommit", poolName) != null) {
+      poolProperties.setDefaultAutoCommit(getBooleanProperty(props, "db.pool.defaultAutoCommit",
+          poolName));
+    }
+    if (getStringProperty(props, "db.pool.defaultReadOnly", poolName) != null) {
+      poolProperties.setDefaultReadOnly(getBooleanProperty(props, "db.pool.defaultReadOnly",
+          poolName));
+    }
+    if (getStringProperty(props, "db.pool.logAbandoned", poolName) != null) {
+      poolProperties.setLogAbandoned(getBooleanProperty(props, "db.pool.logAbandoned", poolName));
+    }
+    if (getStringProperty(props, "db.pool.testOnConnect", poolName) != null) {
+      poolProperties.setTestOnConnect(getBooleanProperty(props, "db.pool.testOnConnect", poolName));
+    }
+    if (getStringProperty(props, "db.pool.connectionProperties", poolName) != null) {
+      poolProperties.setConnectionProperties(getStringProperty(props,
+          "db.pool.connectionProperties", poolName));
+    }
+    if (getStringProperty(props, "db.pool.defaultCatalog", poolName) != null) {
       poolProperties
-          .setValidationQuery(poolPropertiesConfig.getProperty("db.pool.validationQuery"));
+          .setDefaultCatalog(getStringProperty(props, "db.pool.defaultCatalog", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.defaultTransactionIsolation") != null) {
-      poolProperties.setDefaultTransactionIsolation(getIntProperty(poolPropertiesConfig,
-          "db.pool.defaultTransactionIsolation"));
+    if (getStringProperty(props, "db.pool.validatorClassName", poolName) != null) {
+      poolProperties.setValidatorClassName(getStringProperty(props, "db.pool.validatorClassName",
+          poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.maxIdle") != null) {
-      poolProperties.setMaxIdle(getIntProperty(poolPropertiesConfig, "db.pool.maxIdle"));
+    if (getStringProperty(props, "db.pool.initSQL", poolName) != null) {
+      poolProperties.setInitSQL(getStringProperty(props, "db.pool.initSQL", poolName));
     }
-    if (poolPropertiesConfig.getProperty("db.pool.maxWait") != null) {
-      poolProperties.setMaxWait(getIntProperty(poolPropertiesConfig, "db.pool.maxWait"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.numTestsPerEvictionRun") != null) {
-      poolProperties.setNumTestsPerEvictionRun(getIntProperty(poolPropertiesConfig,
-          "db.pool.numTestsPerEvictionRun"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.removeAbandonedTimeout") != null) {
-      poolProperties.setRemoveAbandonedTimeout(getIntProperty(poolPropertiesConfig,
-          "db.pool.removeAbandonedTimeout"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.accessToUnderlyingConnectionAllowed") != null) {
-      poolProperties.setAccessToUnderlyingConnectionAllowed(getBooleanProperty(
-          poolPropertiesConfig, "db.pool.accessToUnderlyingConnectionAllowed"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.defaultAutoCommit") != null) {
-      poolProperties.setDefaultAutoCommit(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.defaultAutoCommit"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.defaultReadOnly") != null) {
-      poolProperties.setDefaultReadOnly(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.defaultReadOnly"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.logAbandoned") != null) {
-      poolProperties.setLogAbandoned(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.logAbandoned"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.testOnConnect") != null) {
-      poolProperties.setTestOnConnect(getBooleanProperty(poolPropertiesConfig,
-          "db.pool.testOnConnect"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.connectionProperties") != null) {
-      poolProperties.setConnectionProperties(poolPropertiesConfig
-          .getProperty("db.pool.connectionProperties"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.defaultCatalog") != null) {
-      poolProperties.setDefaultCatalog(poolPropertiesConfig.getProperty("db.pool.defaultCatalog"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.validatorClassName") != null) {
-      poolProperties.setValidatorClassName(poolPropertiesConfig
-          .getProperty("db.pool.validatorClassName"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.initSQL") != null) {
-      poolProperties.setInitSQL(poolPropertiesConfig.getProperty("db.pool.initSQL"));
-    }
-    if (poolPropertiesConfig.getProperty("db.pool.name") != null) {
-      poolProperties.setName(poolPropertiesConfig.getProperty("db.pool.name"));
+    if (getStringProperty(props, "db.pool.name", poolName) != null) {
+      poolProperties.setName(getStringProperty(props, "db.pool.name", poolName));
     }
 
     return poolProperties;
   }
 
-  private boolean getBooleanProperty(Properties properties, String propertyName) {
-    return ("true".equals(properties.getProperty(propertyName)));
+  private boolean isReadOnlyPoolDefined() {
+    // to define readonly pool, its url is enough
+    return OBPropertiesProvider.getInstance().getOpenbravoProperties()
+        .containsKey("bbdd.readonly.url");
   }
 
-  private int getIntProperty(Properties properties, String propertyName) {
-    return Integer.parseInt(properties.getProperty(propertyName).trim());
+  private boolean getBooleanProperty(Properties properties, String propertyName, String poolName) {
+    return "true".equals(getStringProperty(properties, propertyName, poolName));
+  }
+
+  private int getIntProperty(Properties properties, String propertyName, String poolName) {
+    return Integer.parseInt(getStringProperty(properties, propertyName, poolName).trim());
+  }
+
+  /** gets specific property for pool if present, default property if not */
+  private String getStringProperty(Properties props, String key, String poolName) {
+    if (StringUtils.isEmpty(poolName)) {
+      // return default property if the pool name is not provided
+      return props.getProperty(key);
+    }
+    String poolSpecificKey = key.replaceFirst("\\.", "." + poolName + ".");
+    return props.containsKey(poolSpecificKey) ? props.getProperty(poolSpecificKey) : props
+        .getProperty(key);
   }
 
   /**
-   * This method closes apache jdbc connection pool.
+   * This method closes all the data sources retrieved from the Apache JDBC Connection Pool.
    */
   @Override
   public void closePool() {
-    DataSource ds = getDataSource();
-    if (ds != null) {
-      // Closes the pool and all idle connections. true parameter is for close the active
-      // connections too.
-      ds.close(true);
+    for (DataSource ds : availableDataSources.values()) {
+      if (ds != null) {
+        // Closes the pool and all idle connections. true parameter is for close the active
+        // connections too.
+        ds.close(true);
+      }
     }
     super.closePool();
   }
--- a/modules/org.openbravo.client.application/src/org/openbravo/client/application/report/ReportingUtils.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/modules/org.openbravo.client.application/src/org/openbravo/client/application/report/ReportingUtils.java	Mon Jan 23 12:55:58 2017 +0100
@@ -943,8 +943,9 @@
 
       if (jasperFilePath.endsWith("jrxml")) {
         String strBaseDesign = getBaseDesignPath();
-        JasperReport jReport = getTranslatedJasperReport(new DalConnectionProvider(false),
-            jasperFilePath, language, strBaseDesign);
+        JasperReport jReport = getTranslatedJasperReport(
+            DalConnectionProvider.getReadOnlyConnectionProvider(), jasperFilePath, language,
+            strBaseDesign);
         if (connectionProvider != null) {
           if (compileSubreports) {
             processSubReports(jasperFilePath, parameters, strBaseDesign, connectionProvider,
@@ -975,8 +976,8 @@
             }
           }
         } else {
-          jasperPrint = JasperFillManager.fillReport(jReport, parameters, OBDal.getInstance()
-              .getConnection());
+          jasperPrint = JasperFillManager.fillReport(jReport, parameters, OBDal
+              .getReadOnlyInstance().getConnection());
         }
       } else {
         jasperPrint = JasperFillManager.fillReport(jasperFilePath, parameters);
@@ -1218,7 +1219,7 @@
    *          Map of parameters where the standard process definition parameters are added.
    */
   private static void addProcessDefinitionParameters(Map<String, Object> parameters) {
-    parameters.put(JASPER_PARAM_HBSESSION, OBDal.getInstance().getSession());
+    parameters.put(JASPER_PARAM_HBSESSION, OBDal.getReadOnlyInstance().getSession());
     parameters.put(JASPER_PARAM_OBCONTEXT, OBContext.getOBContext());
 
     {
@@ -1371,7 +1372,7 @@
       this.extension = extension;
       OBContext.setAdminMode(true);
       try {
-        FileType type = OBDal.getInstance().get(FileType.class, strFileTypeId);
+        FileType type = OBDal.getReadOnlyInstance().get(FileType.class, strFileTypeId);
         if (type != null) {
           fileType = type.getFormat();
         } else {
--- a/src-core/src/org/openbravo/database/ExternalConnectionPool.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-core/src/org/openbravo/database/ExternalConnectionPool.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2014-2015 Openbravo SLU 
+ * All portions are Copyright (C) 2014-2016 Openbravo SLU 
  * All Rights Reserved. 
  ************************************************************************
  */
@@ -29,6 +29,8 @@
 public abstract class ExternalConnectionPool {
 
   static Logger log = Logger.getLogger(ExternalConnectionPool.class);
+  public static final String DEFAULT_POOL = "DEFAULT";
+  public static final String READONLY_POOL = "RO";
 
   private static ExternalConnectionPool instance;
 
@@ -52,6 +54,13 @@
   }
 
   /**
+   * @return the singleton instance of the external connection pool
+   */
+  public final static ExternalConnectionPool getInstance() {
+    return instance;
+  }
+
+  /**
    * If the external connection pool should be closed this method should be overwritten
    */
   public void closePool() {
@@ -72,4 +81,19 @@
    */
   public abstract Connection getConnection();
 
+  /**
+   * This method is intended to be overridden by external connection multi-pools. This kind of pools
+   * can handle several datasources and this method allows to select from which of them the
+   * connection should be taken.
+   * 
+   * @param poolName
+   *          The name of the external connection pool
+   * 
+   * @return A Connection from the external connection pool whose name is passed as parameter
+   * 
+   */
+  public Connection getConnection(String poolName) {
+    return getConnection();
+  }
+
 }
--- a/src-core/src/org/openbravo/database/SessionInfo.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-core/src/org/openbravo/database/SessionInfo.java	Mon Jan 23 12:55:58 2017 +0100
@@ -113,6 +113,10 @@
       PreparedStatement psQuery = null;
       PreparedStatement psCreate = null;
       try {
+        if (conn.isReadOnly()) {
+          return;
+        }
+
         psQuery = getPreparedStatement(
             conn,
             "select count(*) from information_schema.tables where table_name='ad_context_info' and table_type = 'LOCAL TEMPORARY'");
@@ -174,6 +178,9 @@
     PreparedStatement psCleanUp = null;
     PreparedStatement psInsert = null;
     try {
+      if (conn.isReadOnly()) {
+        return;
+      }
       psCleanUp = getPreparedStatement(conn, "delete from ad_context_info");
       psCleanUp.executeUpdate();
 
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_01.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_01.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2010-2016 Openbravo SLU
+ * All portions are Copyright (C) 2010-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -181,7 +181,7 @@
     String bpartnerId = "2C4C71BC828B47A0AF2A79855FD3BA7A"; // Sleep Well Hotels, Co.
     String priceListId = "8366EAF1EDF442A98377D74A199084A8"; // General Sales
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "34560A057833457D962F7A573F76F5BB"; // Ale Beer
     String taxId = "3CCDACCCF02C4D209174159A8AF43127"; // NY Sales Tax
     String docTypeId = "61D7AC2360F0417C80237B5D2131BACD"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_02.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_02.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2010-2016 Openbravo SLU
+ * All portions are Copyright (C) 2010-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -184,7 +184,7 @@
     String bpartnerId = "2C4C71BC828B47A0AF2A79855FD3BA7A"; // Sleep Well Hotels, Co.
     String priceListId = "8366EAF1EDF442A98377D74A199084A8"; // General Sales
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "34560A057833457D962F7A573F76F5BB"; // Ale Beer
     String taxId = "3CCDACCCF02C4D209174159A8AF43127"; // NY Sales Tax
     String docTypeId = "61D7AC2360F0417C80237B5D2131BACD"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_03.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_03.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2010-2016 Openbravo SLU
+ * All portions are Copyright (C) 2010-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -181,7 +181,7 @@
     String bpartnerId = "2C4C71BC828B47A0AF2A79855FD3BA7A"; // Sleep Well Hotels, Co.
     String priceListId = "8366EAF1EDF442A98377D74A199084A8"; // General Sales
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "34560A057833457D962F7A573F76F5BB"; // Ale Beer
     String taxId = "3CCDACCCF02C4D209174159A8AF43127"; // NY Sales Tax
     String docTypeId = "61D7AC2360F0417C80237B5D2131BACD"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_04.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_04.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2010-2016 Openbravo SLU
+ * All portions are Copyright (C) 2010-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -160,7 +160,7 @@
     String bpartnerId = "2C4C71BC828B47A0AF2A79855FD3BA7A"; // Sleep Well Hotels, Co.
     String priceListId = "8366EAF1EDF442A98377D74A199084A8"; // General Sales
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "34560A057833457D962F7A573F76F5BB"; // Ale Beer
     String taxId = "3CCDACCCF02C4D209174159A8AF43127"; // NY Sales Tax
     String docTypeId = "61D7AC2360F0417C80237B5D2131BACD"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_05.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_05.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2010-2016 Openbravo SLU
+ * All portions are Copyright (C) 2010-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -90,7 +90,7 @@
   public void testRunPayment_05() {
     String fruitBio = "EB3110511DAB445382CDB316DCDA407C"; // Fruit & Bio is Life, Inc.
     String happyDrinks = "C4C5C87CB62548B3B44B93FF3075FB87"; // Happy Drinks, Inc.
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     Invoice inv1;
     Invoice inv2;
     AdvPaymentMngtDao dao = new AdvPaymentMngtDao();
@@ -148,7 +148,7 @@
     // DATA SETUP
     String priceListId = "C3EA1FF8AAD8452B96AB766B8B2133A6"; // Happy Drinks Price List
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "34560A057833457D962F7A573F76F5BB"; // Ale Beer
     String taxId = "3CCDACCCF02C4D209174159A8AF43127"; // NY Sales Tax
     String docTypeId = "4F914856B90A4F25B4ABA83C5A0C25FE"; // AP Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_06.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_06.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2010-2016 Openbravo SLU
+ * All portions are Copyright (C) 2010-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -188,7 +188,7 @@
     String bpartnerId = "2C4C71BC828B47A0AF2A79855FD3BA7A"; // Sleep Well Hotels, Co.
     String priceListId = "8366EAF1EDF442A98377D74A199084A8"; // General Sales
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "34560A057833457D962F7A573F76F5BB"; // Ale Beer
     String taxId = "3CCDACCCF02C4D209174159A8AF43127"; // NY Sales Tax
     String docTypeId = "61D7AC2360F0417C80237B5D2131BACD"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_07.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_07.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2011-2016 Openbravo SLU
+ * All portions are Copyright (C) 2011-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -163,7 +163,7 @@
     String bpartnerId = "A6750F0D15334FB890C254369AC750A8"; // Alimentos y Supermercados, S.A.
     String priceListId = "AEE66281A08F42B6BC509B8A80A33C29"; // Tarifa de ventas
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "FDDBB89508D24D2C8D97A2A57BEA8788"; // Vino Tinto 0,75L
     String taxId = "4BF9470755AD4395AABCB77F5014CBE8"; // Ventas exentas
     String docTypeId = "7FCD49652E104E6BB06C3A0D787412E3"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_08.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_08.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2011-2016 Openbravo SLU
+ * All portions are Copyright (C) 2011-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -135,7 +135,7 @@
     String bpartnerId = "A6750F0D15334FB890C254369AC750A8"; // Alimentos y Supermercados, S.A.
     String priceListId = "AEE66281A08F42B6BC509B8A80A33C29"; // Tarifa de ventas
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "FDDBB89508D24D2C8D97A2A57BEA8788"; // Vino Tinto 0,75L
     String taxId = "4BF9470755AD4395AABCB77F5014CBE8"; // Ventas Exentas
     String docTypeId = "7FCD49652E104E6BB06C3A0D787412E3"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_09.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_09.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2011-2016 Openbravo SLU
+ * All portions are Copyright (C) 2011-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -161,7 +161,7 @@
     String bpartnerId = "9E6850C866BD4921AD0EB7F7796CE2C7"; // Hoteles Buenas Noches, S.A.
     String priceListId = "AEE66281A08F42B6BC509B8A80A33C29"; // Tarifa de ventas
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "FDDBB89508D24D2C8D97A2A57BEA8788"; // Vino Tinto 0,75L
     String taxId = "4BF9470755AD4395AABCB77F5014CBE8"; // Ventas Exentas
     String docTypeId = "7FCD49652E104E6BB06C3A0D787412E3"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_10.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_10.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2011-2016 Openbravo SLU
+ * All portions are Copyright (C) 2011-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -166,7 +166,7 @@
     String bpartnerId = "9E6850C866BD4921AD0EB7F7796CE2C7"; // Hoteles Buenas Noches, S.A.
     String priceListId = "AEE66281A08F42B6BC509B8A80A33C29"; // Tarifa de ventas
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "FDDBB89508D24D2C8D97A2A57BEA8788"; // Vino Tinto 0,75L
     String taxId = "4BF9470755AD4395AABCB77F5014CBE8"; // Ventas Exentas
     String docTypeId = "7FCD49652E104E6BB06C3A0D787412E3"; // AR Invoice
--- a/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_11.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/advpaymentmngt/test/PaymentTest_11.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Openbravo SLU
- * All portions are Copyright (C) 2011-2016 Openbravo SLU
+ * All portions are Copyright (C) 2011-2017 Openbravo SLU
  * All Rights Reserved.
  * Contributor(s):  ______________________________________.
  *************************************************************************
@@ -187,7 +187,7 @@
     String bpartnerId = "9E6850C866BD4921AD0EB7F7796CE2C7"; // Hoteles Buenas Noches, S.A.
     String priceListId = "AEE66281A08F42B6BC509B8A80A33C29"; // Tarifa de ventas
     String paymentTermId = "66BA1164A7394344BB9CD1A6ECEED05D"; // 30 days
-    String currencyId = "102"; // EUR
+    String currencyId = EURO_ID;
     String productId = "FDDBB89508D24D2C8D97A2A57BEA8788"; // Vino Tinto 0,75L
     String taxId = "4BF9470755AD4395AABCB77F5014CBE8"; // Ventas Exentas
     String docTypeId = "7FCD49652E104E6BB06C3A0D787412E3"; // AR Invoice
--- a/src-test/src/org/openbravo/test/base/OBBaseTest.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/base/OBBaseTest.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2014-2016 Openbravo SLU 
+ * All portions are Copyright (C) 2014-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -48,6 +48,7 @@
 import org.openbravo.dal.service.OBDal;
 import org.openbravo.database.ConnectionProvider;
 import org.openbravo.database.ConnectionProviderImpl;
+import org.openbravo.database.ExternalConnectionPool;
 import org.openbravo.exception.PoolNotFoundException;
 import org.openbravo.model.ad.access.User;
 
@@ -109,6 +110,13 @@
         reportException(e);
         throw new OBException(e);
       } finally {
+        try {
+          if (SessionHandler.isSessionHandlerPresent(ExternalConnectionPool.READONLY_POOL)) {
+            SessionHandler.getInstance().commitAndClose(ExternalConnectionPool.READONLY_POOL);
+          }
+        } catch (Exception ex) {
+          log.error("Error cleaning up read-only session", ex);
+        }
         SessionHandler.deleteSessionHandler();
         OBContext.setOBContext((OBContext) null);
       }
@@ -223,6 +231,26 @@
   protected static final String TEST_LOCATION_ID = "A21EF1AB822149BEB65D055CD91F261B";
 
   /**
+   * ISO code of the Euro currency
+   */
+  protected static final String EURO = "EUR";
+
+  /**
+   * Record ID of the Euro currency
+   */
+  protected static final String EURO_ID = "102";
+
+  /**
+   * ISO code of the US Dollar currency
+   */
+  protected static final String DOLLAR = "USD";
+
+  /**
+   * Record ID of the US Dollar currency
+   */
+  protected static final String DOLLAR_ID = "100";
+
+  /**
    * Initializes DAL, it also creates a log appender that can be used to assert on logs. This log
    * appender is disabled by default, to activate it set the level with
    * {@link OBBaseTest#setTestLogAppenderLevel(Level)}
--- a/src-test/src/org/openbravo/test/costing/TestCosting.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/costing/TestCosting.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2014-2016 Openbravo SLU
+ * All portions are Copyright (C) 2014-2017 Openbravo SLU
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -158,10 +158,6 @@
   private static String INVOICEIN_SEQUENCE_ID = "766DC632FDCE485B88F7535CF2A3422E";
   // Document Sequence with name: DocumentNo_M_Movement
   private static String MOVEMENT_SEQUENCE_ID = "07FD646511E14BADB5C1BB5CF2FCAC57";
-  // Currency with name: EUR
-  private static String CURRENCY1_ID = "102";
-  // Currency with name: USD
-  private static String CURRENCY2_ID = "100";
   // Storage Bin with name: L01
   private static String LOCATOR1_ID = "193476BDD14E4A11B651B4E3E8D767C8";
   // Storage Bin with name: L02
@@ -243,12 +239,12 @@
       OBContext.setAdminMode(true);
 
       // Set EUR currency costing precision
-      Currency currrencyEur = OBDal.getInstance().get(Currency.class, CURRENCY1_ID);
+      Currency currrencyEur = OBDal.getInstance().get(Currency.class, EURO_ID);
       currrencyEur.setCostingPrecision(4L);
       OBDal.getInstance().save(currrencyEur);
 
       // Set USD currency costing precision
-      Currency currrencyUsd = OBDal.getInstance().get(Currency.class, CURRENCY2_ID);
+      Currency currrencyUsd = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
       currrencyUsd.setCostingPrecision(4L);
       OBDal.getInstance().save(currrencyUsd);
 
@@ -259,7 +255,7 @@
 
       // Set Spain organization currency
       Organization organization = OBDal.getInstance().get(Organization.class, ORGANIZATION_ID);
-      organization.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY1_ID));
+      organization.setCurrency(OBDal.getInstance().get(Currency.class, EURO_ID));
       OBDal.getInstance().save(organization);
 
       // Set allow negatives in General Ledger
@@ -325,12 +321,12 @@
       OBContext.setAdminMode(true);
 
       // Set EUR currency costing precision
-      Currency currrencyEur = OBDal.getInstance().get(Currency.class, CURRENCY1_ID);
+      Currency currrencyEur = OBDal.getInstance().get(Currency.class, EURO_ID);
       currrencyEur.setCostingPrecision(2L);
       OBDal.getInstance().save(currrencyEur);
 
       // Set USD currency costing precision
-      Currency currrencyUsd = OBDal.getInstance().get(Currency.class, CURRENCY2_ID);
+      Currency currrencyUsd = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
       currrencyUsd.setCostingPrecision(2L);
       OBDal.getInstance().save(currrencyUsd);
 
@@ -5147,17 +5143,17 @@
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList1 = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList11 = new ArrayList<CostAdjustmentAssert>();
       costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price1).add(quantity1.multiply(price8).negate()),
+          DOLLAR_ID, "LC", quantity1.multiply(price1).add(quantity1.multiply(price8).negate()),
           day0, true, false));
-      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", quantity1.multiply(price1).add(quantity1.multiply(price10).negate()),
+      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", quantity1.multiply(price1).add(quantity1.multiply(price10).negate()), day0, true,
+          false));
+      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0),
+          DOLLAR_ID, "LC", quantity2.multiply(price2).add(quantity2.multiply(price9).negate()),
           day0, true, false));
-      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY2_ID, "LC", quantity2.multiply(price2).add(quantity2.multiply(price9).negate()),
-          day0, true, false));
-      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", quantity2.multiply(price2).add(quantity2.multiply(price11).negate()),
-          day0, true, false));
+      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", quantity2.multiply(price2).add(quantity2.multiply(price11).negate()), day0, true,
+          false));
       costAdjustmentAssertList1.add(costAdjustmentAssertLineList11);
       assertCostAdjustment(costAdjustmentList1, costAdjustmentAssertList1);
 
@@ -5166,17 +5162,17 @@
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList2 = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList21 = new ArrayList<CostAdjustmentAssert>();
       costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price1).add(quantity1.multiply(price8).negate()),
+          DOLLAR_ID, "LC", quantity1.multiply(price1).add(quantity1.multiply(price8).negate()),
           day0, true, false));
-      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", quantity1.multiply(price1).add(quantity1.multiply(price10).negate()),
+      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", quantity1.multiply(price1).add(quantity1.multiply(price10).negate()), day0, true,
+          false));
+      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0),
+          DOLLAR_ID, "LC", quantity2.multiply(price2).add(quantity2.multiply(price9).negate()),
           day0, true, false));
-      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY2_ID, "LC", quantity2.multiply(price2).add(quantity2.multiply(price9).negate()),
-          day0, true, false));
-      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", quantity2.multiply(price2).add(quantity2.multiply(price11).negate()),
-          day0, true, false));
+      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", quantity2.multiply(price2).add(quantity2.multiply(price11).negate()), day0, true,
+          false));
       costAdjustmentAssertList2.add(costAdjustmentAssertLineList21);
       assertCostAdjustment(costAdjustmentList2, costAdjustmentAssertList2);
 
@@ -5232,10 +5228,10 @@
       OBContext.setAdminMode(true);
 
       // Create a new product for the test
-      Product product1 = createProduct("testCostingLC400A", price1, CURRENCY1_ID);
-
-      // Create a new product for the test
-      Product product2 = createProduct("testCostingLC400B", price2, CURRENCY2_ID);
+      Product product1 = createProduct("testCostingLC400A", price1, EURO_ID);
+
+      // Create a new product for the test
+      Product product2 = createProduct("testCostingLC400B", price2, DOLLAR_ID);
 
       // Create purchase order and book it
       Order purchaseOrder = createPurchaseOrder(product2, price2, quantity1, day0);
@@ -5330,31 +5326,31 @@
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList1 = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList11 = new ArrayList<CostAdjustmentAssert>();
       costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY2_ID, "LC", amount1, day3, true, false));
-      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", amount2, day3, true, false));
+          DOLLAR_ID, "LC", amount1, day3, true, false));
+      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", amount2, day3, true, false));
       costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY2_ID, "LC", amount3, day3, true, false));
-      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", amount4, day3, true, false));
+          DOLLAR_ID, "LC", amount3, day3, true, false));
+      costAdjustmentAssertLineList11.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", amount4, day3, true, false));
       costAdjustmentAssertList1.add(costAdjustmentAssertLineList11);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList12 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList12.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", amount5, day3, true, false));
-      costAdjustmentAssertLineList12.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", amount6, day3, true, false));
+      costAdjustmentAssertLineList12.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", amount5, day3, true, false));
+      costAdjustmentAssertLineList12.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", amount6, day3, true, false));
       costAdjustmentAssertList1.add(costAdjustmentAssertLineList12);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList13 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList13.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", amount7, day3, true, false));
-      costAdjustmentAssertLineList13.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", amount8, day3, true, false));
+      costAdjustmentAssertLineList13.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", amount7, day3, true, false));
+      costAdjustmentAssertLineList13.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", amount8, day3, true, false));
       costAdjustmentAssertList1.add(costAdjustmentAssertLineList13);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList14 = new ArrayList<CostAdjustmentAssert>();
       costAdjustmentAssertLineList14.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY2_ID, "LC", amount9, day3, true, false));
+          DOLLAR_ID, "LC", amount9, day3, true, false));
       costAdjustmentAssertLineList14.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY2_ID, "LC", amount10, day3, true, false));
+          DOLLAR_ID, "LC", amount10, day3, true, false));
       costAdjustmentAssertList1.add(costAdjustmentAssertLineList14);
       assertCostAdjustment(costAdjustmentList1, costAdjustmentAssertList1);
 
@@ -5363,31 +5359,31 @@
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList2 = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList21 = new ArrayList<CostAdjustmentAssert>();
       costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY2_ID, "LC", amount1, day3, true, false));
-      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", amount2, day3, true, false));
+          DOLLAR_ID, "LC", amount1, day3, true, false));
+      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", amount2, day3, true, false));
       costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY2_ID, "LC", amount3, day3, true, false));
-      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", amount4, day3, true, false));
+          DOLLAR_ID, "LC", amount3, day3, true, false));
+      costAdjustmentAssertLineList21.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", amount4, day3, true, false));
       costAdjustmentAssertList2.add(costAdjustmentAssertLineList21);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList22 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList22.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", amount5, day3, true, false));
-      costAdjustmentAssertLineList22.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", amount6, day3, true, false));
+      costAdjustmentAssertLineList22.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", amount5, day3, true, false));
+      costAdjustmentAssertLineList22.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", amount6, day3, true, false));
       costAdjustmentAssertList2.add(costAdjustmentAssertLineList22);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList23 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList23.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY1_ID, "LC", amount7, day3, true, false));
-      costAdjustmentAssertLineList23.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY1_ID, "LC", amount8, day3, true, false));
+      costAdjustmentAssertLineList23.add(new CostAdjustmentAssert(transactionList2.get(0), EURO_ID,
+          "LC", amount7, day3, true, false));
+      costAdjustmentAssertLineList23.add(new CostAdjustmentAssert(transactionList1.get(0), EURO_ID,
+          "LC", amount8, day3, true, false));
       costAdjustmentAssertList2.add(costAdjustmentAssertLineList23);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList24 = new ArrayList<CostAdjustmentAssert>();
       costAdjustmentAssertLineList24.add(new CostAdjustmentAssert(transactionList2.get(0),
-          CURRENCY2_ID, "LC", amount9, day3, true, false));
+          DOLLAR_ID, "LC", amount9, day3, true, false));
       costAdjustmentAssertLineList24.add(new CostAdjustmentAssert(transactionList1.get(0),
-          CURRENCY2_ID, "LC", amount10, day3, true, false));
+          DOLLAR_ID, "LC", amount10, day3, true, false));
       costAdjustmentAssertList2.add(costAdjustmentAssertLineList24);
       assertCostAdjustment(costAdjustmentList2, costAdjustmentAssertList2);
 
@@ -7636,12 +7632,12 @@
       List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList1 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price2), day1, true, false));
+      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price2), day1, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList1);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList2 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price4), day1, true, false));
+      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price4), day1, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList2);
       assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);
 
@@ -7710,12 +7706,12 @@
       List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList1 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price4), day2, true, false));
+      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price4), day2, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList1);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList2 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price2), day2, true, false));
+      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price2), day2, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList2);
       assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);
 
@@ -7795,12 +7791,12 @@
       List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList1 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price2), day1, true, false));
+      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price2), day1, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList1);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList2 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price4), day1, true, false));
+      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price4), day1, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList2);
       assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);
 
@@ -7869,12 +7865,12 @@
       List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList1 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price4), day2, true, false));
+      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price4), day2, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList1);
       List<CostAdjustmentAssert> costAdjustmentAssertLineList2 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0),
-          CURRENCY2_ID, "LC", quantity1.multiply(price2), day2, true, false));
+      costAdjustmentAssertLineList2.add(new CostAdjustmentAssert(transactionList.get(0), DOLLAR_ID,
+          "LC", quantity1.multiply(price2), day2, true, false));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList2);
       assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);
 
@@ -8078,7 +8074,7 @@
       OBContext.setAdminMode(true);
 
       // Create a new product for the test
-      Product product = createProduct("testCostingMC444", price1, CURRENCY2_ID);
+      Product product = createProduct("testCostingMC444", price1, DOLLAR_ID);
 
       // Create purchase order and book it
       Order purchaseOrder = createPurchaseOrder(product, price1, quantity1, day0);
@@ -8173,7 +8169,7 @@
       createPurchaseInvoice(goodsReceipt1, price1, quantity1, day2);
 
       // Change organization currency
-      changeOrganizationCurrency(ORGANIZATION_ID, CURRENCY2_ID);
+      changeOrganizationCurrency(ORGANIZATION_ID, DOLLAR_ID);
 
       // Create purchase order and book it
       Order purchaseOrder2 = createPurchaseOrder(product, price2, quantity1, day3);
@@ -8191,10 +8187,10 @@
       List<ProductTransactionAssert> productTransactionAssertList1 = new ArrayList<ProductTransactionAssert>();
       productTransactionAssertList1.add(new ProductTransactionAssert(OBDal.getInstance()
           .get(ShipmentInOut.class, goodsReceipt1.getId()).getMaterialMgmtShipmentInOutLineList()
-          .get(0), CURRENCY1_ID, price1, price1));
+          .get(0), EURO_ID, price1, price1));
       productTransactionAssertList1.add(new ProductTransactionAssert(OBDal.getInstance()
           .get(ShipmentInOut.class, goodsReceipt2.getId()).getMaterialMgmtShipmentInOutLineList()
-          .get(0), CURRENCY2_ID, price4, price5));
+          .get(0), DOLLAR_ID, price4, price5));
       assertProductTransaction(product.getId(), productTransactionAssertList1);
 
       // Assert product costing
@@ -8210,9 +8206,8 @@
       List<CostAdjustment> costAdjustmentList = getCostAdjustment(product.getId());
       List<List<CostAdjustmentAssert>> costAdjustmentAssertList = new ArrayList<List<CostAdjustmentAssert>>();
       List<CostAdjustmentAssert> costAdjustmentAssertLineList1 = new ArrayList<CostAdjustmentAssert>();
-      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(1),
-          CURRENCY2_ID, "PDC", quantity1.multiply(price5).add(quantity1.multiply(price4).negate()),
-          day5, true));
+      costAdjustmentAssertLineList1.add(new CostAdjustmentAssert(transactionList.get(1), DOLLAR_ID,
+          "PDC", quantity1.multiply(price5).add(quantity1.multiply(price4).negate()), day5, true));
       costAdjustmentAssertList.add(costAdjustmentAssertLineList1);
       assertCostAdjustment(costAdjustmentList, costAdjustmentAssertList);
 
@@ -8236,7 +8231,7 @@
 
     finally {
       // Change organization currency
-      changeOrganizationCurrency(ORGANIZATION_ID, CURRENCY1_ID);
+      changeOrganizationCurrency(ORGANIZATION_ID, EURO_ID);
 
       OBContext.restorePreviousMode();
     }
@@ -8521,8 +8516,7 @@
 
   // Create a Product cloning a created one
   private Product createProduct(String name, BigDecimal purchasePrice, BigDecimal salesPrice) {
-    return createProduct(name, "I", purchasePrice, salesPrice, null, null, 0, CURRENCY1_ID, null,
-        null);
+    return createProduct(name, "I", purchasePrice, salesPrice, null, null, 0, EURO_ID, null, null);
   }
 
   // Create a Product cloning a created one
@@ -8534,22 +8528,21 @@
   // Create a Product cloning a created one
   private Product createProduct(String name, BigDecimal purchasePrice, BigDecimal cost,
       String costType, int year) {
-    return createProduct(name, "I", purchasePrice, purchasePrice, cost, costType, year,
-        CURRENCY1_ID, null, null);
+    return createProduct(name, "I", purchasePrice, purchasePrice, cost, costType, year, EURO_ID,
+        null, null);
   }
 
   // Create a Product cloning a created one
   private Product createProduct(String name, String productType, BigDecimal purchasePrice,
       BigDecimal cost, String costType, int year) {
     return createProduct(name, productType, purchasePrice, purchasePrice, cost, costType, year,
-        CURRENCY1_ID, null, null);
+        EURO_ID, null, null);
   }
 
   // Create a Product cloning a created one
   private Product createProduct(String name, List<Product> productList,
       List<BigDecimal> quantityList) {
-    return createProduct(name, null, null, null, null, null, 0, CURRENCY1_ID, productList,
-        quantityList);
+    return createProduct(name, null, null, null, null, null, 0, EURO_ID, productList, quantityList);
   }
 
   // Create a Product cloning a created one
@@ -10161,7 +10154,7 @@
           ProductPrice productPriceClone = (ProductPrice) DalUtil.copy(productPrice, false);
           setGeneralData(productPriceClone);
           if (i % 2 == 0) {
-            if (currencyId.equals(CURRENCY2_ID))
+            if (currencyId.equals(DOLLAR_ID))
               productPriceClone.setPriceListVersion(OBDal.getInstance()
                   .get(Product.class, LANDEDCOSTTYPE3_ID).getPricingProductPriceList().get(0)
                   .getPriceListVersion());
@@ -10191,7 +10184,7 @@
           productCosting.setManual(true);
           productCosting.setCostType(costType);
           productCosting.setCost(cost);
-          productCosting.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY1_ID));
+          productCosting.setCurrency(OBDal.getInstance().get(Currency.class, EURO_ID));
           productCosting.setWarehouse(OBDal.getInstance().get(Warehouse.class, WAREHOUSE1_ID));
           productCosting.setProduct(productClone);
           productClone.getMaterialMgmtCostingList().add(productCosting);
@@ -10295,7 +10288,7 @@
           .equals(
               OBDal.getInstance().get(Product.class, LANDEDCOSTTYPE3_ID)
                   .getPricingProductPriceList().get(0).getPriceListVersion())) {
-        orderClone.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY2_ID));
+        orderClone.setCurrency(OBDal.getInstance().get(Currency.class, DOLLAR_ID));
         orderClone.setPriceList(product.getPricingProductPriceList().get(0).getPriceListVersion()
             .getPriceList());
         orderClone.setBusinessPartner(OBDal.getInstance().get(BusinessPartner.class,
@@ -10303,7 +10296,7 @@
         orderClone
             .setPartnerAddress(OBDal.getInstance().get(BusinessPartner.class, BUSINESSPARTNER_ID)
                 .getBusinessPartnerLocationList().get(0));
-        orderCloneLine.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY2_ID));
+        orderCloneLine.setCurrency(OBDal.getInstance().get(Currency.class, DOLLAR_ID));
         orderCloneLine.setBusinessPartner(OBDal.getInstance().get(BusinessPartner.class,
             BUSINESSPARTNER_ID));
         orderCloneLine
@@ -11220,7 +11213,7 @@
       }
 
       else {
-        invoice.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY2_ID));
+        invoice.setCurrency(OBDal.getInstance().get(Currency.class, DOLLAR_ID));
         invoiceLine.setProduct(OBDal.getInstance().get(Product.class, landedCostTypeId));
       }
 
@@ -11265,9 +11258,9 @@
           landedCostCost.setAmount(amountList.get(i));
 
           if (landedCostTypeId.equals(LANDEDCOSTTYPE3_ID))
-            landedCostCost.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY2_ID));
+            landedCostCost.setCurrency(OBDal.getInstance().get(Currency.class, DOLLAR_ID));
           else
-            landedCostCost.setCurrency(OBDal.getInstance().get(Currency.class, CURRENCY1_ID));
+            landedCostCost.setCurrency(OBDal.getInstance().get(Currency.class, EURO_ID));
         }
 
         else {
@@ -11374,9 +11367,9 @@
       ConversionRateDoc conversion = OBProvider.getInstance().get(ConversionRateDoc.class);
       setGeneralData(conversion);
       conversion.setCurrency(purchaseInvoice.getCurrency());
-      conversion.setToCurrency(purchaseInvoice.getCurrency().getId().equals(CURRENCY1_ID) ? OBDal
-          .getInstance().get(Currency.class, CURRENCY2_ID) : OBDal.getInstance().get(
-          Currency.class, CURRENCY1_ID));
+      conversion.setToCurrency(purchaseInvoice.getCurrency().getId().equals(EURO_ID) ? OBDal
+          .getInstance().get(Currency.class, DOLLAR_ID) : OBDal.getInstance().get(Currency.class,
+          EURO_ID));
       conversion.setInvoice(purchaseInvoice);
       conversion.setRate(rate);
       conversion.setForeignAmount(purchaseInvoice.getInvoiceLineList().get(0).getLineNetAmount()
@@ -12162,9 +12155,9 @@
           criteria2.add(Restrictions.eq(ConversionRate.PROPERTY_CLIENT,
               OBDal.getInstance().get(Client.class, CLIENT_ID)));
           criteria2.add(Restrictions.eq(ConversionRate.PROPERTY_CURRENCY,
-              OBDal.getInstance().get(Currency.class, CURRENCY2_ID)));
+              OBDal.getInstance().get(Currency.class, DOLLAR_ID)));
           criteria2.add(Restrictions.eq(ConversionRate.PROPERTY_TOCURRENCY, OBDal.getInstance()
-              .get(Currency.class, CURRENCY1_ID)));
+              .get(Currency.class, EURO_ID)));
           criteria2.add(Restrictions.ge(ConversionRate.PROPERTY_VALIDTODATE, calendar.getTime()));
           BigDecimal rate = criteria2.list().get(0).getMultipleRateBy();
 
@@ -12644,14 +12637,14 @@
             criteria2.add(Restrictions.eq(ConversionRate.PROPERTY_CLIENT,
                 OBDal.getInstance().get(Client.class, CLIENT_ID)));
             criteria2.add(Restrictions.eq(ConversionRate.PROPERTY_CURRENCY, OBDal.getInstance()
-                .get(Currency.class, CURRENCY2_ID)));
+                .get(Currency.class, DOLLAR_ID)));
             criteria2.add(Restrictions.eq(ConversionRate.PROPERTY_TOCURRENCY, OBDal.getInstance()
-                .get(Currency.class, CURRENCY1_ID)));
+                .get(Currency.class, EURO_ID)));
             criteria2.add(Restrictions.ge(ConversionRate.PROPERTY_VALIDTODATE, calendar.getTime()));
             BigDecimal rate = criteria2.list().get(0).getMultipleRateBy();
 
-            if (productTransactionAssert.getCurrency().getId().equals(CURRENCY1_ID)
-                && costAdjustmentLineList.get(k - 1).getCurrency().getId().equals(CURRENCY2_ID))
+            if (productTransactionAssert.getCurrency().getId().equals(EURO_ID)
+                && costAdjustmentLineList.get(k - 1).getCurrency().getId().equals(DOLLAR_ID))
               assertEquals(
                   materialTransactionCost.getCost().setScale(4, BigDecimal.ROUND_HALF_UP),
                   costAdjustmentLineList.get(k - 1).getAdjustmentAmount().multiply(rate)
@@ -12747,7 +12740,7 @@
             productCostingAssert.getTransaction());
         assertEquals(productCosting.getCurrency(),
             productCostingAssert.getTransaction() != null ? productCostingAssert.getTransaction()
-                .getCurrency() : OBDal.getInstance().get(Currency.class, CURRENCY1_ID));
+                .getCurrency() : OBDal.getInstance().get(Currency.class, EURO_ID));
         assertEquals(productCosting.getCostType(), productCostingAssert.getType());
 
         if (productCostingAssert.getYear() != 0)
@@ -13070,7 +13063,7 @@
         BigDecimal rate;
         if ((productId != null && productId.equals(LANDEDCOSTTYPE3_ID))
             || (document.getEntityName().equals(Invoice.ENTITY_NAME) && ((Invoice) document)
-                .getCurrency().getId().equals(CURRENCY2_ID))
+                .getCurrency().getId().equals(DOLLAR_ID))
             || (document.getEntityName().equals(LandedCost.ENTITY_NAME) && ((LCReceiptLineAmt) line)
                 .getLandedCostCost()
                 .getLandedCostType()
@@ -13105,9 +13098,9 @@
             criteria.add(Restrictions.eq(ConversionRate.PROPERTY_CLIENT,
                 OBDal.getInstance().get(Client.class, CLIENT_ID)));
             criteria.add(Restrictions.eq(ConversionRate.PROPERTY_CURRENCY,
-                OBDal.getInstance().get(Currency.class, CURRENCY2_ID)));
+                OBDal.getInstance().get(Currency.class, DOLLAR_ID)));
             criteria.add(Restrictions.eq(ConversionRate.PROPERTY_TOCURRENCY, OBDal.getInstance()
-                .get(Currency.class, CURRENCY1_ID)));
+                .get(Currency.class, EURO_ID)));
             criteria.add(Restrictions.ge(ConversionRate.PROPERTY_VALIDTODATE, calendar.getTime()));
             rate = criteria.list().get(0).getMultipleRateBy();
           }
@@ -13138,7 +13131,7 @@
 
         if ((productId != null && productId.equals(LANDEDCOSTTYPE3_ID))
             || (document.getEntityName().equals(Invoice.ENTITY_NAME) && ((Invoice) document)
-                .getCurrency().getId().equals(CURRENCY2_ID))
+                .getCurrency().getId().equals(DOLLAR_ID))
             || (document.getEntityName().equals(LandedCost.ENTITY_NAME) && ((LCReceiptLineAmt) line)
                 .getLandedCostCost()
                 .getLandedCostType()
@@ -13156,10 +13149,10 @@
             .getEntityName().equals(ReceiptInvoiceMatch.ENTITY_NAME) && (line.getEntityName()
             .equals(ShipmentInOutLine.ENTITY_NAME) || (line.getEntityName().equals(
             InvoiceLine.ENTITY_NAME) && ((InvoiceLine) line).getInvoice().getCurrency()
-            .equals(CURRENCY2_ID)))))
+            .equals(DOLLAR_ID)))))
             && OBDal.getInstance().get(Organization.class, ORGANIZATION_ID).getCurrency() != null
             && OBDal.getInstance().get(Organization.class, ORGANIZATION_ID).getCurrency().getId()
-                .equals(CURRENCY2_ID)
+                .equals(DOLLAR_ID)
             && !accountingFact.getCurrency().getId()
                 .equals(accountingFact.getAccountingSchema().getCurrency().getId())) {
           Calendar calendar = Calendar.getInstance();
@@ -13169,9 +13162,9 @@
           criteria.add(Restrictions.eq(ConversionRate.PROPERTY_CLIENT,
               OBDal.getInstance().get(Client.class, CLIENT_ID)));
           criteria.add(Restrictions.eq(ConversionRate.PROPERTY_CURRENCY,
-              OBDal.getInstance().get(Currency.class, CURRENCY1_ID)));
+              OBDal.getInstance().get(Currency.class, EURO_ID)));
           criteria.add(Restrictions.eq(ConversionRate.PROPERTY_TOCURRENCY,
-              OBDal.getInstance().get(Currency.class, CURRENCY2_ID)));
+              OBDal.getInstance().get(Currency.class, DOLLAR_ID)));
           criteria.add(Restrictions.ge(ConversionRate.PROPERTY_VALIDTODATE, calendar.getTime()));
           rate = criteria.list().get(0).getMultipleRateBy();
         }
@@ -13314,10 +13307,10 @@
 
         if ((productId != null && productId.equals(LANDEDCOSTTYPE3_ID))
             || (document.getEntityName().equals(Invoice.ENTITY_NAME) && ((Invoice) document)
-                .getCurrency().getId().equals(CURRENCY2_ID))
+                .getCurrency().getId().equals(DOLLAR_ID))
             || (document.getEntityName().equals(ReceiptInvoiceMatch.ENTITY_NAME)
                 && line.getEntityName().equals(InvoiceLine.ENTITY_NAME) && ((InvoiceLine) line)
-                .getInvoice().getCurrency().getId().equals(CURRENCY2_ID))
+                .getInvoice().getCurrency().getId().equals(DOLLAR_ID))
             || (document.getEntityName().equals(LandedCost.ENTITY_NAME) && ((LCReceiptLineAmt) line)
                 .getLandedCostCost()
                 .getLandedCostType()
@@ -13332,13 +13325,13 @@
                     .getEntityName().equals(InvoiceLine.ENTITY_NAME))
                 && OBDal.getInstance().get(Organization.class, ORGANIZATION_ID).getCurrency() != null
                 && OBDal.getInstance().get(Organization.class, ORGANIZATION_ID).getCurrency()
-                    .getId().equals(CURRENCY2_ID) && !accountingFact.getCurrency().getId()
+                    .getId().equals(DOLLAR_ID) && !accountingFact.getCurrency().getId()
                 .equals(accountingFact.getAccountingSchema().getCurrency().getId()))) {
           assertEquals(accountingFact.getCurrency(),
-              OBDal.getInstance().get(Currency.class, CURRENCY2_ID));
+              OBDal.getInstance().get(Currency.class, DOLLAR_ID));
         } else {
           assertEquals(accountingFact.getCurrency(),
-              OBDal.getInstance().get(Currency.class, CURRENCY1_ID));
+              OBDal.getInstance().get(Currency.class, EURO_ID));
         }
 
         if (productId != null && productId.equals(LANDEDCOSTTYPE2_ID)) {
@@ -13597,7 +13590,7 @@
 
     public ProductTransactionAssert(ShipmentInOutLine shipmentReceiptLine,
         BigDecimal originalPrice, BigDecimal finalPrice) {
-      this(shipmentReceiptLine, null, null, null, null, CURRENCY1_ID, originalPrice, finalPrice,
+      this(shipmentReceiptLine, null, null, null, null, EURO_ID, originalPrice, finalPrice,
           finalPrice, false, false);
     }
 
@@ -13609,74 +13602,74 @@
 
     public ProductTransactionAssert(ShipmentInOutLine shipmentReceiptLine,
         BigDecimal originalPrice, BigDecimal finalPrice, boolean permanent) {
-      this(shipmentReceiptLine, null, null, null, null, CURRENCY1_ID, originalPrice, finalPrice,
+      this(shipmentReceiptLine, null, null, null, null, EURO_ID, originalPrice, finalPrice,
           finalPrice, false, permanent);
     }
 
     public ProductTransactionAssert(ShipmentInOutLine shipmentReceiptLine,
         BigDecimal originalPrice, BigDecimal finalPrice, boolean priceDifference, boolean permanent) {
-      this(shipmentReceiptLine, null, null, null, null, CURRENCY1_ID, originalPrice, finalPrice,
+      this(shipmentReceiptLine, null, null, null, null, EURO_ID, originalPrice, finalPrice,
           finalPrice, priceDifference, permanent);
     }
 
     public ProductTransactionAssert(ShipmentInOutLine shipmentReceiptLine,
         BigDecimal originalPrice, BigDecimal totalPrice, BigDecimal unitPrice) {
-      this(shipmentReceiptLine, null, null, null, null, CURRENCY1_ID, originalPrice, totalPrice,
+      this(shipmentReceiptLine, null, null, null, null, EURO_ID, originalPrice, totalPrice,
           unitPrice, false, false);
     }
 
     public ProductTransactionAssert(InventoryAmountUpdateLine inventoryLine,
         BigDecimal originalPrice, BigDecimal finalPrice) {
-      this(null, inventoryLine, null, null, null, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, false);
+      this(null, inventoryLine, null, null, null, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, false);
     }
 
     public ProductTransactionAssert(InventoryAmountUpdateLine inventoryLine,
         BigDecimal originalPrice, BigDecimal totalPrice, BigDecimal unitPrice) {
-      this(null, inventoryLine, null, null, null, CURRENCY1_ID, originalPrice, totalPrice,
-          unitPrice, false, false);
+      this(null, inventoryLine, null, null, null, EURO_ID, originalPrice, totalPrice, unitPrice,
+          false, false);
     }
 
     public ProductTransactionAssert(InventoryAmountUpdateLine inventoryLine,
         BigDecimal originalPrice, BigDecimal finalPrice, boolean permanent) {
-      this(null, inventoryLine, null, null, null, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, permanent);
+      this(null, inventoryLine, null, null, null, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, permanent);
     }
 
     public ProductTransactionAssert(InternalMovementLine movementLine, BigDecimal originalPrice,
         BigDecimal finalPrice) {
-      this(null, null, movementLine, null, null, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, false);
+      this(null, null, movementLine, null, null, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, false);
     }
 
     public ProductTransactionAssert(InternalMovementLine movementLine, BigDecimal originalPrice,
         BigDecimal totalPrice, BigDecimal unitPrice) {
-      this(null, null, movementLine, null, null, CURRENCY1_ID, originalPrice, totalPrice,
-          unitPrice, false, false);
+      this(null, null, movementLine, null, null, EURO_ID, originalPrice, totalPrice, unitPrice,
+          false, false);
     }
 
     public ProductTransactionAssert(InternalMovementLine movementLine, BigDecimal originalPrice,
         BigDecimal finalPrice, boolean permanent) {
-      this(null, null, movementLine, null, null, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, permanent);
+      this(null, null, movementLine, null, null, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, permanent);
     }
 
     public ProductTransactionAssert(InternalConsumptionLine consumptionLine,
         BigDecimal originalPrice, BigDecimal finalPrice) {
-      this(null, null, null, consumptionLine, null, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, false);
+      this(null, null, null, consumptionLine, null, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, false);
     }
 
     public ProductTransactionAssert(InternalConsumptionLine consumptionLine,
         BigDecimal originalPrice, BigDecimal finalPrice, boolean permanent) {
-      this(null, null, null, consumptionLine, null, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, permanent);
+      this(null, null, null, consumptionLine, null, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, permanent);
     }
 
     public ProductTransactionAssert(ProductionLine productionLine, BigDecimal originalPrice,
         BigDecimal finalPrice) {
-      this(null, null, null, null, productionLine, CURRENCY1_ID, originalPrice, finalPrice,
-          finalPrice, false, false);
+      this(null, null, null, null, productionLine, EURO_ID, originalPrice, finalPrice, finalPrice,
+          false, false);
     }
 
     public ProductTransactionAssert(ShipmentInOutLine shipmentReceiptLine,
@@ -13850,7 +13843,7 @@
 
     public CostAdjustmentAssert(MaterialTransaction materialTransaction, String type,
         BigDecimal amount, int day, boolean source, boolean unit) {
-      this(materialTransaction, CURRENCY1_ID, type, amount, day, source, unit);
+      this(materialTransaction, EURO_ID, type, amount, day, source, unit);
     }
 
     public CostAdjustmentAssert(MaterialTransaction materialTransaction, String currencyId,
@@ -13865,7 +13858,7 @@
 
     public CostAdjustmentAssert(MaterialTransaction materialTransaction, String type,
         BigDecimal amount, int day, boolean source, boolean unit, String status) {
-      this(materialTransaction, CURRENCY1_ID, type, amount, day, source, unit, status);
+      this(materialTransaction, EURO_ID, type, amount, day, source, unit, status);
     }
 
     public CostAdjustmentAssert(MaterialTransaction materialTransaction, String currencyId,
--- a/src-test/src/org/openbravo/test/dal/DalPerformanceCriteriaTest.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/dal/DalPerformanceCriteriaTest.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2012-2014 Openbravo SLU 
+ * All portions are Copyright (C) 2012-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -148,7 +148,7 @@
 
     public int doCriteriaQry() {
       final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-      obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+      obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
       if (doScroll) {
         final ScrollableResults r = obc.scroll(ScrollMode.FORWARD_ONLY);
         int cnt = 0;
--- a/src-test/src/org/openbravo/test/dal/DalQueryTest.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/dal/DalQueryTest.java	Mon Jan 23 12:55:58 2017 +0100
@@ -203,7 +203,7 @@
   public void testIUpdateCurrencyByUser() {
     setUserContext("E12DC7B3FF8C4F64924A98195223B1F8");
     final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
     final List<Currency> cs = obc.list();
     assertEquals(1, cs.size());
     final Currency c = cs.get(0);
--- a/src-test/src/org/openbravo/test/dal/DalTest.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/dal/DalTest.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2016 Openbravo SLU 
+ * All portions are Copyright (C) 2008-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):
  *   Martin Taal <martin.taal@openbravo.com>,
@@ -22,14 +22,18 @@
 
 package org.openbravo.test.dal;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeThat;
 
 import java.util.List;
 
@@ -45,12 +49,14 @@
 import org.openbravo.base.exception.OBSecurityException;
 import org.openbravo.base.model.Property;
 import org.openbravo.base.provider.OBProvider;
+import org.openbravo.base.session.OBPropertiesProvider;
 import org.openbravo.base.structure.BaseOBObject;
 import org.openbravo.dal.core.DalUtil;
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.core.SessionHandler;
 import org.openbravo.dal.service.OBCriteria;
 import org.openbravo.dal.service.OBDal;
+import org.openbravo.database.ExternalConnectionPool;
 import org.openbravo.model.ad.system.SystemInformation;
 import org.openbravo.model.common.businesspartner.BusinessPartner;
 import org.openbravo.model.common.businesspartner.Category;
@@ -169,7 +175,7 @@
   public void testFUpdateCurrencyByUser() {
     setUserContext("E12DC7B3FF8C4F64924A98195223B1F8");
     final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
     final List<Currency> cs = obc.list();
     assertEquals(1, cs.size());
     final Currency c = cs.get(0);
@@ -197,7 +203,7 @@
     String newDescription = null;
     {
       final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-      obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+      obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
       final List<Currency> cs = obc.list();
       assertEquals(1, cs.size());
       c = cs.get(0);
@@ -211,7 +217,7 @@
     // roll back the change, while doing some checks
     {
       final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-      obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+      obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
       final List<Currency> cs = obc.list();
       assertEquals(1, cs.size());
       final Currency newC = cs.get(0);
@@ -367,7 +373,7 @@
       String cashBookId = "";
       {
         final OBCriteria<Currency> cc = OBDal.getInstance().createCriteria(Currency.class);
-        cc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+        cc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
         final List<Currency> cs = cc.list();
         final Currency currency = cs.get(0);
         final CashBook c = OBProvider.getInstance().get(CashBook.class);
@@ -438,7 +444,7 @@
     setTestLogAppenderLevel(Level.WARN);
 
     final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "EUR"));
+    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, EURO));
     obc.count();
 
     assertThat(getTestLogAppender().getMessages(Level.WARN), hasSize(0));
@@ -450,7 +456,7 @@
     setTestLogAppenderLevel(Level.WARN);
 
     final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "EUR"));
+    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, EURO));
     if (obc.count() > 0) {
       obc.addOrderBy(Currency.PROPERTY_ISOCODE, false);
     }
@@ -466,12 +472,148 @@
     final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
     obc.add(Restrictions.or(
         //
-        Restrictions.eq(Currency.PROPERTY_ISOCODE, "EUR"),
-        Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD")));
+        Restrictions.eq(Currency.PROPERTY_ISOCODE, EURO),
+        Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR)));
     if (obc.count() > 0) {
       obc.addOrderBy(Currency.PROPERTY_ISOCODE, false);
     }
 
-    assertEquals("USD", obc.list().get(0).getISOCode());
+    assertEquals(DOLLAR, obc.list().get(0).getISOCode());
+  }
+
+  @Test
+  public void defaultPoolIsClosedAfterCommit() {
+    setTestUserContext();
+    OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getInstance().commitAndClose();
+    assertFalse(SessionHandler.isSessionHandlerPresent());
+  }
+
+  @Test
+  public void defaultPoolIsClosedAfterRollback() {
+    setTestUserContext();
+    OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getInstance().rollbackAndClose();
+    assertFalse(SessionHandler.isSessionHandlerPresent());
+  }
+
+  @Test
+  public void defaultPoolCanBeUsedAfterCommit() {
+    setTestUserContext();
+    Currency currency = OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getInstance().commitAndClose();
+    currency = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
+    assertEquals(DOLLAR, currency.getISOCode());
+  }
+
+  @Test
+  public void defaultPoolCanBeUsedAfterRollback() {
+    setTestUserContext();
+    Currency currency = OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getInstance().rollbackAndClose();
+    currency = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
+    assertEquals(DOLLAR, currency.getISOCode());
+  }
+
+  @Test
+  public void readOnlyPoolNotClosedAfterCommitDefaultPool() {
+    setTestUserContext();
+    OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getReadOnlyInstance().get(Currency.class, EURO_ID);
+    OBDal.getInstance().commitAndClose();
+    boolean[] expectedAvailability = { false, true };
+    boolean[] currentAvailability = {
+        SessionHandler.isSessionHandlerPresent(ExternalConnectionPool.DEFAULT_POOL),
+        SessionHandler.isSessionHandlerPresent(ExternalConnectionPool.READONLY_POOL) };
+    assertThat("Session Handler is still present for the read-only pool", expectedAvailability,
+        equalTo(currentAvailability));
+  }
+
+  @Test
+  public void defaultPoolNotClosedAfterCommitReadOnlyPool() {
+    setTestUserContext();
+    OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getReadOnlyInstance().get(Currency.class, EURO_ID);
+    OBDal.getReadOnlyInstance().commitAndClose();
+    boolean[] expectedAvailability = { true, false };
+    boolean[] currentAvailability = {
+        SessionHandler.isSessionHandlerPresent(ExternalConnectionPool.DEFAULT_POOL),
+        SessionHandler.isSessionHandlerPresent(ExternalConnectionPool.READONLY_POOL) };
+    assertThat("Session Handler is still present for the default pool", expectedAvailability,
+        equalTo(currentAvailability));
+  }
+
+  @Test
+  public void readOnlyPoolCanBeUsedAfterClosingDefaultPool() {
+    setTestUserContext();
+    Currency currency = OBDal.getInstance().get(Currency.class, EURO_ID);
+    OBDal.getInstance().commitAndClose();
+    currency = OBDal.getReadOnlyInstance().get(Currency.class, DOLLAR_ID);
+    assertEquals(DOLLAR, currency.getISOCode());
+  }
+
+  @Test
+  public void defaultPoolCanBeUsedAfterClosingReadOnlyPool() {
+    setTestUserContext();
+    Currency currency = OBDal.getReadOnlyInstance().get(Currency.class, EURO_ID);
+    OBDal.getReadOnlyInstance().commitAndClose();
+    currency = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
+    assertEquals(DOLLAR, currency.getISOCode());
+  }
+
+  @Test
+  public void readOnlyPoolCanNotInsert() {
+    assumeThat("read-only pool is configured", isReadOnlyPoolDefined(), is(true));
+    setTestUserContext();
+    try {
+      final Category category = OBProvider.getInstance().get(Category.class);
+      category.setDefault(true);
+      category.setDescription("ro_testdescription");
+      category.setName("ro_testname");
+      category.setSearchKey("ro_testvalue");
+      category.setActive(true);
+      OBDal.getReadOnlyInstance().save(category);
+      OBDal.getReadOnlyInstance().commitAndClose();
+    } catch (Exception ignored) {
+    }
+    final OBCriteria<Category> obCriteria = OBDal.getReadOnlyInstance().createCriteria(
+        Category.class);
+    obCriteria.add(Restrictions.eq(Category.PROPERTY_NAME, "ro_testname"));
+    final List<Category> categories = obCriteria.list();
+    assertEquals(0, categories.size());
+  }
+
+  @Test
+  public void readOnlyPoolCanNotUpdate() {
+    assumeThat("read-only pool is configured", isReadOnlyPoolDefined(), is(true));
+    setTestUserContext();
+    final String newDescription = "ro_testdescription";
+    try {
+      Category category = OBDal.getReadOnlyInstance().get(Category.class, TEST_BP_CATEGORY_ID);
+      category.setDescription(newDescription);
+      OBDal.getReadOnlyInstance().commitAndClose();
+    } catch (Exception ignored) {
+    }
+    Category category = OBDal.getReadOnlyInstance().get(Category.class, TEST_BP_CATEGORY_ID);
+    assertThat(newDescription, not(equalTo(category.getDescription())));
+  }
+
+  @Test
+  public void readOnlyPoolCanNotDelete() {
+    assumeThat("read-only pool is configured", isReadOnlyPoolDefined(), is(true));
+    setTestUserContext();
+    try {
+      Category category = OBDal.getReadOnlyInstance().get(Category.class, TEST_BP_CATEGORY_ID);
+      OBDal.getReadOnlyInstance().remove(category);
+      OBDal.getReadOnlyInstance().commitAndClose();
+    } catch (Exception ignored) {
+    }
+    Category category = OBDal.getInstance().get(Category.class, TEST_BP_CATEGORY_ID);
+    assertNotNull(category);
+  }
+
+  private boolean isReadOnlyPoolDefined() {
+    return OBPropertiesProvider.getInstance().getOpenbravoProperties()
+        .containsKey("bbdd.readonly.url");
   }
 }
--- a/src-test/src/org/openbravo/test/dal/ValidationTest.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/dal/ValidationTest.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2014 Openbravo SLU 
+ * All portions are Copyright (C) 2008-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -65,7 +65,7 @@
   public void testTypeChecking() {
     setTestAdminContext();
     final OBCriteria<Currency> obc = OBDal.getInstance().createCriteria(Currency.class);
-    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, "USD"));
+    obc.add(Restrictions.eq(Currency.PROPERTY_ISOCODE, DOLLAR));
     final List<Currency> cs = obc.list();
     final Currency c = cs.get(0);
 
--- a/src-test/src/org/openbravo/test/security/CrossOrganizationReference.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/security/CrossOrganizationReference.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2016 Openbravo SLU 
+ * All portions are Copyright (C) 2016-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -67,7 +67,6 @@
   protected static final String USA_ORG = "5EFF95EB540740A3B10510D9814EFAD5";
   protected static final String USA_WAREHOUSE = "4028E6C72959682B01295ECFE2E20270";
   protected static final String USA_BP = "4028E6C72959682B01295F40D4D20333";
-  protected static final String EUR = "102";
 
   private static final String CREDIT_ORDER_DOC_TYPE = "FF8080812C2ABFC6012C2B3BDF4C0056";
   private static final String CUST_A = "4028E6C72959682B01295F40C3CB02EC";
@@ -109,7 +108,7 @@
 
     order.setBusinessPartner(OBDal.getInstance().getProxy(BusinessPartner.class, CUST_A));
     order.setPartnerAddress(OBDal.getInstance().getProxy(Location.class, CUST_A_LOCATION));
-    order.setCurrency(OBDal.getInstance().getProxy(Currency.class, EUR));
+    order.setCurrency(OBDal.getInstance().getProxy(Currency.class, EURO_ID));
     order.setPaymentTerms(OBDal.getInstance().getProxy(PaymentTerm.class, PAYMENT_TERM));
     order.setWarehouse(OBDal.getInstance().getProxy(Warehouse.class, SPAIN_WAREHOUSE));
     order.setPriceList(OBDal.getInstance().getProxy(PriceList.class, PRICE_LIST));
@@ -147,7 +146,7 @@
     ol.setProduct(OBDal.getInstance().getProxy(Product.class, PRODUCT));
     ol.setUOM(OBDal.getInstance().getProxy(UOM.class, OUM));
     ol.setOrderedQuantity(BigDecimal.TEN);
-    ol.setCurrency(OBDal.getInstance().getProxy(Currency.class, EUR));
+    ol.setCurrency(OBDal.getInstance().getProxy(Currency.class, EURO_ID));
     ol.setTax(OBDal.getInstance().getProxy(TaxRate.class, TAX));
 
     setProperties(propertyValues, ol);
--- a/src-test/src/org/openbravo/test/security/EntityAccessTest.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src-test/src/org/openbravo/test/security/EntityAccessTest.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2014 Openbravo SLU 
+ * All portions are Copyright (C) 2008-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -114,7 +114,7 @@
   @Test
   public void testCCheckDerivedReadableCurrency() {
     setUserContext(TEST2_USER_ID);
-    final Currency c = OBDal.getInstance().get(Currency.class, "100");
+    final Currency c = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
     log.debug(c.getIdentifier());
     log.debug(c.getId());
     try {
@@ -159,7 +159,7 @@
   @Test
   public void testDUpdateCurrencyDerivedRead() {
     setUserContext(TEST2_USER_ID);
-    final Currency c = OBDal.getInstance().get(Currency.class, "100");
+    final Currency c = OBDal.getInstance().get(Currency.class, DOLLAR_ID);
     try {
       c.setCostingPrecision((long) 5);
       fail("Derived readable not checked on set");
--- a/src/org/openbravo/base/secureApp/HttpSecureAppServlet.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/base/secureApp/HttpSecureAppServlet.java	Mon Jan 23 12:55:58 2017 +0100
@@ -49,6 +49,7 @@
 import org.openbravo.dal.service.OBDal;
 import org.openbravo.data.FieldProvider;
 import org.openbravo.data.ScrollableFieldProvider;
+import org.openbravo.database.ConnectionProvider;
 import org.openbravo.database.SessionInfo;
 import org.openbravo.erpCommon.obps.ActivationKey;
 import org.openbravo.erpCommon.obps.ActivationKey.FeatureRestriction;
@@ -67,6 +68,7 @@
 import org.openbravo.model.ad.ui.ProcessTrl;
 import org.openbravo.model.ad.ui.Tab;
 import org.openbravo.model.ad.ui.WindowTrl;
+import org.openbravo.service.db.DalConnectionProvider;
 import org.openbravo.utils.FileUtility;
 import org.openbravo.utils.Replace;
 import org.openbravo.xmlEngine.XmlDocument;
@@ -1253,16 +1255,18 @@
         String localAddress = HttpBaseUtils.getLocalAddress(request);
         localExportParameters.put(ReportingUtils.IMAGES_URI, localAddress
             + "/servlets/image?image={0}");
+        ConnectionProvider readOnlyCP = DalConnectionProvider.getReadOnlyConnectionProvider();
         ReportingUtils.exportJR(localStrReportName, expType, localDesignParameters, os, false,
-            this, data, localExportParameters);
+            readOnlyCP, data, localExportParameters);
       } else if (localStrOutputType.equals("pdf") || localStrOutputType.equalsIgnoreCase("xls")
           || localStrOutputType.equalsIgnoreCase("txt")
           || localStrOutputType.equalsIgnoreCase("csv")) {
         reportId = UUID.randomUUID();
         File outputFile = new File(globalParameters.strFTPDirectory + "/" + localStrFileName + "-"
             + (reportId) + "." + localStrOutputType);
+        ConnectionProvider readOnlyCP = DalConnectionProvider.getReadOnlyConnectionProvider();
         ReportingUtils.exportJR(localStrReportName, expType, localDesignParameters, outputFile,
-            false, this, data, localExportParameters);
+            false, readOnlyCP, data, localExportParameters);
         response.setContentType("text/html;charset=UTF-8");
         response.setHeader("Content-disposition", "inline" + "; filename=" + localStrFileName + "-"
             + (reportId) + ".html");
--- a/src/org/openbravo/dal/core/DalThreadHandler.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/dal/core/DalThreadHandler.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2010 Openbravo SLU 
+ * All portions are Copyright (C) 2008-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -40,28 +40,39 @@
   @Override
   public void doFinal(boolean errorOccured) {
     try {
-      if (SessionHandler.isSessionHandlerPresent()
-          && SessionHandler.getInstance().doSessionInViewPatter()) {
-        // application software can force a rollback
-        if (SessionHandler.getInstance().getDoRollback()) {
-          SessionHandler.getInstance().rollback();
-        } else if (errorOccured) {
-          SessionHandler.getInstance().rollback();
-        } else if (SessionHandler.getInstance().getSession().getTransaction().isActive()) {
-          SessionHandler.getInstance().commitAndClose();
-        } else {
-          SessionHandler.getInstance().closeSession();
-        }
+      closeDefaultPoolSession(errorOccured);
+    } finally {
+      try {
+        closeOtherSessions();
+      } finally {
+        SessionHandler.deleteSessionHandler();
+        // note before the code below was enabled, however for longer running transactions
+        // openbravo does multiple http requests, so while the long running transaction
+        // had set inadministratormode, the subsequence http requests put it to false again
+        // if (OBContext.getOBContext() != null) {
+        // OBContext.getOBContext().setInAdministratorMode(false);
+        // }
+        OBContext.setOBContext((OBContext) null);
       }
-    } finally {
-      SessionHandler.deleteSessionHandler();
-      // note before the code below was enabled, however for longer running transactions
-      // openbravo does multiple http requests, so while the long running transaction
-      // had set inadministratormode, the subsequence http requests put it to false again
-      // if (OBContext.getOBContext() != null) {
-      // OBContext.getOBContext().setInAdministratorMode(false);
-      // }
-      OBContext.setOBContext((OBContext) null);
+    }
+  }
+
+  private void closeDefaultPoolSession(boolean errorOccured) {
+    SessionHandler sessionHandler = SessionHandler.isSessionHandlerPresent() ? SessionHandler
+        .getInstance() : null;
+    if (sessionHandler != null && sessionHandler.doSessionInViewPatter()) {
+      // application software can force a rollback
+      if (sessionHandler.getDoRollback() || errorOccured) {
+        sessionHandler.rollback();
+      } else if (sessionHandler.getSession().getTransaction().isActive()) {
+        sessionHandler.commitAndClose();
+      }
+    }
+  }
+
+  private void closeOtherSessions() {
+    if (SessionHandler.existsOpenedSessions()) {
+      SessionHandler.getInstance().cleanUpSessions();
     }
   }
 }
\ No newline at end of file
--- a/src/org/openbravo/dal/core/SessionHandler.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/dal/core/SessionHandler.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2016 Openbravo SLU
+ * All portions are Copyright (C) 2008-2017 Openbravo SLU
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -19,9 +19,15 @@
 
 package org.openbravo.dal.core;
 
+import static org.openbravo.database.ExternalConnectionPool.DEFAULT_POOL;
+
 import java.io.Serializable;
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.log4j.Logger;
 import org.hibernate.FlushMode;
@@ -76,22 +82,50 @@
   private static ThreadLocal<SessionHandler> sessionHandler = new ThreadLocal<SessionHandler>();
 
   /**
-   * Removes the current SessionHandler from the ThreadLocal. A call to getSessionHandler will
-   * create a new SessionHandler, session and transaction.
+   * Removes the current SessionHandler from the ThreadLocal. A call to getInstance will create a
+   * new SessionHandler. A call to getSession will create a session and a transaction.
    */
   public static void deleteSessionHandler() {
     log.debug("Removing sessionhandler");
     sessionHandler.set(null);
   }
 
-  /** @return true if a session handler is present for this thread, false */
+  /**
+   * Checks whether a session handler is present for this thread and also available for the default
+   * pool.
+   * 
+   * @return true if a session handler is present for this thread and available for the default
+   *         pool, false otherwise
+   */
   public static boolean isSessionHandlerPresent() {
-    return sessionHandler.get() != null;
+    return isSessionHandlerPresent(DEFAULT_POOL);
   }
 
   /**
-   * Returns the SessionHandler of this thread. If there is none then a new one is created and a
-   * Hibernate Session is created and a transaction is started.
+   * Checks whether a session handler is present for this thread and also available for the pool
+   * whose name is passed as parameter.
+   * 
+   * @param pool
+   *          the name of the pool
+   * 
+   * @return true if a session handler is present for this thread and available for the specified
+   *         pool, false otherwise
+   */
+  public static boolean isSessionHandlerPresent(String pool) {
+    return sessionHandler.get() != null && sessionHandler.get().isAvailablePool(pool);
+  }
+
+  /**
+   * Checks if the session handler has available sessions which are not closed yet.
+   * 
+   * @return true if there are sessions not closed, false otherwise
+   */
+  public static boolean existsOpenedSessions() {
+    return sessionHandler.get() != null && sessionHandler.get().hasAvailablePools();
+  }
+
+  /**
+   * Returns the SessionHandler of this thread. If there is none then a new one is created.
    * 
    * @return the sessionhandler for this thread
    */
@@ -100,25 +134,22 @@
     if (sh == null) {
       log.debug("Creating sessionHandler");
       sh = getCreateSessionHandler();
-      sh.begin();
       sessionHandler.set(sh);
     }
     return sh;
   }
 
-  private static boolean checkedSessionHandlerRegistration = false;
-
   private static SessionHandler getCreateSessionHandler() {
-    if (!checkedSessionHandlerRegistration
-        && !OBProvider.getInstance().isRegistered(SessionHandler.class)) {
+    if (!OBProvider.getInstance().isRegistered(SessionHandler.class)) {
       OBProvider.getInstance().register(SessionHandler.class, SessionHandler.class, false);
     }
     return OBProvider.getInstance().get(SessionHandler.class);
   }
 
-  private Session session;
-  private Transaction tx;
-  private Connection connection;
+  private Map<String, Session> sessions = new HashMap<>();
+  private Map<String, Transaction> trxs = new HashMap<>();
+  private Map<String, Connection> connections = new HashMap<>();
+  private Set<String> availablePools = new HashSet<String>();
 
   // Sets the session handler at rollback so that the controller can rollback
   // at the end
@@ -126,35 +157,55 @@
 
   /** @return the session */
   public Session getSession() {
-    return session;
+    return getSession(DEFAULT_POOL);
+  }
+
+  /**
+   * Gets a {@code Session} from the connection pool whose name is passed as parameter. If it was
+   * not created previously, this methods returns a newly created session from that pool.
+   * 
+   * @param pool
+   *          the name of the pool used to retrieve the session
+   * @return the session
+   */
+  public Session getSession(String pool) {
+    String thePool = pool;
+    if (thePool == null) {
+      thePool = DEFAULT_POOL;
+    }
+    Session theSession = sessions.get(thePool);
+    if (theSession == null) {
+      begin(thePool);
+    }
+    return sessions.get(thePool);
   }
 
   protected void setSession(Session thisSession) {
-    session = thisSession;
+    setSession(DEFAULT_POOL, thisSession);
   }
 
-  public void setConnection(Connection connection) {
-    this.connection = connection;
-  }
-
-  /** Gets current session's {@code Connection} if it's set, {@code null} if not. */
-  public Connection getConnection() {
-    return this.connection;
+  private void setSession(String pool, Session thisSession) {
+    sessions.put(pool, thisSession);
   }
 
   protected Session createSession() {
+    return createSession(DEFAULT_POOL);
+  }
+
+  private Session createSession(String pool) {
     SessionFactory sf = SessionFactoryController.getInstance().getSessionFactory();
     // Checks if the session connection has to be obtained using an external connection pool
-    if (externalConnectionPool != null && connection == null) {
+    if (externalConnectionPool != null && getConnection(pool) == null) {
       Connection externalConnection;
       try {
-        externalConnection = getNewConnection();
-        setConnection(externalConnection);
+        externalConnection = getNewConnection(pool);
+        setConnection(pool, externalConnection);
       } catch (SQLException e) {
         throw new OBException("Could not get connection to create DAL session", e);
       }
     }
 
+    Connection connection = getConnection(pool);
     if (connection != null) {
       // If the connection has been obtained using an external connection pool it is passed to
       // openSession, to prevent a new connection to be created using the Hibernate default
@@ -165,35 +216,57 @@
     }
   }
 
-  /**
-   * Returns true when the current SessionHandler has a transaction and it is active.
-   */
-  public boolean isCurrentTransactionActive() {
-    return tx != null && tx.isActive();
+  protected void closeSession() {
+    closeSession(DEFAULT_POOL);
   }
 
-  /**
-   * Begins a new Transaction on the current HibernateSession and assigns it to the SessionHandler.
-   * 
-   * @throws OBException
-   *           if there is already an available active transaction.
-   */
-  public void beginNewTransaction() throws OBException {
-    if (isCurrentTransactionActive()) {
-      throw new OBException(
-          "Not possible to start a new transaction while there is still one active.");
+  void closeSession(String pool) {
+    Session session = sessions.get(pool);
+    if (session != null) {
+      if (session.isOpen()) {
+        session.close();
+      }
+      removeSession(pool);
     }
-    tx = getSession().beginTransaction();
+  }
+
+  /** Commits all remaining sessions and closes them */
+  void cleanUpSessions() {
+    for (String pool : sessions.keySet()) {
+      commitAndCloseNoCheck(pool);
+    }
+    clearSessions();
+    clearTransactions();
+    clearConnections();
+  }
+
+  private void removeSession(String pool) {
+    sessions.remove(pool);
+  }
+
+  private void clearSessions() {
+    sessions.clear();
   }
 
   /** Gets a new {@code Connection} from the connection pool. */
   public Connection getNewConnection() throws SQLException {
+    return getNewConnection(DEFAULT_POOL);
+  }
+
+  /**
+   * Gets a new {@code Connection} from the connection pool.
+   * 
+   * @param pool
+   *          the name of the pool used to retrieve the connection
+   * @return a {@code Connection} from the specified pool
+   */
+  public Connection getNewConnection(String pool) throws SQLException {
     Connection newConnection;
     if (externalConnectionPool != null) {
-      newConnection = externalConnectionPool.getConnection();
+      newConnection = externalConnectionPool.getConnection(pool);
       try {
         // Autocommit is disabled because DAL is taking into account his logical and DAL is setting
-        // autoCommint to false to maintain transactional way of working.
+        // autoCommit to false to maintain transactional way of working.
         newConnection.setAutoCommit(false);
       } catch (SQLException e) {
         log.error("Error setting connection to auto-commit mode", e);
@@ -207,9 +280,104 @@
     return newConnection;
   }
 
-  protected void closeSession() {
-    if (session != null && session.isOpen()) {
-      session.close();
+  /** Gets current session's {@code Connection} if it's set, {@code null} if not. */
+  public Connection getConnection() {
+    // use getSession to create the session if it does not exist yet
+    // in that case, the session will be created together with a new connection
+    getSession(DEFAULT_POOL);
+    return getConnection(DEFAULT_POOL);
+  }
+
+  private Connection getConnection(String pool) {
+    return connections.get(pool);
+  }
+
+  /**
+   * Sets the connection of the default pool to be used by the handler.
+   * 
+   * @param connection
+   *          the connection of the default pool.
+   */
+  public void setConnection(Connection newConnection) {
+    setConnection(DEFAULT_POOL, newConnection);
+  }
+
+  private void setConnection(String pool, Connection newConnection) {
+    connections.put(pool, newConnection);
+  }
+
+  private void removeConnection(String pool) {
+    connections.remove(pool);
+  }
+
+  private void clearConnections() {
+    connections.clear();
+  }
+
+  private Transaction getTransaction(String pool) {
+    return trxs.get(pool);
+  }
+
+  private void setTransaction(String pool, Transaction newTransaction) {
+    trxs.put(pool, newTransaction);
+  }
+
+  private void removeTransaction(String pool) {
+    trxs.remove(pool);
+  }
+
+  private void clearTransactions() {
+    trxs.clear();
+  }
+
+  private void setAvailablePool(String pool) {
+    availablePools.add(pool);
+  }
+
+  private void setUnavailablePool(String pool) {
+    if (availablePools.contains(pool)) {
+      availablePools.remove(pool);
+    }
+  }
+
+  private boolean isAvailablePool(String pool) {
+    return availablePools.contains(pool);
+  }
+
+  private boolean hasAvailablePools() {
+    return !availablePools.isEmpty();
+  }
+
+  /**
+   * Returns true when the current SessionHandler has a transaction and it is active.
+   */
+  public boolean isCurrentTransactionActive() {
+    return isCurrentTransactionActive(DEFAULT_POOL);
+  }
+
+  private boolean isCurrentTransactionActive(String pool) {
+    return trxs.containsKey(pool) && trxs.get(pool).isActive();
+  }
+
+  /**
+   * Begins a new Transaction on the current HibernateSession and assigns it to the SessionHandler.
+   * 
+   * @throws OBException
+   *           if there is already an available active transaction.
+   */
+  public void beginNewTransaction() throws OBException {
+    beginNewTransaction(DEFAULT_POOL);
+  }
+
+  private void beginNewTransaction(String pool) throws OBException {
+    if (isCurrentTransactionActive(pool)) {
+      throw new OBException(
+          "Not possible to start a new transaction while there is still one active.");
+    }
+    Session session = getSession(pool);
+    if (!isCurrentTransactionActive(pool)) {
+      // getSession has returned an existing session, so just begin a new transaction
+      setTransaction(pool, session.beginTransaction());
     }
   }
 
@@ -220,10 +388,22 @@
    *          the object to persist
    */
   public void save(Object obj) {
+    save(DEFAULT_POOL, obj);
+  }
+
+  /**
+   * Saves the object in the session of the pool whose name is passed as parameter.
+   * 
+   * @param pool
+   *          the name of the pool used to retrieve the session where the object will be saved
+   * @param obj
+   *          the object to persist
+   */
+  public void save(String pool, Object obj) {
     if (Identifiable.class.isAssignableFrom(obj.getClass())) {
-      getSession().saveOrUpdate(((Identifiable) obj).getEntityName(), obj);
+      getSession(pool).saveOrUpdate(((Identifiable) obj).getEntityName(), obj);
     } else {
-      getSession().saveOrUpdate(obj);
+      getSession(pool).saveOrUpdate(obj);
     }
   }
 
@@ -234,10 +414,22 @@
    *          the object to remove
    */
   public void delete(Object obj) {
+    delete(DEFAULT_POOL, obj);
+  }
+
+  /**
+   * Delete the object from the db.
+   * 
+   * @param pool
+   *          the name of the pool used to retrieve the session where the object will be deleted
+   * @param obj
+   *          the object to remove
+   */
+  public void delete(String pool, Object obj) {
     if (Identifiable.class.isAssignableFrom(obj.getClass())) {
-      getSession().delete(((Identifiable) obj).getEntityName(), obj);
+      getSession(pool).delete(((Identifiable) obj).getEntityName(), obj);
     } else {
-      getSession().delete(obj);
+      getSession(pool).delete(obj);
     }
   }
 
@@ -250,15 +442,30 @@
    *          the id to use for querying
    * @return the retrieved object, can be null
    */
+  public <T extends Object> T find(Class<T> clazz, Object id) {
+    return find(DEFAULT_POOL, clazz, id);
+  }
+
+  /**
+   * Queries for a certain object using the class and id. If not found then null is returned.
+   * 
+   * @param pool
+   *          the name of the pool used to obtain the connection to execute the query
+   * @param clazz
+   *          the class to query
+   * @param id
+   *          the id to use for querying
+   * @return the retrieved object, can be null
+   */
   @SuppressWarnings("unchecked")
-  public <T extends Object> T find(Class<T> clazz, Object id) {
+  public <T extends Object> T find(String pool, Class<T> clazz, Object id) {
     // translates a class to an entityname because the hibernate
     // getSession().get method can not handle class names if the entity was
     // mapped with entitynames.
     if (Identifiable.class.isAssignableFrom(clazz)) {
-      return (T) find(DalUtil.getEntityName(clazz), id);
+      return (T) find(pool, DalUtil.getEntityName(clazz), id);
     }
-    return (T) getSession().get(clazz, (Serializable) id);
+    return (T) getSession(pool).get(clazz, (Serializable) id);
   }
 
   /**
@@ -273,7 +480,24 @@
    * @see Entity
    */
   public BaseOBObject find(String entityName, Object id) {
-    return (BaseOBObject) getSession().get(entityName, (Serializable) id);
+    return find(DEFAULT_POOL, entityName, id);
+  }
+
+  /**
+   * Queries for a certain object using the entity name and id. If not found then null is returned.
+   * 
+   * @param pool
+   *          the name of the pool used to obtain the connection to execute the query
+   * @param entityName
+   *          the name of the entity to query
+   * @param id
+   *          the id to use for querying
+   * @return the retrieved object, can be null
+   * 
+   * @see Entity
+   */
+  public BaseOBObject find(String pool, String entityName, Object id) {
+    return (BaseOBObject) getSession(pool).get(entityName, (Serializable) id);
   }
 
   /**
@@ -284,18 +508,27 @@
    * @return a new Query object
    */
   public Query createQuery(String qryStr) {
-    return getSession().createQuery(qryStr);
+    return createQuery(DEFAULT_POOL, qryStr);
+  }
+
+  private Query createQuery(String pool, String qryStr) {
+    return getSession(pool).createQuery(qryStr);
   }
 
   /**
    * Starts a transaction.
    */
   protected void begin() {
-    Check.isTrue(getSession() == null, "Session must be null before begin");
-    setSession(createSession());
-    getSession().setFlushMode(FlushMode.COMMIT);
-    Check.isTrue(tx == null, "tx must be null before begin");
-    tx = getSession().beginTransaction();
+    begin(DEFAULT_POOL);
+  }
+
+  private void begin(String pool) {
+    Check.isTrue(sessions.get(pool) == null, "Session must be null before begin");
+    setSession(pool, createSession(pool));
+    getSession(pool).setFlushMode(FlushMode.COMMIT);
+    Check.isTrue(getTransaction(pool) == null, "tx must be null before begin");
+    setTransaction(pool, getSession(pool).beginTransaction());
+    setAvailablePool(pool);
     log.debug("Transaction started");
   }
 
@@ -304,71 +537,113 @@
    * work.
    */
   public void commitAndClose() {
+    commitAndClose(DEFAULT_POOL);
+  }
+
+  /**
+   * Commits the transaction and closes the session, should normally be called at the end of all the
+   * work.
+   * 
+   * @param pool
+   *          the name of the pool which the transaction belongs.
+   */
+  public void commitAndClose(String pool) {
     boolean err = true;
     try {
       Check.isFalse(TriggerHandler.getInstance().isDisabled(),
           "Triggers disabled, commit is not allowed when in triggers-disabled mode, "
               + "call TriggerHandler.enable() before committing");
 
-      checkInvariant();
-      flushRemainingChanges();
-      if (connection == null || (connection != null && !connection.isClosed())) {
-        if (connection != null) {
-          connection.setAutoCommit(false);
+      checkInvariant(pool);
+      flushRemainingChanges(pool);
+      err = false;
+    } finally {
+      if (err) {
+        // close transaction in case checks or flush failed, other case transaction is closed in
+        // commit
+        closeTransaction(pool, err);
+      }
+    }
+
+    commitAndCloseNoCheck(pool);
+  }
+
+  private void commitAndCloseNoCheck(String pool) {
+    boolean err = true;
+    Connection con = getConnection(pool);
+    Transaction trx = getTransaction(pool);
+    try {
+      if (con == null || !con.isClosed()) {
+        if (con != null) {
+          con.setAutoCommit(false);
         }
-        tx.commit();
+        if (trx != null && trx.isActive()) {
+          trx.commit();
+        }
       }
-      tx = null;
       err = false;
     } catch (SQLException e) {
-      log.error("Error while closing the connection", DbUtility.getUnderlyingSQLException(e));
+      log.error("Error while closing the connection in pool " + pool,
+          DbUtility.getUnderlyingSQLException(e));
     } finally {
-      if (err) {
-        try {
-          tx.rollback();
-          tx = null;
-        } catch (Throwable t) {
-          // ignore these exception not to hide others
-        }
+      closeTransaction(pool, err);
+    }
+    log.debug("Transaction closed, session closed in pool " + pool);
+  }
+
+  private void closeTransaction(String pool, boolean err) {
+    Connection con = getConnection(pool);
+    Transaction trx = getTransaction(pool);
+    if (err && trx != null) {
+      try {
+        trx.rollback();
+      } catch (Throwable t) {
+        // ignore these exception not to hide others
       }
-      try {
-        if (connection != null && !connection.isClosed()) {
-          connection.close();
-        }
-      } catch (SQLException e) {
-        log.error("Error while closing the connection", e);
+    }
+    try {
+      if (con != null && !con.isClosed()) {
+        con.close();
       }
-      deleteSessionHandler();
-      closeSession();
+    } catch (SQLException e) {
+      log.error("Error while closing the connection in pool " + pool, e);
     }
-    setSession(null);
-    log.debug("Transaction closed, session closed");
+    closeSession(pool);
+    removeTransaction(pool);
+    removeConnection(pool);
+    setUnavailablePool(pool);
   }
 
   /**
    * Commits the transaction and starts a new transaction.
    */
   public void commitAndStart() {
+    commitAndStart(DEFAULT_POOL);
+  }
+
+  private void commitAndStart(String pool) {
     Check.isFalse(TriggerHandler.getInstance().isDisabled(),
         "Triggers disabled, commit is not allowed when in triggers-disabled mode, "
             + "call TriggerHandler.enable() before committing");
 
     checkInvariant();
-    flushRemainingChanges();
-    tx.commit();
-    tx = null;
-    tx = getSession().beginTransaction();
+    flushRemainingChanges(pool);
+    Transaction trx = getTransaction(pool);
+    if (trx != null) {
+      trx.commit();
+    }
+    setTransaction(pool, getSession(pool).beginTransaction());
     log.debug("Committed and started new transaction");
   }
 
-  private void flushRemainingChanges() {
+  private void flushRemainingChanges(String pool) {
 
     // business event handlers can change the data
     // during flush, flush several times until
     // the session is really cleaned up
     int countFlushes = 0;
-    while (OBDal.getInstance().getSession().isDirty()) {
-      OBDal.getInstance().flush();
+    while (OBDal.getInstance(pool).getSession().isDirty()) {
+      OBDal.getInstance(pool).flush();
       countFlushes++;
       // arbitrary point to give up...
       if (countFlushes > 100) {
@@ -379,40 +654,56 @@
   }
 
   /**
-   * Rolls back the transaction and closes the getSession().
+   * Rolls back the transaction and closes the session.
    */
   public void rollback() {
-    log.debug("Rolling back transaction");
+    rollback(DEFAULT_POOL);
+  }
+
+  /**
+   * Rolls back the transaction and closes the session.
+   * 
+   * @param pool
+   *          the name of the pool which the transaction belongs.
+   */
+  public void rollback(String pool) {
+    log.debug("Rolling back transaction in pool " + pool);
+    Connection con = getConnection(pool);
     try {
-      checkInvariant();
-      if (connection == null || (connection != null && !connection.isClosed())) {
-        tx.rollback();
+      checkInvariant(pool);
+      if (con == null || !con.isClosed()) {
+        getTransaction(pool).rollback();
       }
-      tx = null;
     } catch (SQLException e) {
-      log.error("Error while closing the connection", e);
+      log.error("Error while closing the connection in pool " + pool, e);
     } finally {
-      deleteSessionHandler();
+      removeTransaction(pool);
+      removeConnection(pool);
+      setUnavailablePool(pool);
       try {
-        if (connection != null && !connection.isClosed()) {
-          connection.close();
+        if (con == null || !con.isClosed()) {
+          con.close();
         }
         log.debug("Closing session");
-        closeSession();
+        closeSession(pool);
       } catch (SQLException e) {
-        log.error("Error while closing the connection", e);
+        log.error("Error while closing the connection in pool " + pool, e);
       }
     }
-    setSession(null);
   }
 
   /**
    * The invariant is that for begin, rollback and commit the session etc. are alive
    */
   private void checkInvariant() {
-    Check.isNotNull(getSession(), "Session is null");
-    Check.isNotNull(tx, "Tx is null");
-    Check.isTrue(tx.isActive(), "Tx is not active");
+    checkInvariant(DEFAULT_POOL);
+  }
+
+  private void checkInvariant(String pool) {
+    Check.isNotNull(sessions.get(pool), "Session is null");
+    Transaction theTx = getTransaction(pool);
+    Check.isNotNull(theTx, "Tx is null");
+    Check.isTrue(theTx.isActive(), "Tx is not active");
   }
 
   /**
@@ -442,4 +733,5 @@
   public boolean doSessionInViewPatter() {
     return true;
   }
+
 }
--- a/src/org/openbravo/dal/service/OBCriteria.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/dal/service/OBCriteria.java	Mon Jan 23 12:55:58 2017 +0100
@@ -71,16 +71,22 @@
   private boolean initialized = false;
   private boolean modified = false;
 
-  // package visible
-
   public OBCriteria(String entityOrClassName) {
     super(entityOrClassName, (SessionImplementor) SessionHandler.getInstance().getSession());
   }
 
+  public OBCriteria(String entityOrClassName, SessionImplementor session) {
+    super(entityOrClassName, session);
+  }
+
   public OBCriteria(String entityOrClassName, String alias) {
     super(entityOrClassName, alias, (SessionImplementor) SessionHandler.getInstance().getSession());
   }
 
+  public OBCriteria(String entityOrClassName, String alias, SessionImplementor session) {
+    super(entityOrClassName, alias, session);
+  }
+
   /**
    * See the list() method of the Hibernate Criteria class.
    * 
--- a/src/org/openbravo/dal/service/OBDal.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/dal/service/OBDal.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2016 Openbravo SLU 
+ * All portions are Copyright (C) 2008-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -23,6 +23,7 @@
 import java.sql.Connection;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.log4j.Logger;
 import org.hibernate.ObjectNotFoundException;
@@ -38,8 +39,8 @@
 import org.openbravo.base.model.ModelProvider;
 import org.openbravo.base.model.Property;
 import org.openbravo.base.model.UniqueConstraint;
+import org.openbravo.base.provider.OBNotSingleton;
 import org.openbravo.base.provider.OBProvider;
-import org.openbravo.base.provider.OBSingleton;
 import org.openbravo.base.session.SessionFactoryController;
 import org.openbravo.base.structure.BaseOBObject;
 import org.openbravo.base.structure.ClientEnabled;
@@ -49,6 +50,7 @@
 import org.openbravo.dal.core.OBContext;
 import org.openbravo.dal.core.SessionHandler;
 import org.openbravo.dal.security.SecurityChecker;
+import org.openbravo.database.ExternalConnectionPool;
 import org.openbravo.model.ad.system.Client;
 import org.openbravo.model.common.enterprise.Organization;
 
@@ -65,22 +67,52 @@
 // object
 // TODO: re-check singleton pattern when a new factory/dependency injection
 // approach is implemented.
-public class OBDal implements OBSingleton {
+public class OBDal implements OBNotSingleton {
   private static final Logger log = Logger.getLogger(OBDal.class);
 
   private static OBDal instance;
 
+  private static ConcurrentHashMap<String, OBDal> otherPoolInstances = new ConcurrentHashMap<>();
+  private String poolName;
+
   /**
    * @return the singleton instance of the OBDal service
    */
   public static OBDal getInstance() {
     if (instance == null) {
       instance = OBProvider.getInstance().get(OBDal.class);
+      instance.poolName = ExternalConnectionPool.DEFAULT_POOL;
     }
     return instance;
   }
 
   /**
+   * @return the singleton instance of the OBDal read-only service
+   */
+  public static OBDal getReadOnlyInstance() {
+    return getInstance(ExternalConnectionPool.READONLY_POOL);
+  }
+
+  /**
+   * @param pool
+   *          the name of the pool used by the OBDal service that will be returned
+   * 
+   * @return the singleton instance related to the name passed as parameter
+   */
+  public static OBDal getInstance(String pool) {
+    if (ExternalConnectionPool.DEFAULT_POOL.equals(pool)) {
+      return getInstance();
+    }
+    if (!otherPoolInstances.containsKey(pool)) {
+      OBDal dal = OBProvider.getInstance().get(OBDal.class);
+      dal.poolName = pool;
+      otherPoolInstances.putIfAbsent(pool, dal);
+    }
+
+    return otherPoolInstances.get(pool);
+  }
+
+  /**
    * After calling this method all collections and queries will only return objects which are
    * active. Note that this overrides the active filtering setting on
    * {@link OBQuery#setFilterOnActive(boolean)} and {@link OBCriteria#setFilterOnActive(boolean)}.
@@ -88,7 +120,7 @@
    * @see #disableActiveFilter()
    */
   public void enableActiveFilter() {
-    SessionHandler.getInstance().getSession().enableFilter("activeFilter")
+    SessionHandler.getInstance().getSession(poolName).enableFilter("activeFilter")
         .setParameter("activeParam", "Y");
   }
 
@@ -112,11 +144,16 @@
    * @see #enableActiveFilter()
    */
   public void disableActiveFilter() {
-    SessionHandler.getInstance().getSession().disableFilter("activeFilter");
+    SessionHandler.getInstance().getSession(poolName).disableFilter("activeFilter");
   }
 
+  /**
+   * Returns the status of the active filter.
+   * 
+   * @return true if the active filter is enabled, false if it is disabled
+   */
   public boolean isActiveFilterEnabled() {
-    return SessionHandler.getInstance().getSession().getEnabledFilter("activeFilter") != null;
+    return SessionHandler.getInstance().getSession(poolName).getEnabledFilter("activeFilter") != null;
   }
 
   /**
@@ -152,8 +189,8 @@
     final ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
     try {
       Thread.currentThread().setContextClassLoader(BorrowedConnectionProxy.class.getClassLoader());
-      final Connection connection = ((SessionImplementor) SessionHandler.getInstance().getSession())
-          .connection();
+      final Connection connection = ((SessionImplementor) SessionHandler.getInstance().getSession(
+          poolName)).connection();
       return connection;
     } finally {
       Thread.currentThread().setContextClassLoader(currentLoader);
@@ -164,15 +201,15 @@
    * @return the current hibernate session
    */
   public Session getSession() {
-    return SessionHandler.getInstance().getSession();
+    return SessionHandler.getInstance().getSession(poolName);
   }
 
   /**
    * Commits the transaction and closes session.
    */
   public void commitAndClose() {
-    if (SessionHandler.isSessionHandlerPresent()) {
-      SessionHandler.getInstance().commitAndClose();
+    if (SessionHandler.isSessionHandlerPresent(poolName)) {
+      SessionHandler.getInstance().commitAndClose(poolName);
     }
   }
 
@@ -180,34 +217,36 @@
    * Rolls back the transaction and closes the session.
    */
   public void rollbackAndClose() {
-    if (SessionHandler.isSessionHandlerPresent()) {
-      SessionHandler.getInstance().rollback();
+    if (SessionHandler.isSessionHandlerPresent(poolName)) {
+      SessionHandler.getInstance().rollback(poolName);
     }
   }
 
   /**
    * Utility method to log all entities loaded into the current hibernate session. Useful to debug
    * slow flush() calls.
+   * 
+   * @return the hibernate session statistics that are used to log the information
    */
-  private void dumpSessionEntities() {
-    SessionStatistics sessStat = SessionHandler.getInstance().getSession().getStatistics();
+  private SessionStatistics dumpSessionEntities() {
+    SessionStatistics sessStat = SessionHandler.getInstance().getSession(poolName).getStatistics();
     log.debug("Dumping all entities in session");
     for (Object o : sessStat.getEntityKeys()) {
       log.debug(o);
     }
+    return sessStat;
   }
 
   /**
    * Flushes the current state to the database.
    */
   public void flush() {
-    if (SessionHandler.isSessionHandlerPresent()) {
+    if (SessionHandler.isSessionHandlerPresent(poolName)) {
       long s1 = System.currentTimeMillis();
-      SessionHandler.getInstance().getSession().flush();
+      SessionHandler.getInstance().getSession(poolName).flush();
       if (log.isDebugEnabled()) {
         long s2 = System.currentTimeMillis();
-        SessionStatistics sessStat = SessionHandler.getInstance().getSession().getStatistics();
-        dumpSessionEntities();
+        SessionStatistics sessStat = dumpSessionEntities();
         log.debug(
             "Flush of " + sessStat.getEntityCount() + " entities and "
                 + sessStat.getCollectionCount() + " collections took: " + (s2 - s1),
@@ -247,7 +286,7 @@
       }
       SecurityChecker.getInstance().checkWriteAccess(obj);
     }
-    SessionHandler.getInstance().save(obj);
+    SessionHandler.getInstance().save(poolName, obj);
   }
 
   /**
@@ -270,7 +309,7 @@
     // TODO: log using entityName
     log.debug("Removing object " + obj.getClass().getName());
     SecurityChecker.getInstance().checkDeleteAllowed(obj);
-    SessionHandler.getInstance().delete(obj);
+    SessionHandler.getInstance().delete(poolName, obj);
   }
 
   /**
@@ -282,7 +321,7 @@
    * @see Session#refresh(Object)
    */
   public void refresh(Object obj) {
-    SessionHandler.getInstance().getSession().refresh(obj);
+    SessionHandler.getInstance().getSession(poolName).refresh(obj);
   }
 
   /**
@@ -297,7 +336,7 @@
   public <T extends Object> T get(Class<T> clazz, Object id) {
     checkReadAccess(clazz);
     try {
-      return SessionHandler.getInstance().find(clazz, id);
+      return SessionHandler.getInstance().find(poolName, clazz, id);
     } catch (ObjectNotFoundException ignore) {
       // ObjectNotFoundException is thrown when there was a proxy in cache for this id but the
       // record does not exist in DB. As if there was no proxy, the same invokation would return
@@ -316,7 +355,7 @@
    * @return true if exists, false otherwise
    */
   public boolean exists(String entityName, Object id) {
-    return null != SessionHandler.getInstance().find(entityName, id);
+    return null != SessionHandler.getInstance().find(poolName, entityName, id);
   }
 
   /**
@@ -330,7 +369,7 @@
    */
   public BaseOBObject get(String entityName, Object id) {
     checkReadAccess(entityName);
-    return SessionHandler.getInstance().find(entityName, id);
+    return SessionHandler.getInstance().find(poolName, entityName, id);
   }
 
   /**
@@ -394,6 +433,7 @@
     obQuery.setWhereAndOrderBy(whereOrderByClause);
     obQuery.setEntity(ModelProvider.getInstance().getEntity(fromClz));
     obQuery.setParameters(parameters);
+    obQuery.setPoolName(poolName);
     return obQuery;
   }
 
@@ -429,6 +469,7 @@
     obQuery.setWhereAndOrderBy(whereOrderByClause);
     obQuery.setEntity(ModelProvider.getInstance().getEntity(entityName));
     obQuery.setParameters(parameters);
+    obQuery.setPoolName(poolName);
     return obQuery;
   }
 
@@ -442,7 +483,8 @@
   public <T extends BaseOBObject> OBCriteria<T> createCriteria(Class<T> clz) {
     checkReadAccess(clz);
     final Entity entity = ModelProvider.getInstance().getEntity(clz);
-    final OBCriteria<T> obCriteria = new OBCriteria<T>(entity.getName());
+    final OBCriteria<T> obCriteria = new OBCriteria<T>(entity.getName(),
+        (SessionImplementor) SessionHandler.getInstance().getSession(poolName));
     obCriteria.setEntity(entity);
     return obCriteria;
   }
@@ -459,7 +501,8 @@
   public <T extends BaseOBObject> OBCriteria<T> createCriteria(Class<T> clz, String alias) {
     checkReadAccess(clz);
     final Entity entity = ModelProvider.getInstance().getEntity(clz);
-    final OBCriteria<T> obCriteria = new OBCriteria<T>(entity.getName(), alias);
+    final OBCriteria<T> obCriteria = new OBCriteria<T>(entity.getName(), alias,
+        (SessionImplementor) SessionHandler.getInstance().getSession(poolName));
     obCriteria.setEntity(entity);
     return obCriteria;
   }
@@ -473,7 +516,8 @@
    */
   public <T extends BaseOBObject> OBCriteria<T> createCriteria(String entityName) {
     checkReadAccess(entityName);
-    final OBCriteria<T> obCriteria = new OBCriteria<T>(entityName);
+    final OBCriteria<T> obCriteria = new OBCriteria<T>(entityName,
+        (SessionImplementor) SessionHandler.getInstance().getSession(poolName));
     obCriteria.setEntity(ModelProvider.getInstance().getEntity(entityName));
     return obCriteria;
   }
@@ -489,7 +533,8 @@
    */
   public <T extends BaseOBObject> OBCriteria<T> createCriteria(String entityName, String alias) {
     checkReadAccess(entityName);
-    final OBCriteria<T> obCriteria = new OBCriteria<T>(entityName, alias);
+    final OBCriteria<T> obCriteria = new OBCriteria<T>(entityName, alias,
+        (SessionImplementor) SessionHandler.getInstance().getSession(poolName));
     obCriteria.setEntity(ModelProvider.getInstance().getEntity(entityName));
     return obCriteria;
   }
--- a/src/org/openbravo/dal/service/OBQuery.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/dal/service/OBQuery.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2008-2014 Openbravo SLU 
+ * All portions are Copyright (C) 2008-2016 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -76,6 +76,8 @@
 
   private String selectClause;
 
+  private String poolName;
+
   // package visible
   OBQuery() {
   }
@@ -199,6 +201,13 @@
     return qryStr;
   }
 
+  /**
+   * Creates a Hibernate Query object intended to delete records of the Entity associated to the
+   * OBQuery instance. To generate the criteria of the deletion, it makes use of the whereclause and
+   * extra filters (for readable organizations etc.).
+   * 
+   * @return a new Hibernate Query object
+   */
   public Query deleteQuery() {
     final String qryStr = createQueryString();
     String whereClause;
@@ -530,7 +539,7 @@
   }
 
   private Session getSession() {
-    return SessionHandler.getInstance().getSession();
+    return SessionHandler.getInstance().getSession(poolName);
   }
 
   /**
@@ -611,43 +620,102 @@
     this.namedParameters.put(paramName, value);
   }
 
+  /**
+   * Returns the position of the first row to be retrieved by the underlying query.
+   * 
+   * @return the position of the first row to be retrieved
+   */
   public int getFirstResult() {
     return firstResult;
   }
 
+  /**
+   * Sets the position of the first row to retrieve.
+   * 
+   * @param firstResult
+   *          the position of the first row to retrieve
+   */
   public void setFirstResult(int firstResult) {
     this.firstResult = firstResult;
   }
 
+  /**
+   * Returns the maximum number of rows to be retrieved by the underlying query.
+   * 
+   * @return the maximum number of rows to be retrieved
+   */
   public int getMaxResult() {
     return maxResult;
   }
 
+  /**
+   * Sets the maximum number of rows to retrieve.
+   * 
+   * @param maxResult
+   *          the maximum number of rows to retrieve
+   */
   public void setMaxResult(int maxResult) {
     this.maxResult = maxResult;
   }
 
+  /**
+   * Returns the fetch size of the underlying query.
+   * 
+   * @return the fetch size of the underlying query
+   */
   public int getFetchSize() {
     return fetchSize;
   }
 
+  /**
+   * Sets a fetch size for the underlying query.
+   * 
+   * @param fetchSize
+   *          the fetch size for the underlying query
+   */
   public void setFetchSize(int fetchSize) {
     this.fetchSize = fetchSize;
   }
 
+  /**
+   * Returns the select clause defined for the underlying query.
+   * 
+   * @return the select clause defined for the underlying query
+   */
   public String getSelectClause() {
     return selectClause;
   }
 
+  /**
+   * Defines a select clause for the underlying query.
+   * 
+   * @param selectClause
+   *          the select clause to be used by the underlying query.
+   */
   public void setSelectClause(String selectClause) {
     this.selectClause = selectClause;
   }
 
+  /**
+   * Sets the type of the underlying query.
+   * 
+   * @param queryType
+   *          the type of the underlying query
+   */
   public void setQueryType(String queryType) {
     this.queryType = queryType;
   }
 
+  /**
+   * Returns the type of the underlying query.
+   * 
+   * @return a String with the type of the underlying query
+   */
   public String getQueryType() {
     return this.queryType;
   }
+
+  void setPoolName(String poolName) {
+    this.poolName = poolName;
+  }
 }
--- a/src/org/openbravo/erpCommon/utility/Utility.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/erpCommon/utility/Utility.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License. 
  * The Original Code is Openbravo ERP. 
  * The Initial Developer of the Original Code is Openbravo SLU 
- * All portions are Copyright (C) 2001-2016 Openbravo SLU
+ * All portions are Copyright (C) 2001-2017 Openbravo SLU
  * All Rights Reserved. 
  * Contributor(s):  ______________________________________.
  ************************************************************************
@@ -2211,51 +2211,57 @@
     try {
 
       if ("yourcompanylogin".equals(logo)) {
-        img = OBDal.getInstance().get(SystemInformation.class, "0").getYourCompanyLoginImage();
+        img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
+            .getYourCompanyLoginImage();
       } else if ("youritservicelogin".equals(logo)) {
-        img = OBDal.getInstance().get(SystemInformation.class, "0").getYourItServiceLoginImage();
+        img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
+            .getYourItServiceLoginImage();
       } else if ("yourcompanymenu".equals(logo)) {
-        img = OBDal.getInstance()
+        img = OBDal.getReadOnlyInstance()
             .get(ClientInformation.class, OBContext.getOBContext().getCurrentClient().getId())
             .getYourCompanyMenuImage();
         if (img == null) {
-          img = OBDal.getInstance().get(SystemInformation.class, "0").getYourCompanyMenuImage();
+          img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
+              .getYourCompanyMenuImage();
         }
       } else if ("yourcompanybig".equals(logo)) {
-        img = OBDal.getInstance()
+        img = OBDal.getReadOnlyInstance()
             .get(ClientInformation.class, OBContext.getOBContext().getCurrentClient().getId())
             .getYourCompanyBigImage();
         if (img == null) {
-          img = OBDal.getInstance().get(SystemInformation.class, "0").getYourCompanyBigImage();
+          img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
+              .getYourCompanyBigImage();
         }
       } else if ("yourcompanydoc".equals(logo)) {
         if (org != null && !org.equals("")) {
-          Organization organization = OBDal.getInstance().get(Organization.class, org);
+          Organization organization = OBDal.getReadOnlyInstance().get(Organization.class, org);
           img = organization.getOrganizationInformationList().get(0).getYourCompanyDocumentImage();
         }
         if (img == null) {
-          img = OBDal.getInstance()
+          img = OBDal.getReadOnlyInstance()
               .get(ClientInformation.class, OBContext.getOBContext().getCurrentClient().getId())
               .getYourCompanyDocumentImage();
         }
         if (img == null) {
-          img = OBDal.getInstance().get(SystemInformation.class, "0").getYourCompanyDocumentImage();
+          img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
+              .getYourCompanyDocumentImage();
         }
       } else if ("banner-production".equals(logo)) {
-        img = OBDal.getInstance().get(SystemInformation.class, "0").getProductionBannerImage();
+        img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
+            .getProductionBannerImage();
       } else if ("yourcompanylegal".equals(logo)) {
         if (org != null && !org.equals("")) {
-          Organization organization = OBDal.getInstance().get(Organization.class, org);
+          Organization organization = OBDal.getReadOnlyInstance().get(Organization.class, org);
           img = organization.getOrganizationInformationList().get(0).getYourCompanyDocumentImage();
         }
         if (img == null) {
 
-          img = OBDal.getInstance()
+          img = OBDal.getReadOnlyInstance()
               .get(ClientInformation.class, OBContext.getOBContext().getCurrentClient().getId())
               .getYourCompanyDocumentImage();
 
           if (img == null) {
-            img = OBDal.getInstance().get(SystemInformation.class, "0")
+            img = OBDal.getReadOnlyInstance().get(SystemInformation.class, "0")
                 .getYourCompanyDocumentImage();
           }
         }
@@ -2604,8 +2610,8 @@
    * 
    */
   public static Country getCountryFromOrgId(String orgid) {
-    Organization organization = (Organization) OBDal.getInstance().get(Organization.ENTITY_NAME,
-        orgid);
+    Organization organization = (Organization) OBDal.getReadOnlyInstance().get(
+        Organization.ENTITY_NAME, orgid);
     List<OrganizationInformation> orgInfoList = organization.getOrganizationInformationList();
     if (orgInfoList.isEmpty()) {
       return null;
@@ -2638,7 +2644,7 @@
       return df.format(date);
     } finally {
       OBContext.restorePreviousMode();
-      OBDal.getInstance().commitAndClose();
+      OBDal.getReadOnlyInstance().commitAndClose();
     }
   }
 
@@ -2693,7 +2699,7 @@
       }
     } finally {
       OBContext.restorePreviousMode();
-      OBDal.getInstance().commitAndClose();
+      OBDal.getReadOnlyInstance().commitAndClose();
     }
   }
 
--- a/src/org/openbravo/erpCommon/utility/reporting/Report.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/erpCommon/utility/reporting/Report.java	Mon Jan 23 12:55:58 2017 +0100
@@ -9,7 +9,7 @@
  * either express or implied. See the License for the specific language
  * governing rights and limitations under the License. The Original Code is
  * Openbravo ERP. The Initial Developer of the Original Code is Openbravo SLU All
- * portions are Copyright (C) 2001-2014 Openbravo SLU All Rights Reserved.
+ * portions are Copyright (C) 2001-2017 Openbravo SLU All Rights Reserved.
  * Contributor(s): ______________________________________.
  * ***********************************************************************
  */
@@ -28,6 +28,7 @@
 import org.openbravo.database.ConnectionProvider;
 import org.openbravo.erpCommon.utility.Utility;
 import org.openbravo.erpCommon.utility.reporting.TemplateInfo.EmailDefinition;
+import org.openbravo.service.db.DalConnectionProvider;
 
 public class Report {
   public String getOrgId() {
@@ -79,6 +80,13 @@
 
   private TemplateInfo templateInfo;
 
+  public Report(DocumentType documentType, String documentId, String strLanguage,
+      String templateId, boolean multiReport, OutputTypeEnum outputTypeString)
+      throws ReportingException, ServletException {
+    this(DalConnectionProvider.getReadOnlyConnectionProvider(), documentType, documentId,
+        strLanguage, templateId, multiReport, outputTypeString);
+  }
+
   public Report(ConnectionProvider connectionProvider, DocumentType documentType,
       String documentId, String strLanguage, String templateId, boolean multiReport,
       OutputTypeEnum outputTypeString) throws ReportingException, ServletException {
--- a/src/org/openbravo/erpCommon/utility/reporting/ReportManager.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/erpCommon/utility/reporting/ReportManager.java	Mon Jan 23 12:55:58 2017 +0100
@@ -11,7 +11,7 @@
  * under the License.
  * The Original Code is Openbravo ERP.
  * The Initial Developer of the Original Code is Business Momentum b.v.
- * All portions are Copyright (C) 2007-2016 Openbravo SLU 
+ * All portions are Copyright (C) 2007-2017 Openbravo SLU 
  * All Rights Reserved. 
  * Contributor(s):  Business Momentum b.v. (http://www.businessmomentum.eu).
  *************************************************************************
@@ -26,9 +26,6 @@
 import java.util.Locale;
 import java.util.Map;
 
-import net.sf.jasperreports.engine.JRException;
-import net.sf.jasperreports.engine.JasperPrint;
-
 import org.apache.log4j.Logger;
 import org.openbravo.base.secureApp.VariablesSecureApp;
 import org.openbravo.base.weld.WeldUtils;
@@ -38,8 +35,12 @@
 import org.openbravo.client.application.report.ReportingUtils.ExportType;
 import org.openbravo.database.ConnectionProvider;
 import org.openbravo.erpCommon.utility.Utility;
+import org.openbravo.service.db.DalConnectionProvider;
 import org.openbravo.utils.Replace;
 
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JasperPrint;
+
 public class ReportManager {
   private static Logger log4j = Logger.getLogger(ReportManager.class);
   private static final String TEMP_REPORT_DIR = "tmp";
@@ -54,6 +55,12 @@
   private String _prefix;
   private String _strAttachmentPath;
 
+  public ReportManager(String ftpDirectory, String replaceWithFull, String baseDesignPath,
+      String defaultDesignPath, String prefix, boolean multiReport) {
+    this(DalConnectionProvider.getReadOnlyConnectionProvider(), ftpDirectory, replaceWithFull,
+        baseDesignPath, defaultDesignPath, prefix, multiReport);
+  }
+
   public ReportManager(ConnectionProvider connectionProvider, String ftpDirectory,
       String replaceWithFull, String baseDesignPath, String defaultDesignPath, String prefix,
       boolean multiReport) {
--- a/src/org/openbravo/erpCommon/utility/reporting/printing/PrintController.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/erpCommon/utility/reporting/printing/PrintController.java	Mon Jan 23 12:55:58 2017 +0100
@@ -8,7 +8,7 @@
  * either express or implied. See the License for the specific language
  * governing rights and limitations under the License. The Original Code is
  * Openbravo ERP. The Initial Developer of the Original Code is Openbravo SLU All
- * portions are Copyright (C) 2008-2016 Openbravo SLU All Rights Reserved.
+ * portions are Copyright (C) 2008-2017 Openbravo SLU All Rights Reserved.
  * Contributor(s): ______________________________________.
  */
 package org.openbravo.erpCommon.utility.reporting.printing;
@@ -38,10 +38,6 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import net.sf.jasperreports.engine.JRException;
-import net.sf.jasperreports.engine.JasperPrint;
-import net.sf.jasperreports.export.SimplePdfExporterConfiguration;
-
 import org.apache.commons.fileupload.FileItem;
 import org.codehaus.jettison.json.JSONException;
 import org.codehaus.jettison.json.JSONObject;
@@ -81,6 +77,10 @@
 import org.openbravo.utils.FormatUtilities;
 import org.openbravo.xmlEngine.XmlDocument;
 
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.export.SimplePdfExporterConfiguration;
+
 @SuppressWarnings("serial")
 public class PrintController extends HttpSecureAppServlet {
   private final Map<String, TemplateData[]> differentDocTypes = new HashMap<String, TemplateData[]>();
@@ -195,7 +195,7 @@
       multiReports = (documentIds.length > 1);
 
       reports = (Map<String, Report>) vars.getSessionObject(sessionValuePrefix + ".Documents");
-      final ReportManager reportManager = new ReportManager(this, globalParameters.strFTPDirectory,
+      final ReportManager reportManager = new ReportManager(globalParameters.strFTPDirectory,
           strReplaceWithFull, globalParameters.strBaseDesignPath,
           globalParameters.strDefaultDesignPath, globalParameters.prefix, multiReports);
 
@@ -273,7 +273,7 @@
               log4j.debug("Processing document with id: " + documentId);
 
             try {
-              final Report report = new Report(this, documentType, documentId, vars.getLanguage(),
+              final Report report = new Report(documentType, documentId, vars.getLanguage(),
                   "default", multiReports, OutputTypeEnum.DEFAULT);
               reports.put(documentId, report);
 
@@ -412,7 +412,7 @@
                 + fullDocumentIdentifier);
             final String templateId = vars.getRequestGlobalVariable("templates", "templates");
             final String documentId = pocData[0].documentId;
-            final Report report = new Report(this, documentType, documentId, vars.getLanguage(),
+            final Report report = new Report(documentType, documentId, vars.getLanguage(),
                 templateId, multiReports, OutputTypeEnum.DEFAULT);
             o.put("templateId", templateId);
             o.put("subject", report.getEmailDefinition().getSubject());
@@ -585,7 +585,7 @@
       localStrDocumentId = localStrDocumentId.replaceAll("\\(|\\)|'", "");
     }
     try {
-      report = new Report(this, documentType, localStrDocumentId, vars.getLanguage(), templateId,
+      report = new Report(documentType, localStrDocumentId, vars.getLanguage(), templateId,
           multiReports, outputType);
     } catch (final ReportingException e) {
       log4j.error(e);
--- a/src/org/openbravo/service/db/DalConnectionProvider.java	Mon Jan 23 12:36:31 2017 +0100
+++ b/src/org/openbravo/service/db/DalConnectionProvider.java	Mon Jan 23 12:55:58 2017 +0100
@@ -31,6 +31,7 @@
 import org.openbravo.dal.core.SessionHandler;
 import org.openbravo.dal.service.OBDal;
 import org.openbravo.database.ConnectionProvider;
+import org.openbravo.database.ExternalConnectionPool;
 import org.openbravo.database.SessionInfo;
 import org.openbravo.exception.NoConnectionAvailableException;
 
@@ -57,13 +58,23 @@
   // This parameter can be used to define whether the OBDal needs to be flushed when the connection
   // is retrieved or not
   private boolean flush = true;
+  private String pool;
 
   public void destroy() throws Exception {
     // never close
   }
 
   public DalConnectionProvider() {
+    pool = ExternalConnectionPool.DEFAULT_POOL;
+  }
 
+  private DalConnectionProvider(String poolName) {
+    pool = poolName;
+    flush = false;
+  }
+
+  public static DalConnectionProvider getReadOnlyConnectionProvider() {
+    return new DalConnectionProvider(ExternalConnectionPool.READONLY_POOL);
   }
 
   /**
@@ -72,17 +83,18 @@
    *          if set to true, the getConnection method will flush the OBDal instance.
    */
   public DalConnectionProvider(boolean flush) {
+    pool = ExternalConnectionPool.DEFAULT_POOL;
     this.flush = flush;
   }
 
   public Connection getConnection() throws NoConnectionAvailableException {
     if (connection == null) {
-      connection = OBDal.getInstance().getConnection(flush);
+      connection = OBDal.getInstance(pool).getConnection(flush);
     }
 
     // always flush all remaining actions
     if (flush) {
-      OBDal.getInstance().flush();
+      OBDal.getInstance(pool).flush();
     }
     return connection;
   }
@@ -108,7 +120,7 @@
   }
 
   public Connection getTransactionConnection() throws NoConnectionAvailableException, SQLException {
-    Connection conn = SessionHandler.getInstance().getNewConnection();
+    Connection conn = SessionHandler.getInstance().getNewConnection(pool);
 
     if (conn == null) {
       throw new NoConnectionAvailableException("Couldn't get an available connection");