/*
* JBoss, Home of Professional Open Source
* Copyright 2009 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.test.fwk;
import com.mysql.jdbc.Driver;
import org.infinispan.loaders.jdbc.DatabaseType;
import org.infinispan.loaders.jdbc.JdbcUtil;
import org.infinispan.loaders.jdbc.TableManipulation;
import org.infinispan.loaders.jdbc.connectionfactory.ConnectionFactory;
import org.infinispan.loaders.jdbc.connectionfactory.ConnectionFactoryConfig;
import org.infinispan.loaders.jdbc.connectionfactory.PooledConnectionFactory;
import org.infinispan.loaders.jdbc.connectionfactory.SimpleConnectionFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class that assures concurrent access to the in memory database.
*
* @author Mircea.Markus@jboss.com
* @author Navin Surtani (<a href="mailto:nsurtani@redhat.com">nsurtani@redhat.com</a>)
* @author Tristan Tarrant
*/
public class UnitTestDatabaseManager {
private static final ConnectionFactoryConfig realConfig = new ConnectionFactoryConfig();
private static AtomicInteger userIndex = new AtomicInteger(0);
private static final String DB_TYPE = System.getProperty("infinispan.test.jdbc.db", "H2");
private static final String H2_DRIVER = org.h2.Driver.class.getName();
private static final String NON_EXISTENT_DRIVER = "non.existent.Driver";
static {
String driver = "";
DatabaseType dt = DatabaseType.H2;
try {
if (!DB_TYPE.equalsIgnoreCase("H2")) {
if (DB_TYPE.equalsIgnoreCase("mysql")) {
driver = Driver.class.getName();
dt = DatabaseType.MYSQL;
} else {
driver = H2_DRIVER;
}
}
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
driver = H2_DRIVER;
Class.forName(H2_DRIVER);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
configure(dt, driver, realConfig);
}
private static void configure(DatabaseType dt, String driver, ConnectionFactoryConfig cfg) {
cfg.setDriverClass(driver);
switch (dt) {
case H2:
cfg.setConnectionUrl("jdbc:h2:mem:infinispan;DB_CLOSE_DELAY=-1");
cfg.setConnectionFactoryClass(PooledConnectionFactory.class.getName());
cfg.setUserName("sa");
break;
case MYSQL:
cfg.setConnectionUrl("jdbc:mysql://localhost/infinispan?user=ispn&password=ispn");
cfg.setConnectionFactoryClass(SimpleConnectionFactory.class.getName());
cfg.setUserName("ispn");
cfg.setPassword("ispn");
break;
}
}
public static ConnectionFactoryConfig getUniqueConnectionFactoryConfig() {
synchronized (realConfig) {
return returnBasedOnDifferentInstance();
}
}
public static ConnectionFactoryConfig getBrokenConnectionFactoryConfig() {
ConnectionFactoryConfig brokenConfig = new ConnectionFactoryConfig();
brokenConfig.setDriverClass(NON_EXISTENT_DRIVER);
return brokenConfig;
}
public static String getDatabaseName(Properties prop) {
StringTokenizer tokenizer = new StringTokenizer(prop.getProperty("cache.jdbc.url"), ":");
tokenizer.nextToken();
tokenizer.nextToken();
tokenizer.nextToken();
return tokenizer.nextToken();
}
private static String getShutdownUrl(ConnectionFactoryConfig props) {
String url = props.getConnectionUrl();
assert url != null;
StringTokenizer tokenizer = new StringTokenizer(url, ";");
String result = tokenizer.nextToken() + ";" + "shutdown=true";
return result;
}
private static ConnectionFactoryConfig returnBasedOnDifferentInstance() {
ConnectionFactoryConfig result = realConfig.clone();
String jdbcUrl = result.getConnectionUrl();
Pattern pattern = Pattern.compile("infinispan");
Matcher matcher = pattern.matcher(jdbcUrl);
boolean found = matcher.find();
assert found : String.format("%1s not found in %2s", pattern, jdbcUrl);
String newJdbcUrl = matcher.replaceFirst(extractTestName() + userIndex.incrementAndGet());
result.setConnectionUrl(newJdbcUrl);
return result;
}
private static String extractTestName() {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
if (stack.length == 0) return null;
for (int i = stack.length - 1; i > 0; i--) {
StackTraceElement e = stack[i];
String className = e.getClassName();
if (className.indexOf("org.infinispan") != -1) return className.replace('.', '_') + "_" + e.getMethodName();
}
return null;
}
public static TableManipulation buildDefaultTableManipulation() {
return new TableManipulation("ID_COLUMN", "VARCHAR(255)", "ISPN_JDBC", "DATA_COLUMN",
"BLOB", "TIMESTAMP_COLUMN", "BIGINT");
}
/**
* Counts the number of rows in the given table.
*/
public static int rowCount(ConnectionFactory connectionFactory, String tableName) {
Connection conn = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
conn = connectionFactory.getConnection();
String sql = "SELECT count(*) FROM " + tableName;
statement = conn.prepareStatement(sql);
resultSet = statement.executeQuery();
resultSet.next();
return resultSet.getInt(1);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
finally {
JdbcUtil.safeClose(resultSet);
JdbcUtil.safeClose(statement);
connectionFactory.releaseConnection(conn);
}
}
}