/*
* @(#)Fixtures.java 2013-1-22 下午1:21:56
*
* Copyright (c) 2011-2013 Makersoft.org all rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
*
*/
package org.makersoft.test;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
import org.yaml.snakeyaml.introspector.BeanAccess;
/**
* Class description goes here.
*
* @version 2013-1-22 下午1:21:56
* @author Feng Kuok
*/
public class Fixtures {
static Pattern keyPattern = Pattern.compile("([^(]+)\\(([^)]+)\\)");
// Allows people to clear the cache, so Fixture is not stateful
public static Map<String, Object> idCache = new HashMap<String, Object>();
// public static void executeSQL(String sqlScript) {
// for(String sql: sqlScript.split(";")) {
// if(sql.trim().length() > 0) {
// DB.execute(sql);
// }
// }
// }
//
// public static void executeSQL(File sqlScript) {
// executeSQL(IO.readContentAsString(sqlScript));
// }
/**
* Delete all Model instances for the given types using the underlying persistence mechanisms
* @param types Types to delete
*/
public static void delete(Class<?>... types) {
// idCache.clear();
// disableForeignKeyConstraints();
// for (Class<? extends ActiveRecord> type : types) {
// try {
// Model.Manager.factoryFor(type).deleteAll();
// } catch(Exception e) {
// Logger.error(e, "While deleting " + type + " instances");
// }
//
// }
// enableForeignKeyConstraints();
// Play.pluginCollection.afterFixtureLoad();
}
/**
* Delete all Model instances for the given types using the underlying persistence mechanisms
* @param types Types to delete
*/
public static void delete(List<Class<?>> classes) {
// @SuppressWarnings("unchecked")
// Class<? extends ActiveRecord>[] types = new Class[classes.size()];
// for (int i = 0; i < types.length; i++) {
// types[i] = classes.get(i);
// }
// delete(types);
}
/**
* Delete all Model instances for the all available types using the underlying persistence mechanisms
*/
// @SuppressWarnings("unchecked")
public static void deleteAllModels() {
// List<Class<? extends ActiveRecord>> classes = new ArrayList<Class<? extends ActiveRecord>>();
// for (ApplicationClasses.ApplicationClass c : Play.classes.getAssignableClasses(ActiveRecord.class)) {
// classes.add((Class<? extends ActiveRecord>)c.javaClass);
// }
// disableForeignKeyConstraints();
// Fixtures.delete(classes);
}
// /**
// * Use deleteDatabase() instead
// * @deprecated use {@link deleteDatabase()} instead
// */
// @Deprecated
// public static void deleteAll() {
// deleteDatabase();
// }
static String[] dontDeleteTheseTables = new String[] {"play_evolutions"};
/**
* Flush the entire JDBC database
*/
public static void deleteDatabase() {
// try {
// idCache.clear();
// List<String> names = new ArrayList<String>();
// ResultSet rs = DB.getConnection().getMetaData().getTables(null, null, null, new String[]{"TABLE"});
// while (rs.next()) {
// String name = rs.getString("TABLE_NAME");
// names.add(name);
// }
// disableForeignKeyConstraints();
// for (String name : names) {
// if(Arrays.binarySearch(dontDeleteTheseTables, name) < 0) {
// if (Logger.isTraceEnabled()) {
// Logger.trace("Dropping content of table %s", name);
// }
// DB.execute(getDeleteTableStmt(name) + ";");
// }
// }
// enableForeignKeyConstraints();
// Play.pluginCollection.afterFixtureLoad();
// } catch (Exception e) {
// throw new RuntimeException("Cannot delete all table data : " + e.getMessage(), e);
// }
}
// /**
// * @param name
// * @deprecated use {@link loadModels(String...)} instead
// */
// @Deprecated
// public static void load(String name) {
// loadModels(name);
// }
/**
* Load Model instances from a YAML file and persist them using the underlying persistence mechanism.
* The format of the YAML file is constrained, see the Fixtures manual page
* @param name Name of a YAML file somewhere in the classpath (or conf/)
*/
public static void loadModels(String name) {
// VirtualFile yamlFile = null;
// try {
// for (VirtualFile vf : Play.javaPath) {
// yamlFile = vf.child(name);
// if (yamlFile != null && yamlFile.exists()) {
// break;
// }
// }
// if (yamlFile == null) {
// throw new RuntimeException("Cannot load fixture " + name + ", the file was not found");
// }
//
// String renderedYaml = TemplateLoader.load(yamlFile).render();
//
// Yaml yaml = new Yaml();
// Object o = yaml.load(renderedYaml);
// if (o instanceof LinkedHashMap<?, ?>) {
// @SuppressWarnings("unchecked") LinkedHashMap<Object, Map<?, ?>> objects = (LinkedHashMap<Object, Map<?, ?>>) o;
// for (Object key : objects.keySet()) {
// Matcher matcher = keyPattern.matcher(key.toString().trim());
// if (matcher.matches()) {
// // Type of the object. i.e. models.employee
// String type = matcher.group(1);
// // Id of the entity i.e. nicolas
// String id = matcher.group(2);
// if (!type.startsWith("models.")) {
// type = "models." + type;
// }
//
// // Was the entity already defined?
// if (idCache.containsKey(type + "-" + id)) {
// throw new RuntimeException("Cannot load fixture " + name + ", duplicate id '" + id + "' for type " + type);
// }
//
//
// // Those are the properties that were parsed from the YML file
// final Map<?, ?> entityValues = objects.get(key);
//
// // Prefix is object, why is that?
// final Map<String, String[]> fields = serialize(entityValues, "object");
//
//
// @SuppressWarnings("unchecked")
// Class<Model> cType = (Class<Model>)Play.classloader.loadClass(type);
// final Map<String, String[]> resolvedFields = resolveDependencies(cType, fields);
//
// RootParamNode rootParamNode = ParamNode.convert(resolvedFields);
// // This is kind of hacky. This basically says that if we have an embedded class we should ignore it.
// if (Model.class.isAssignableFrom(cType)) {
//
// Model model = (Model) Binder.bind(rootParamNode, "object", cType, cType, null);
// for(Field f : model.getClass().getFields()) {
// if (f.getType().isAssignableFrom(Map.class)) {
// f.set(model, objects.get(key).get(f.getName()));
// }
// if (f.getType().equals(byte[].class)) {
// f.set(model, objects.get(key).get(f.getName()));
// }
// }
// model._save();
//
// Class<?> tType = cType;
// while (!tType.equals(Object.class)) {
// idCache.put(tType.getName() + "-" + id, Model.Manager.factoryFor(cType).keyValue((Model)model));
// tType = tType.getSuperclass();
// }
// }
// else {
// idCache.put(cType.getName() + "-" + id, Binder.bind(rootParamNode, "object", cType, cType, null));
// }
// }
// }
// }
// // Most persistence engine will need to clear their state
// Play.pluginCollection.afterFixtureLoad();
// } catch (ClassNotFoundException e) {
// throw new RuntimeException("Class " + e.getMessage() + " was not found", e);
// } catch (ScannerException e) {
// throw new YAMLException(e, yamlFile);
// } catch (Throwable e) {
// e.printStackTrace();
// throw new RuntimeException("Cannot load fixture " + name + ": " + e.getMessage(), e);
// }
}
// /**
// * @deprecated use {@link loadModels(String...)} instead
// */
// @Deprecated
// public static void load(String... names) {
// for (String name : names) {
// loadModels(name);
// }
// }
/**
* @see loadModels(String name)
*/
public static void loadModels(String... names) {
for (String name : names) {
loadModels(name);
}
}
// /**
// * @deprecated use {@link loadModels(String...)} instead
// */
// public static void load(List<String> names) {
// loadModels(names);
// }
/**
* @see loadModels(String name)
*/
public static void loadModels(List<String> names) {
String[] tNames = new String[names.size()];
for (int i = 0; i < tNames.length; i++) {
tNames[i] = names.get(i);
}
loadModels(tNames);
}
/**
* Load and parse a plain YAML file and returns the corresponding Java objects.
* The YAML parser used is SnakeYAML (http://code.google.com/p/snakeyaml/)
* @param name Name of a YAML file somewhere in the classpath (or conf/)me
* @return Java objects
*/
public static Object loadYaml(String name) {
return loadYaml(name, Object.class);
}
/**
* Load and parse a plain YAML file and returns the corresponding Java List.
* The YAML parser used is SnakeYAML (http://code.google.com/p/snakeyaml/)
* @param name Name of a YAML file somewhere in the classpath (or conf/)me
* @return Java List representing the YAML data
*/
@SuppressWarnings("unchecked")
public static <T> List<T> loadYamlAsList(String name) {
return (List<T>)loadYaml(name);
}
/**
* Load and parse a plain YAML file and returns the corresponding Java Map.
* The YAML parser used is SnakeYAML (http://code.google.com/p/snakeyaml/)
* @param name Name of a YAML file somewhere in the classpath (or conf/)me
* @return Java Map representing the YAML data
*/
public static Map<?,?> loadYamlAsMap(String name) {
return (Map<?,?>)loadYaml(name);
}
/**
* Load and parse a plain YAML file and returns the corresponding Java Map.
* The YAML parser used is SnakeYAML (http://code.google.com/p/snakeyaml/)
* @param name Name of a YAML file somewhere in the classpath (or conf/)me
* @param clazz the expected class
* @return Object representing the YAML data
*/
@SuppressWarnings("unchecked")
public static <T> T loadYaml(String name, Class<T> clazz) {
Yaml yaml = new Yaml(new CustomClassLoaderConstructor(clazz, Fixtures.class.getClassLoader()));
yaml.setBeanAccess(BeanAccess.FIELD);
return (T)loadYaml(name, yaml);
}
@SuppressWarnings("unchecked")
public static <T> T loadYaml(String name, Yaml yaml) {
// VirtualFile yamlFile = null;
try {
// for (VirtualFile vf : Play.javaPath) {
// yamlFile = vf.child(name);
// if (yamlFile != null && yamlFile.exists()) {
// break;
// }
// }
InputStream is = Fixtures.class.getClass().getResourceAsStream(name);
if (is == null) {
throw new RuntimeException("Cannot load fixture " + name + ", the file was not found");
}
Object o = yaml.load(is);
return (T)o;
} catch (Throwable e) {
throw new RuntimeException("Cannot load fixture " + name + ": " + e.getMessage(), e);
}
}
/**
* Delete a directory recursively
* @param path relative path of the directory to delete
*/
public static void deleteDirectory(String path) {
// try {
// FileUtils.deleteDirectory(Play.getFile(path));
// } catch (IOException ex) {
// throw new UnexpectedException(ex);
// }
}
// Private
// /**
// *
// * TODO: reuse beanutils or MapUtils?
// *
// * @param entityProperties
// * @param prefix
// * @return an hash with the resolved entity name and the corresponding value
// */
// static Map<String, String[]> serialize(Map<?, ?> entityProperties, String prefix) {
//
// if (entityProperties == null) {
// return Collections.emptyMap();
// }
//
// final Map<String, String[]> serialized = new HashMap<String, String[]>();
//
// for (Object key : entityProperties.keySet()) {
//
// Object value = entityProperties.get(key);
// if (value == null) {
// continue;
// }
// if (value instanceof Map<?, ?>) {
// serialized.putAll(serialize((Map<?, ?>) value, prefix + "." + key));
// } else if (value instanceof Date) {
// serialized.put(prefix + "." + key.toString(), new String[]{new SimpleDateFormat(DateBinder.ISO8601).format(((Date) value))});
// } else if (Collection.class.isAssignableFrom(value.getClass())) {
// Collection<?> l = (Collection<?>) value;
// String[] r = new String[l.size()];
// int i = 0;
// for (Object el : l) {
// r[i++] = el.toString();
// }
// serialized.put(prefix + "." + key.toString(), r);
// } else if (value instanceof String && value.toString().matches("<<<\\s*\\{[^}]+}\\s*")) {
// Matcher m = Pattern.compile("<<<\\s*\\{([^}]+)}\\s*").matcher(value.toString());
// m.find();
// String file = m.group(1);
// VirtualFile f = Play.getVirtualFile(file);
// if (f != null && f.exists()) {
// serialized.put(prefix + "." + key.toString(), new String[]{f.contentAsString()});
// }
// } else {
// serialized.put(prefix + "." + key.toString(), new String[]{value.toString()});
// }
// }
//
// return serialized;
// }
// @SuppressWarnings("unchecked")
// /**
// * Resolve dependencies between objects using their keys. For each referenced objects, it sets the foreign key
// */
// static Map<String, String[]> resolveDependencies(Class<Model> type, Map<String, String[]> yml) {
//
// // Contains all the fields (object properties) we should look up
// final Set<Field> fields = new HashSet<Field>();
// final Map<String, String[]> resolvedYml = new HashMap<String, String[]>();
// resolvedYml.putAll(yml);
//
// // Look up the super classes
// Class<?> clazz = type;
// while (!clazz.equals(Object.class)) {
// Collections.addAll(fields, clazz.getDeclaredFields());
// clazz = clazz.getSuperclass();
// }
//
//
// // Iterate through the Entity property list
// // @Embedded are not managed by the JPA plugin
// // This is not the nicest way of doing things.
// //modelFields = Model.Manager.factoryFor(type).listProperties();
// final List<Model.Property> modelFields = new JPAPlugin.JPAModelLoader(type).listProperties();
//
// for (Model.Property field : modelFields) {
// // If we have a relation, get the matching object
// if (field.isRelation) {
// // These are the Ids that were set in the yml file (i.e person(nicolas)-> nicolas is the id)
// final String[] ids = resolvedYml.get("object." + field.name);
// if (ids != null) {
// final String[] resolvedIds = new String[ids.length];
// for (int i = 0; i < ids.length; i++) {
// final String id = field.relationType.getName() + "-" + ids[i];
// if (!idCache.containsKey(id)) {
// throw new RuntimeException("No previous reference found for object of type " + field.name + " with key " + ids[i]);
// }
// // We now get the primary key
// resolvedIds[i] = idCache.get(id).toString();
// }
// // Set the primary keys instead of the object itself.
// // Model.Manager.factoryFor((Class<? extends Model>)field.relationType).keyName() returns the primary key label.
// if (Model.class.isAssignableFrom(field.relationType )) {
// resolvedYml.put("object." + field.name + "." + Model.Manager.factoryFor((Class<? extends Model>)field.relationType).keyName(), resolvedIds);
// } else {
// // Might be an embedded object
// final String id = field.relationType.getName() + "-" + ids[0];
// Object o = idCache.get(id);
// // This can be a composite key
// if (o.getClass().isArray()) {
// for (Object a : (Object[])o) {
// for (Field f : field.relationType.getDeclaredFields()) {
// try {
// resolvedYml.put("object." + field.name + "." + f.getName(), new String[] {f.get(a).toString()});
// } catch(Exception e) {
// // Ignores
// }
// }
// }
// } else {
// for (Field f : field.relationType.getDeclaredFields()) {
// try {
// resolvedYml.put("object." + field.name + "." + f.getName(), new String[] {f.get(o).toString()});
// } catch(Exception e) {
// // Ignores
// }
// }
// }
// }
// }
//
// resolvedYml.remove("object." + field.name);
// }
// }
// // Returns the map containing the ids to load for this object's relation.
// return resolvedYml;
// }
// private static void disableForeignKeyConstraints() {
// if (DBPlugin.url.startsWith("jdbc:oracle:")) {
// DB.execute("begin\n"
// + "for i in (select constraint_name, table_name from user_constraints where constraint_type ='R'\n"
// + "and status = 'ENABLED') LOOP\n"
// + "execute immediate 'alter table '||i.table_name||' disable constraint '||i.constraint_name||'';\n"
// + "end loop;\n"
// + "end;"
// );
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:hsqldb:")) {
// DB.execute("SET REFERENTIAL_INTEGRITY FALSE");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:h2:")) {
// DB.execute("SET REFERENTIAL_INTEGRITY FALSE");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:mysql:")) {
// DB.execute("SET foreign_key_checks = 0;");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:postgresql:")) {
// DB.execute("SET CONSTRAINTS ALL DEFERRED");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:sqlserver:")) {
// Statement exec=null;
//
// try {
// List<String> names = new ArrayList<String>();
// Connection connection = DB.getConnection();
//
// ResultSet rs = connection.getMetaData().getTables(null, null, null, new String[]{"TABLE"});
// while (rs.next()) {
// String name = rs.getString("TABLE_NAME");
// names.add(name);
// }
//
// // Then we disable all foreign keys
// exec = connection.createStatement();
// for (String tableName:names)
// exec.addBatch("ALTER TABLE " + tableName+" NOCHECK CONSTRAINT ALL");
// exec.executeBatch();
// exec.close();
//
// return;
// } catch (SQLException ex) {
// throw new DatabaseException("Error while disabling foreign keys", ex);
// }
// }
//
// // Maybe Log a WARN for unsupported DB ?
// Logger.warn("Fixtures : unable to disable constraints, unsupported database : " + DBPlugin.url);
// }
// private static void enableForeignKeyConstraints() {
// if (DBPlugin.url.startsWith("jdbc:oracle:")) {
// DB.execute("begin\n"
// + "for i in (select constraint_name, table_name from user_constraints where constraint_type ='R'\n"
// + "and status = 'DISABLED') LOOP\n"
// + "execute immediate 'alter table '||i.table_name||' enable constraint '||i.constraint_name||'';\n"
// + "end loop;\n"
// + "end;"
// );
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:hsqldb:")) {
// DB.execute("SET REFERENTIAL_INTEGRITY TRUE");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:h2:")) {
// DB.execute("SET REFERENTIAL_INTEGRITY TRUE");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:mysql:")) {
// DB.execute("SET foreign_key_checks = 1;");
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:postgresql:")) {
// return;
// }
//
// if (DBPlugin.url.startsWith("jdbc:sqlserver:")) {
// Connection connect = null;
// Statement exec=null;
// try {
// connect = DB.getConnection();
// // We must first drop all foreign keys
// ArrayList<String> checkFKCommands=new ArrayList<String>();
// exec=connect.createStatement();
// ResultSet rs=exec.executeQuery("SELECT 'ALTER TABLE ' + TABLE_SCHEMA + '.[' + TABLE_NAME +'] WITH CHECK CHECK CONSTRAINT [' + CONSTRAINT_NAME + ']' FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'");
// while (rs.next())
// {
// checkFKCommands.add(rs.getString(1));
// }
// exec.close();
// exec=null;
//
// // Now we have the drop commands, let's execute them
// exec=connect.createStatement();
// for (String sql:checkFKCommands)
// exec.addBatch(sql);
// exec.executeBatch();
// exec.close();
// } catch (SQLException ex) {
// throw new DatabaseException("Cannot enable foreign keys", ex);
// }
// return;
// }
//
// Logger.warn("Fixtures : unable to enable constraints, unsupported database : " + DBPlugin.url);
// }
// static String getDeleteTableStmt(String name) {
// if (DBPlugin.url.startsWith("jdbc:mysql:") ) {
// return "TRUNCATE TABLE " + name;
// } else if (DBPlugin.url.startsWith("jdbc:postgresql:")) {
// return "TRUNCATE TABLE " + name + " cascade";
// } else if (DBPlugin.url.startsWith("jdbc:oracle:")) {
// return "TRUNCATE TABLE " + name;
// }
// return "DELETE FROM " + name;
// }
}