/*
* ome.testing
*
* Copyright 2006 University of Dundee. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.testing;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
/**
* abstract data container for testing. Sub-classes can set whatever values it
* would like in <code>init()</code>. After the OMEData instance is inserted
* into the test class by Spring, it SHOULD not be changed, but this is a matter
* of opionon. Setting the same <code>seed</code> value for two independent
* Data instances is also assumed to create identical values.
*
* @author Josh Moore <a
* href="mailto:josh.moore@gmx.de">josh.moore@gmx.de</a>
* @version 1.0
* @since 1.0
*/
public class OMEData {
final static String emptyColl = "Collections may not be empty.\n"
+ "You are currently trying to run a test on an OME database\n"
+ "that does not appear to have the needed data.\n"
+ "\n"
+ "There must be at least one:\n"
+ "project,dataset,image,experimenter,classification,category,category group,image annotation and dataset annotation\n"
+ "\n"
+ "Testing results would be unpredictable without test data.\n"
+ "Please fill your database and retry.";
private static Logger log = LoggerFactory.getLogger(OMEData.class);
boolean initialized = false;
DataSource ds;
Map properties;
Map values = new HashMap();
long seed;
Random rnd;
String[] files = new String[] { "test_data.properties" };
public void setDataSource(DataSource dataSource) {
this.ds = dataSource;
}
public OMEData() {
init();
}
public OMEData(String[] files) {
this.files = files;
init();
}
void init() {
properties = SqlPropertiesParser.parse(files);
seed = System.currentTimeMillis();
rnd = new Random(seed);
}
/* allows for storing arbitrary objects in data */
public void put(String propertyKey, Object value) {
toCache(propertyKey, value);
}
public List get(String propertyKey) {
if (inCache(propertyKey)) {
return (List) fromCache(propertyKey);
}
Object obj = properties.get(propertyKey);
if (obj == null) {
return null;
} else if (obj instanceof List) {
toCache(propertyKey, obj);
return (List) obj;
} else if (obj instanceof String) {
String sql = (String) obj;
List result = runSql(sql);
toCache(propertyKey, result);
return result;
} else {
throw new RuntimeException("Error in properties. Not expecting "
+ obj == null ? null : obj.getClass().getName());
}
}
List getRandomNumber(List l, Number number) {
if (number == null) {
return null;
}
if (l == null || l.size() == 0) {
log.warn(emptyColl);
return null;
}
List ordered = new ArrayList(l);
List result = new ArrayList();
while (ordered.size() > 0 && result.size() < number.longValue()) {
int choice = randomChoice(ordered.size());
result.add(ordered.remove(choice));
}
return result;
}
public List getMax(String propertyKey, int maximum) {
List l = get(propertyKey);
return getRandomNumber(l, new Integer(maximum));
}
public List getPercent(String propertyKey, double percent) {
List l = get(propertyKey);
return getRandomNumber(l, new Double(l.size() * percent));
}
public Object getRandom(String propertyKey) {
List l = get(propertyKey);
List result = getRandomNumber(l, new Integer(1));
if (result == null || result.size() < 1) {
return null;
}
return result.get(0);
}
public Object getFirst(String propertyKey) {
List l = get(propertyKey);
if (l == null || l.size() == 0) {
log.warn(emptyColl);
return null;
}
return l.get(0);
}
boolean inCache(String key) {
return values.containsKey(key);
}
void toCache(String key, Object value) {
values.put(key, value);
}
Object fromCache(String key) {
return values.get(key);
}
/**
* returns a list of results from the sql statement. if there is more than
* one column in the result set, a map from column name to Object is
* returned, else the Object itself.
*
* @param sql
* @return
*/
List runSql(String sql) {
JdbcTemplate jt = new JdbcTemplate(ds);
SqlRowSet rows = jt.queryForRowSet(sql);
List result = new ArrayList();
while (rows.next()) {
SqlRowSetMetaData meta = rows.getMetaData();
int count = meta.getColumnCount();
if (count > 1) {
Map cols = new HashMap();
String[] names = meta.getColumnNames();
for (int i = 0; i < names.length; i++) {
cols.put(names[i], rows.getObject(names[i]));
}
result.add(cols);
} else {
result.add(rows.getObject(1));
}
}
log.debug("SQL:" + sql + "\n\nResult:" + result);
return result;
}
public int randomChoice(int size) {
double value = (size - 1) * rnd.nextDouble();
return (new Double(value)).intValue();
}
}