/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package fedora.server.utilities;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import fedora.server.config.DatastoreConfiguration;
import fedora.server.config.ModuleConfiguration;
import fedora.server.config.ServerConfiguration;
import fedora.server.errors.InconsistentTableSpecException;
import fedora.server.storage.ConnectionPool;
/**
* <p>
* SQL-related utility methods.
* </p>
* <p>
* <b>Implementation note:</b> Many of these static methods use JDBC objects
* which are difficult to mock out for unit tests. The methods now delegate to
* an instance of {@link SQLUtilityImpl} instead. The instance is declared
* <code>private</code>, but not <code>final</code>, so it can be
* overridden for unit tests. For example, see
* <code>TestFieldSearchSQLImpl.java</code>.
* </p>
* <p>
* Some of the methods involve no JDBC objects, and so are not delegated to the
* instance.
* </p>
*
* @author Chris Wilper
*/
public abstract class SQLUtility {
public static ConnectionPool getConnectionPool(ServerConfiguration fcfg)
throws SQLException {
ModuleConfiguration mcfg =
fcfg
.getModuleConfiguration("fedora.server.storage.ConnectionPoolManager");
String defaultPool = mcfg.getParameter("defaultPoolName").getValue();
DatastoreConfiguration dcfg =
fcfg.getDatastoreConfiguration(defaultPool);
return getConnectionPool(dcfg);
}
public static ConnectionPool getConnectionPool(DatastoreConfiguration cpDC)
throws SQLException {
return instance.i_getConnectionPool(cpDC);
}
public static void replaceInto(Connection conn,
String tableName,
String[] columns,
String[] values,
String uniqueColumn) throws SQLException {
replaceInto(conn, tableName, columns, values, uniqueColumn, null);
}
/**
* Adds or replaces a row in the given table.
*
* @param conn
* the connection to use
* @param table
* the name of the table
* @param columns
* the names of the columns whose values we're setting.
* @param values
* associated values
* @param uniqueColumn
* which column name is unique? The value of this column will be used
* in the where clause. It must be a column which is not numeric.
* @param numeric
* for each associated column, is it numeric? if null, all columns
* are assumed to be strings.
*/
public static void replaceInto(Connection conn,
String table,
String[] columns,
String[] values,
String uniqueColumn,
boolean[] numeric) throws SQLException {
instance.i_replaceInto(conn,
table,
columns,
values,
uniqueColumn,
numeric);
}
/**
* Updates an existing row.
*
* @return false if the row did not previously exist and therefore was not
* updated.
*/
public static boolean updateRow(Connection conn,
String table,
String[] columns,
String[] values,
String uniqueColumn,
boolean[] numeric) throws SQLException {
return instance.i_updateRow(conn,
table,
columns,
values,
uniqueColumn,
numeric);
}
/**
* Adds a new row.
*
* @throws SQLException
* if the row could not be added.
*/
public static void addRow(Connection conn,
String table,
String[] columns,
String[] values,
boolean[] numeric) throws SQLException {
instance.i_addRow(conn, table, columns, values, numeric);
}
/**
* Get a long string, which could be a TEXT or CLOB type. (CLOBs require
* special handling -- this method normalizes the reading of them)
*/
public static String getLongString(ResultSet rs, int pos)
throws SQLException {
return instance.i_getLongString(rs, pos);
}
public static void createNonExistingTables(ConnectionPool cPool,
InputStream dbSpec)
throws IOException, InconsistentTableSpecException, SQLException {
instance.i_createNonExistingTables(cPool, dbSpec);
}
/*
* ------------------------------------------------------------------------
* These methods involve no JDBC objects, and so remain at the class level.
* ------------------------------------------------------------------------
*/
public static String slashEscaped(String in) {
StringBuffer out = new StringBuffer();
for (int i = 0; i < in.length(); i++) {
char c = in.charAt(i);
if (c == '\\') {
out.append("\\\\"); // slash slash
} else {
out.append(c);
}
}
return out.toString();
}
public static String backslashEscape(String in) {
if (in == null) {
return in;
}
if (in.indexOf("\\") == -1) {
return in;
}
StringBuffer out = new StringBuffer();
for (int i = 0; i < in.length(); i++) {
char c = in.charAt(i);
if (c == '\\') {
out.append('\\');
}
out.append(c);
}
return out.toString();
}
public static String aposEscape(String in) {
if (in == null) {
return in;
}
if (in.indexOf("'") == -1) {
return in;
}
StringBuffer out = new StringBuffer();
for (int i = 0; i < in.length(); i++) {
char c = in.charAt(i);
if (c == '\'') {
out.append('\'');
}
out.append(c);
}
return out.toString();
}
/*
* ------------------------------------------------------------------------
* The instance that handles the JDBC operations, and the method stubs.
* ------------------------------------------------------------------------
*/
private static SQLUtility instance = new SQLUtilityImpl();
protected abstract ConnectionPool i_getConnectionPool(DatastoreConfiguration cpDC)
throws SQLException;
protected abstract void i_replaceInto(Connection conn,
String table,
String[] columns,
String[] values,
String uniqueColumn,
boolean[] numeric)
throws SQLException;
protected abstract boolean i_updateRow(Connection conn,
String table,
String[] columns,
String[] values,
String uniqueColumn,
boolean[] numeric)
throws SQLException;
protected abstract void i_addRow(Connection conn,
String table,
String[] columns,
String[] values,
boolean[] numeric) throws SQLException;
protected abstract void i_createNonExistingTables(ConnectionPool pool,
InputStream dbSpec)
throws IOException, InconsistentTableSpecException, SQLException;
protected abstract List<TableSpec> i_getNonExistingTables(Connection conn,
List<TableSpec> specs)
throws SQLException;
protected abstract void i_createTables(TableCreatingConnection tcConn,
List<TableSpec> specs)
throws SQLException;
protected abstract String i_getLongString(ResultSet rs, int pos)
throws SQLException;
}