package com.transmem.data.db;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import java.util.Map;
import java.util.HashMap;
import java.util.logging.Logger;
/**
* Databases contains a list of DataSource references and provides
* java.sql.Connection objects from the DataSource pool specified
* by a category and read/write operation.
* In this way, an action handler can get different connections from
* different physical databases for reading and writing. For example,
* a database can be used for updating user-related tables while
* another is only used for reading (which can be a replica).
* There can be multiple categories that separate different databases
* for different uses, for example, the USER database can be different
* from CORPUS database and they can be installed on different servers
* for better performance and scalability.
* The datasource objects are created during initiation of the Transmem
* servlet and stored in the ServletContext as application-wide variable.
*
* @version 0.1
* @author Ted Wen
* @date Jan. 2007
*/
public class Databases
{
public static final String CATEGORY_MAIN = "MAIN";
public static final String CATEGORY_USER = "USER";
public static final String CATEGORY_CORPUS = "CORPUS";
private Logger log_ = Logger.getLogger(Databases.class.getName());
private Map<String, DataSource> dsmap_; ///DataSource hash map for read-only databases
private Map<String, DataSource> dswmap_; ///DataSource hash map for write-only databases
public Databases()
{
log_.entering("Databases","Databases");
dsmap_ = new HashMap<String, DataSource>();
dswmap_ = new HashMap<String, DataSource>();
log_.exiting("Databases","Databases");
}
/**
* Add a datasource to the read or write list with the category string as the key.
* Algorithm:
* If WRITE is specified, then save it in write map; else in read map;
* Multiple categories can be set, but must be separated by spaces. Any category string is
* acceptable and converted to uppercase.
* @param ds - shared DataSource object
* @param cat - category string such as USER, CORPUS
* @param readwrite - a string containing words separated by spaces such as "READwrite".
*/
public void addDataSource(DataSource ds, String category, String readwrite)
{
log_.entering("Databases","addDataSource",category);
String[] cats = category.toUpperCase().split(" ");
readwrite = readwrite.toUpperCase();
boolean forWrite = (readwrite.indexOf("WRITE")>=0);
boolean forRead = (readwrite.indexOf("READ")>=0);
for (int i=0; i<cats.length; i++)
{
String cat = cats[i].trim();
if (cat.length()<1) continue;
if (forWrite) {
dswmap_.put(cat, ds);
log_.info("DS '"+cat+"' forWrite put in dswmap");
}
if (forRead) {
dsmap_.put(cat, ds);
log_.info("DS '"+cat+"' forRead put in dsmap");
}
}
log_.exiting("Databases","addDataSource",category);
}
/**
* Get the java.sql.Connection from the DataSource maps according to
* the specified category and read/write tag.
* Algorithm:
* if forWrite then search write list for the category;
* if not found then search read list, and if the category not found, use default MAIN category;
* if for Readonly, then search read list, if not found by the given category, use MAIN category.
*
* @param cat - category string, can be USER, CORPUS, or others defined in web.xml
* @param forWrite - true if want updateable database and false for read-only.
* @return java.sql.Connection
*/
public Connection getConnection(String cat, boolean forWrite) throws SQLException
{
log_.entering("Databases","getConnection",cat);
cat = cat.toUpperCase();
if (forWrite)
if (dswmap_.containsKey(cat)) {
log_.info("Databases.getConnection("+cat+") return from dswmap_");
return dswmap_.get(cat).getConnection();
}
if (dsmap_.containsKey(cat)) {
log_.info("Databases.getConnection("+cat+") return from dsmap_");
return dsmap_.get(cat).getConnection();
} else {
log_.info("Databases.getConnection("+cat+") return from dsmap_ as default");
return dsmap_.get(CATEGORY_MAIN).getConnection();
}
}
/**
* Get the Connection of a category for reading only.
* @param cat - category string
* @return java.sql.Connection
*/
public Connection getConnection(String cat) throws SQLException
{
return getConnection(cat, false);
}
}