/* * Copyright 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.jstestdriver; import static com.google.inject.multibindings.Multibinder.newSetBinder; import com.google.inject.Binder; import com.google.inject.Module; import com.google.jstestdriver.hooks.PluginInitializer; import com.google.jstestdriver.util.ManifestLoader; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.LinkedList; import java.util.List; /** * Handles the loading of Plugins from the filesystem. * * @author corysmith */ public class PluginLoader { public static class InitializerModule implements Module { private final Class<PluginInitializer> initializer; public InitializerModule(Class<PluginInitializer> initializer) { this.initializer = initializer; } @Override public void configure(Binder binder) { newSetBinder(binder, PluginInitializer.class).addBinding().to(initializer); } @Override public String toString() { return String.format("InitializerModule [%s]", initializer); } } final ManifestLoader manifestLoader = new ManifestLoader(); /** * For each plugin, the specified jar is loaded, then the specified class is * extracted from the Jar. * * @return a list of {@code Module} */ public List<Module> load(List<Plugin> plugins) { List<Module> modules = new LinkedList<Module>(); for (Plugin plugin : plugins) { // TODO(corysmith): figure out how to test this... try { URLClassLoader urlClassLoader = new URLClassLoader( new URL[] { new URL("jar:file:" + plugin.getPathToJar() + "!/") }, getClass().getClassLoader()); Class<?> module = getPluginMainClass(plugin, urlClassLoader); modules.add(getModuleInstance(plugin, module)); } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } return modules; } // TODO(corysmith): Look for the elegant solution, or // just deprecate leading with a module. private Class<?> getPluginMainClass(Plugin plugin, URLClassLoader urlClassLoader) throws ClassNotFoundException { final String moduleName = plugin.getModuleName(manifestLoader); if (moduleName != null && moduleName.length() > 0) { return Class.forName(moduleName, true, urlClassLoader); } final String initializerName = plugin.getInitializerName(manifestLoader); if (initializerName != null && initializerName.length() > 0) { return Class.forName(initializerName, true, urlClassLoader); } throw new IllegalArgumentException("Cannot determine main class for " + plugin.getName(manifestLoader) + " please see http://code.google.com/p/js-test-driver/wiki/Plugins#mainclass."); } @SuppressWarnings("unchecked") private Module getModuleInstance(Plugin plugin, Class<?> mainClass) { try { if (PluginInitializer.class.isAssignableFrom(mainClass)) { return new InitializerModule((Class<PluginInitializer>)mainClass); } Constructor<Module> argsConstructor = ((Class<Module>)mainClass).getConstructor(List.class); return argsConstructor.newInstance(plugin.getArgs()); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { try { return ((Class<Module>) mainClass).newInstance(); } catch (InstantiationException e1) { throw new RuntimeException(e1); } catch (IllegalAccessException e1) { throw new RuntimeException(e1); } } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } }