package liquibase.test; import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collections; import java.util.List; import liquibase.util.SystemUtils; /** * Class Loader for loading JDBC drivers in unit tests. It was orginally not a singleton, but * would instead take the directory of the particular driver you wanted and create a new * class loader with just those jar files. Unfortunatley, the class loaders were never cleaned up by * the JVM even though there were no references to them and the permgen space requirements would skyrocket. * It was re-implemented as a singleton to solve that problem. If we ever need to make different unit tests that use * the same driver class name but different jars (versions) we will need to re-address the issue. */ public class JUnitJDBCDriverClassLoader extends URLClassLoader { private static final JUnitJDBCDriverClassLoader instance = new JUnitJDBCDriverClassLoader(); private JUnitJDBCDriverClassLoader() { super(getDriverClasspath()); } public static JUnitJDBCDriverClassLoader getInstance() { return instance; } private static URL[] getDriverClasspath() { try { List<URL> urls = new ArrayList<URL>(); addUrlsFromPath(urls, "jdbc-drivers/all"); //Add drivers by Java version. Only jars from the biggest matching version are taken if(SystemUtils.isJavaVersionAtLeast(1.6f)) { addUrlsFromPath(urls, "jdbc-drivers/byJavaVersion/1.6"); } else if(SystemUtils.isJavaVersionAtLeast(1.5f)) { addUrlsFromPath(urls, "jdbc-drivers/byJavaVersion/1.5"); } return urls.toArray(new URL[urls.size()]); } catch (Exception e) { throw new RuntimeException(e); } } private static void addUrlsFromPath(List<URL> addTo,String path) throws Exception{ File thisClassFile = new File(new URI(Thread.currentThread().getContextClassLoader().getResource("liquibase/test/JUnitJDBCDriverClassLoader.class") .toExternalForm())); File jdbcLib = new File(thisClassFile.getParentFile().getParentFile().getParentFile(),path); if (!jdbcLib.exists()) { throw new RuntimeException("JDBC driver directory "+jdbcLib.getAbsolutePath()+" does not exist"); } File[] files = jdbcLib.listFiles(new FileFilter() { public boolean accept(File pathname) { return pathname.isDirectory(); } }); if(files == null) { files = new File[]{}; } for (File driverDir : files) { File[] driverJars = driverDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith("jar"); } }); for (File jar : driverJars) { addTo.add(jar.toURL()); } } } }