Plugin system
This commit is contained in:
parent
4141b478f7
commit
8c0c9bb10d
@ -33,5 +33,7 @@
|
||||
<classpathentry kind="lib" path="lib/guice-multibindings-3.0.jar"/>
|
||||
<classpathentry kind="lib" path="lib/javax.inject.jar"/>
|
||||
<classpathentry kind="lib" path="lib/aopalliance.jar"/>
|
||||
<classpathentry kind="lib" path="lib-test/test-plugin.jar"/>
|
||||
<classpathentry kind="lib" path="lib/annotation-detector-3.0.2-SNAPSHOT.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
|
@ -101,6 +101,7 @@
|
||||
<zipfileset src="${lib.dir}/miglayout15-swing.jar"/>
|
||||
<zipfileset src="${lib.dir}/opencsv-2.3.jar"/>
|
||||
<zipfileset src="${lib.dir}/OrangeExtensions-1.2.jar"/>
|
||||
<zipfileset src="${lib.dir}/annotation-detector-3.0.2-SNAPSHOT.jar"/>
|
||||
|
||||
|
||||
<!-- JOGL libraries need to be jar-in-jar -->
|
||||
|
BIN
core/lib-test/test-plugin.jar
Normal file
BIN
core/lib-test/test-plugin.jar
Normal file
Binary file not shown.
BIN
core/lib/annotation-detector-3.0.2-SNAPSHOT.jar
Normal file
BIN
core/lib/annotation-detector-3.0.2-SNAPSHOT.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
16
core/src/net/sf/openrocket/plugin/AnnotationFinder.java
Normal file
16
core/src/net/sf/openrocket/plugin/AnnotationFinder.java
Normal file
@ -0,0 +1,16 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface for finding annotated classes from the class path.
|
||||
*/
|
||||
public interface AnnotationFinder {
|
||||
|
||||
/**
|
||||
* Return a list of all types (classes and interfaces) that are annotated
|
||||
* with the provided annotation.
|
||||
*/
|
||||
public List<Class<?>> findAnnotatedTypes(Class<?> annotation);
|
||||
|
||||
}
|
92
core/src/net/sf/openrocket/plugin/AnnotationFinderImpl.java
Normal file
92
core/src/net/sf/openrocket/plugin/AnnotationFinderImpl.java
Normal file
@ -0,0 +1,92 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.JarUtil;
|
||||
import eu.infomas.annotation.AnnotationDetector;
|
||||
import eu.infomas.annotation.AnnotationDetector.TypeReporter;
|
||||
|
||||
/**
|
||||
* An AnnotationFinder that uses annotation-detector library to scan
|
||||
* the class path. Compatible with the JIJ loader.
|
||||
*/
|
||||
public class AnnotationFinderImpl implements AnnotationFinder {
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public List<Class<?>> findAnnotatedTypes(Class<?> annotation) {
|
||||
final List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
|
||||
TypeReporter reporter = new ListReporter(classes);
|
||||
final AnnotationDetector cf = new AnnotationDetector(reporter);
|
||||
try {
|
||||
ClassLoader loader = this.getClass().getClassLoader();
|
||||
if (loader instanceof URLClassLoader) {
|
||||
|
||||
/*
|
||||
* In case of URLClassLoader (which may be our own instantiation)
|
||||
* use the URLs from there, as java.class.path may not be up-to-date.
|
||||
*/
|
||||
|
||||
URLClassLoader urlClassLoader = (URLClassLoader) loader;
|
||||
URL[] urls = urlClassLoader.getURLs();
|
||||
|
||||
List<File> files = new ArrayList<File>();
|
||||
for (URL url : urls) {
|
||||
if (url.getProtocol() == "file") {
|
||||
files.add(JarUtil.urlToFile(url));
|
||||
}
|
||||
}
|
||||
|
||||
cf.detect(files.toArray(new File[0]));
|
||||
} else {
|
||||
|
||||
/*
|
||||
* If not using a URLClassLoader, just do the default.
|
||||
*/
|
||||
cf.detect();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new BugException("Unable to search class path", e);
|
||||
}
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
private static class ListReporter implements TypeReporter {
|
||||
private final List<Class<?>> classes;
|
||||
private final Set<String> names = new HashSet<String>();
|
||||
|
||||
public ListReporter(List<Class<?>> classes) {
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<? extends Annotation>[] annotations() {
|
||||
return new Class[] { Plugin.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportTypeAnnotation(Class<? extends Annotation> annotation, String className) {
|
||||
if (names.add(className)) {
|
||||
try {
|
||||
classes.add(this.getClass().getClassLoader().loadClass(className));
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JIJ {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String cp = System.getProperty("java.class.path");
|
||||
String[] cps = cp.split(File.pathSeparator);
|
||||
|
||||
URL[] urls = new URL[cps.length + 1];
|
||||
for (int i = 0; i < cps.length; i++) {
|
||||
urls[i] = new File(cps[i]).toURI().toURL();
|
||||
}
|
||||
urls[cps.length] = new File("/home/sampo/Projects/OpenRocket/core/example.jar").toURI().toURL();
|
||||
|
||||
System.out.println("Classpath: " + Arrays.toString(urls));
|
||||
|
||||
URLClassLoader loader = new URLClassLoader(urls, null);
|
||||
Class<?> c = loader.loadClass("net.sf.openrocket.plugin.Test");
|
||||
Method m = c.getMethod("main", args.getClass());
|
||||
m.invoke(null, (Object) args);
|
||||
}
|
||||
|
||||
}
|
@ -6,8 +6,10 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that defines an interface to be a plugin interface.
|
||||
* Plugin interfaces are automatically discovered from plugin JARs and
|
||||
* Annotation that defines an interface to be a plugin interface and
|
||||
* classes as plugin implementations.
|
||||
* <p>
|
||||
* Plugin interfaces are automatically discovered from the classpath and
|
||||
* registered as plugins in Guice.
|
||||
*
|
||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||
|
@ -1,14 +1,9 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.multibindings.Multibinder;
|
||||
@ -21,63 +16,46 @@ import com.google.inject.multibindings.Multibinder;
|
||||
*/
|
||||
public class PluginModule extends AbstractModule {
|
||||
|
||||
private final List<File> jars;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private Map<Class<?>, Multibinder<?>> binders = new HashMap<Class<?>, Multibinder<?>>();
|
||||
|
||||
|
||||
/**
|
||||
* Sole constructor.
|
||||
*
|
||||
* @param jars the JAR files to search for plugins
|
||||
* @param classLoader the class loader used to load classes from the JAR files
|
||||
*/
|
||||
public PluginModule(List<File> jars, ClassLoader classLoader) {
|
||||
this.jars = jars;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
for (File jar : jars) {
|
||||
List<String> classNames = readClassNames(jar);
|
||||
for (String className : classNames) {
|
||||
checkForPlugin(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AnnotationFinder finder = new AnnotationFinderImpl();
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void checkForPlugin(String className) {
|
||||
try {
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
List<Class<?>> classes = finder.findAnnotatedTypes(Plugin.class);
|
||||
List<Class<?>> interfaces = new ArrayList<Class<?>>();
|
||||
List<Class<?>> unusedInterfaces;
|
||||
|
||||
|
||||
// Find plugin interfaces
|
||||
for (Class<?> c : classes) {
|
||||
if (c.isInterface()) {
|
||||
interfaces.add(c);
|
||||
}
|
||||
}
|
||||
unusedInterfaces = new ArrayList<Class<?>>(interfaces);
|
||||
|
||||
// Find plugin implementations
|
||||
for (Class<?> c : classes) {
|
||||
if (c.isInterface())
|
||||
continue;
|
||||
|
||||
Class<?> c = classLoader.loadClass(className);
|
||||
for (Class<?> intf : c.getInterfaces()) {
|
||||
System.out.println("Testing class " + c + " interface " + intf);
|
||||
|
||||
if (isPluginInterface(intf)) {
|
||||
System.out.println("BINDING");
|
||||
if (interfaces.contains(intf)) {
|
||||
// Ugly hack to enable dynamic binding... Can this be done type-safely?
|
||||
Multibinder<Object> binder = (Multibinder<Object>) findBinder(intf);
|
||||
binder.addBinding().to(c);
|
||||
unusedInterfaces.remove(intf);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not load class " + className + ": " + e);
|
||||
}
|
||||
|
||||
// TODO: Unused plugin interfaces should be bound to an empty set - how?
|
||||
}
|
||||
|
||||
|
||||
private boolean isPluginInterface(Class<?> intf) {
|
||||
return intf.isAnnotationPresent(Plugin.class);
|
||||
}
|
||||
|
||||
|
||||
private Multibinder<?> findBinder(Class<?> intf) {
|
||||
Multibinder<?> binder = binders.get(intf);
|
||||
if (binder == null) {
|
||||
@ -87,36 +65,4 @@ public class PluginModule extends AbstractModule {
|
||||
return binder;
|
||||
}
|
||||
|
||||
|
||||
private List<String> readClassNames(File jar) {
|
||||
List<String> classNames = new ArrayList<String>();
|
||||
|
||||
JarFile file = null;
|
||||
try {
|
||||
file = new JarFile(jar);
|
||||
Enumeration<JarEntry> entries = file.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if (name.toLowerCase().endsWith(".class") && !name.contains("$")) {
|
||||
name = name.substring(0, name.length() - 6);
|
||||
name = name.replace('/', '.');
|
||||
classNames.add(name);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading JAR file " + jar);
|
||||
} finally {
|
||||
if (file != null) {
|
||||
try {
|
||||
file.close();
|
||||
} catch (IOException e) {
|
||||
// Curse all checked exceptions...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return classNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
public class Test {
|
||||
|
||||
@Inject
|
||||
private Set<ExamplePlugin> impls;
|
||||
|
||||
|
||||
public void run() {
|
||||
System.out.println("Plugin count: " + impls.size());
|
||||
for (ExamplePlugin i : impls) {
|
||||
i.doit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws MalformedURLException {
|
||||
// Properties p = System.getProperties();
|
||||
// Enumeration<Object> e = p.keys();
|
||||
// while (e.hasMoreElements()) {
|
||||
// Object key = e.nextElement();
|
||||
// Object value = p.get(key);
|
||||
// System.out.println(key + " = " + value);
|
||||
// }
|
||||
|
||||
List<File> jars = Arrays.asList(new File("/home/sampo/Projects/OpenRocket/core/example.jar"));
|
||||
URL[] urls = { new File("/home/sampo/Projects/OpenRocket/core/example.jar").toURI().toURL() };
|
||||
ClassLoader classLoader = new URLClassLoader(urls);
|
||||
|
||||
classLoader = Test.class.getClassLoader();
|
||||
|
||||
Injector injector = Guice.createInjector(new PluginModule(jars, classLoader));
|
||||
injector.getInstance(Test.class).run();
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@ import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.logging.LogLevel;
|
||||
import net.sf.openrocket.logging.LogLevelBufferLogger;
|
||||
import net.sf.openrocket.logging.PrintStreamLogger;
|
||||
import net.sf.openrocket.plugin.PluginHelper;
|
||||
import net.sf.openrocket.plugin.PluginModule;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
@ -135,26 +134,27 @@ public class GuiceStartup {
|
||||
" " + LOG_STDERR_PROPERTY + "=" + System.getProperty(LOG_STDERR_PROPERTY) + ")";
|
||||
log.info(str);
|
||||
|
||||
|
||||
|
||||
|
||||
//Replace System.err with a PrintStream that logs lines to DEBUG, or VBOSE if they are indented.
|
||||
//If debug info is not being output to the console then the data is both logged and written to
|
||||
//stderr.
|
||||
final boolean writeToStderr = !( printer.getOutput(LogLevel.DEBUG) == System.out || printer.getOutput(LogLevel.DEBUG) == System.err);
|
||||
final PrintStream stdErr = System.err;
|
||||
final boolean writeToStderr = !(printer.getOutput(LogLevel.DEBUG) == System.out || printer.getOutput(LogLevel.DEBUG) == System.err);
|
||||
final PrintStream stdErr = System.err;
|
||||
System.setErr(new PrintStream(new OutputStream() {
|
||||
StringBuilder currentLine = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public synchronized void write(int b) throws IOException {
|
||||
if ( writeToStderr ){
|
||||
if (writeToStderr) {
|
||||
//Write to real stderr
|
||||
stdErr.write(b);
|
||||
}
|
||||
if (b == '\r' || b == '\n') {
|
||||
//Line is complete, log it
|
||||
if (currentLine.toString().trim().length() > 0){
|
||||
if (currentLine.toString().trim().length() > 0) {
|
||||
String s = currentLine.toString();
|
||||
if ( Character.isWhitespace(s.charAt(0))){
|
||||
if (Character.isWhitespace(s.charAt(0))) {
|
||||
log.verbose(currentLine.toString());
|
||||
} else {
|
||||
log.debug(currentLine.toString());
|
||||
@ -247,7 +247,7 @@ public class GuiceStartup {
|
||||
|
||||
private static Injector initializeGuice() {
|
||||
Module applicationModule = new ApplicationModule();
|
||||
Module pluginModule = new PluginModule(PluginHelper.getPluginJars(), GuiceStartup.class.getClassLoader());
|
||||
Module pluginModule = new PluginModule();
|
||||
|
||||
return Guice.createInjector(applicationModule, pluginModule);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package net.sf.openrocket.database;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -14,31 +18,31 @@ import net.sf.openrocket.util.Coordinate;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ThrustCurveMotorSetTest {
|
||||
|
||||
|
||||
|
||||
|
||||
private static final ThrustCurveMotor motor1 = new ThrustCurveMotor(
|
||||
Manufacturer.getManufacturer("A"),
|
||||
"F12X", "Desc", Motor.Type.UNKNOWN, new double[] { },
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] {0, 1, 0},
|
||||
new Coordinate[] {Coordinate.NUL, Coordinate.NUL, Coordinate.NUL}, "digestA");
|
||||
"F12X", "Desc", Motor.Type.UNKNOWN, new double[] {},
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] { 0, 1, 0 },
|
||||
new Coordinate[] { Coordinate.NUL, Coordinate.NUL, Coordinate.NUL }, "digestA");
|
||||
|
||||
private static final ThrustCurveMotor motor2 = new ThrustCurveMotor(
|
||||
Manufacturer.getManufacturer("A"),
|
||||
"F12H", "Desc", Motor.Type.SINGLE, new double[] { 5 },
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] {0, 1, 0},
|
||||
new Coordinate[] {Coordinate.NUL, Coordinate.NUL, Coordinate.NUL}, "digestB");
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] { 0, 1, 0 },
|
||||
new Coordinate[] { Coordinate.NUL, Coordinate.NUL, Coordinate.NUL }, "digestB");
|
||||
|
||||
private static final ThrustCurveMotor motor3 = new ThrustCurveMotor(
|
||||
Manufacturer.getManufacturer("A"),
|
||||
"F12", "Desc", Motor.Type.UNKNOWN, new double[] { 0, Motor.PLUGGED },
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] {0, 2, 0},
|
||||
new Coordinate[] {Coordinate.NUL, Coordinate.NUL, Coordinate.NUL}, "digestC");
|
||||
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] { 0, 2, 0 },
|
||||
new Coordinate[] { Coordinate.NUL, Coordinate.NUL, Coordinate.NUL }, "digestC");
|
||||
|
||||
private static final ThrustCurveMotor motor4 = new ThrustCurveMotor(
|
||||
Manufacturer.getManufacturer("A"),
|
||||
"F12", "Desc", Motor.Type.HYBRID, new double[] { 0 },
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] {0, 2, 0},
|
||||
new Coordinate[] {Coordinate.NUL, Coordinate.NUL, Coordinate.NUL}, "digestD");
|
||||
0.024, 0.07, new double[] { 0, 1, 2 }, new double[] { 0, 2, 0 },
|
||||
new Coordinate[] { Coordinate.NUL, Coordinate.NUL, Coordinate.NUL }, "digestD");
|
||||
|
||||
|
||||
@Test
|
||||
@ -50,7 +54,7 @@ public class ThrustCurveMotorSetTest {
|
||||
assertEquals("J115", ThrustCurveMotorSet.simplifyDesignation("384-J115"));
|
||||
assertEquals("A2", ThrustCurveMotorSet.simplifyDesignation("A2T"));
|
||||
assertEquals("1/2A2T", ThrustCurveMotorSet.simplifyDesignation("1/2A2T"));
|
||||
assertEquals("Micro Maxx II", ThrustCurveMotorSet.simplifyDesignation("Micro Maxx II"));
|
||||
assertEquals("MicroMaxxII", ThrustCurveMotorSet.simplifyDesignation("Micro Maxx II"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
9
core/test/net/sf/openrocket/plugin/Example2Plugin.java
Normal file
9
core/test/net/sf/openrocket/plugin/Example2Plugin.java
Normal file
@ -0,0 +1,9 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
/**
|
||||
* Example plugin interface for testing purposes.
|
||||
*/
|
||||
@Plugin
|
||||
public interface Example2Plugin {
|
||||
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
/**
|
||||
* Example plugin for testing purposes.
|
||||
*/
|
||||
@Plugin
|
||||
public interface ExamplePlugin {
|
||||
|
||||
public void doit();
|
||||
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
/**
|
||||
* ExamplePlugin implementation for testing purposes.
|
||||
*/
|
||||
@Plugin
|
||||
public class ExamplePluginImpl implements ExamplePlugin {
|
||||
|
||||
@Override
|
||||
public void doit() {
|
||||
System.out.println("ExamplePluginImpl.doit() called");
|
||||
}
|
||||
|
||||
}
|
10
core/test/net/sf/openrocket/plugin/MultiPluginImpl.java
Normal file
10
core/test/net/sf/openrocket/plugin/MultiPluginImpl.java
Normal file
@ -0,0 +1,10 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
/**
|
||||
* Plugin that implements both ExamplePlugin and Example2Plugin
|
||||
* for testing purposes.
|
||||
*/
|
||||
@Plugin
|
||||
public class MultiPluginImpl implements ExamplePlugin, Example2Plugin {
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
/**
|
||||
* An implementation of ExamplePlugin that is not annotated with @Plugin
|
||||
* for testing purposes. This should not be injected into the test class.
|
||||
*/
|
||||
public class NotAnExamplePluginImpl implements ExamplePlugin {
|
||||
|
||||
}
|
26
core/test/net/sf/openrocket/plugin/PluginTest.java
Normal file
26
core/test/net/sf/openrocket/plugin/PluginTest.java
Normal file
@ -0,0 +1,26 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* Test the plugin loading system using Guice.
|
||||
*
|
||||
* This is more of an integration than a unit test. It uses the
|
||||
* PluginModule to load a Guice injector, and then verifies that it
|
||||
* has found the appropriate plugins.
|
||||
*/
|
||||
public class PluginTest {
|
||||
|
||||
@Test
|
||||
public void testPluginModule() {
|
||||
|
||||
Injector injector = Guice.createInjector(new PluginModule());
|
||||
PluginTester tester = injector.getInstance(PluginTester.class);
|
||||
tester.testPlugins();
|
||||
|
||||
}
|
||||
|
||||
}
|
38
core/test/net/sf/openrocket/plugin/PluginTester.java
Normal file
38
core/test/net/sf/openrocket/plugin/PluginTester.java
Normal file
@ -0,0 +1,38 @@
|
||||
package net.sf.openrocket.plugin;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class PluginTester {
|
||||
|
||||
@Inject
|
||||
private Set<ExamplePlugin> examplePlugins;
|
||||
@Inject
|
||||
private Set<Example2Plugin> example2Plugins;
|
||||
|
||||
|
||||
public void testPlugins() {
|
||||
assertContains(examplePlugins, ExamplePluginImpl.class, MultiPluginImpl.class, JarPluginImpl.class);
|
||||
assertContains(example2Plugins, MultiPluginImpl.class);
|
||||
}
|
||||
|
||||
|
||||
private void assertContains(Set<?> set, Class<?>... classes) {
|
||||
assertEquals(classes.length, set.size());
|
||||
|
||||
List<Class<?>> list = new ArrayList<Class<?>>(Arrays.asList(classes));
|
||||
for (Object o : set) {
|
||||
Class<?> c = o.getClass();
|
||||
assertTrue(list.contains(c));
|
||||
list.remove(c);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
package net.sf.openrocket.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -53,7 +57,7 @@ public class TestMutex {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private volatile int testState = 0;
|
||||
private volatile String failure = null;
|
||||
|
||||
@ -106,6 +110,7 @@ public class TestMutex {
|
||||
testState = 6;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
failure = "Exception occurred in thread: " + e;
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user