diff --git a/core/.classpath b/core/.classpath
index fb297f54e..5a8600e02 100644
--- a/core/.classpath
+++ b/core/.classpath
@@ -30,5 +30,9 @@
+
+
+
+
diff --git a/core/example.jar b/core/example.jar
new file mode 100644
index 000000000..bf2b50c97
Binary files /dev/null and b/core/example.jar differ
diff --git a/core/lib/aopalliance.jar b/core/lib/aopalliance.jar
new file mode 100644
index 000000000..578b1a0c3
Binary files /dev/null and b/core/lib/aopalliance.jar differ
diff --git a/core/lib/guice-3.0.jar b/core/lib/guice-3.0.jar
new file mode 100644
index 000000000..76be5e0dd
Binary files /dev/null and b/core/lib/guice-3.0.jar differ
diff --git a/core/lib/guice-multibindings-3.0.jar b/core/lib/guice-multibindings-3.0.jar
new file mode 100644
index 000000000..f2ec19a2a
Binary files /dev/null and b/core/lib/guice-multibindings-3.0.jar differ
diff --git a/core/lib/javax.inject.jar b/core/lib/javax.inject.jar
new file mode 100644
index 000000000..a9dfb86d2
Binary files /dev/null and b/core/lib/javax.inject.jar differ
diff --git a/core/src/net/sf/openrocket/gui/plugin/DoSomethingPlugin.java b/core/src/net/sf/openrocket/gui/plugin/DoSomethingPlugin.java
deleted file mode 100644
index d238c4eb6..000000000
--- a/core/src/net/sf/openrocket/gui/plugin/DoSomethingPlugin.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.sf.openrocket.gui.plugin;
-
-import javax.swing.Action;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.gui.main.BasicFrame;
-
-public class DoSomethingPlugin extends OpenRocketSwingMenuPlugin {
-
- @Override
- public Action getAction(BasicFrame frame, OpenRocketDocument document) {
- // TODO Auto-generated method stub
- return null;
- }
-
-}
diff --git a/core/src/net/sf/openrocket/gui/plugin/OpenRocketSwingMenuPlugin.java b/core/src/net/sf/openrocket/gui/plugin/OpenRocketSwingMenuPlugin.java
deleted file mode 100644
index e76e64a20..000000000
--- a/core/src/net/sf/openrocket/gui/plugin/OpenRocketSwingMenuPlugin.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.sf.openrocket.gui.plugin;
-
-import java.util.List;
-
-import net.sf.openrocket.plugin.framework.Service;
-
-public abstract class OpenRocketSwingMenuPlugin implements Service, SwingMenuPlugin {
-
- @Override
- public String[] getMenuPosition() {
- // TODO Auto-generated method stub
- return null;
- }
-
-
- @Override
- public List getPlugins(Class type, Object... args) {
- // TODO Auto-generated method stub
- return null;
- }
-
-}
diff --git a/core/src/net/sf/openrocket/gui/plugin/SwingMenuPlugin.java b/core/src/net/sf/openrocket/gui/plugin/SwingMenuPlugin.java
deleted file mode 100644
index e27b78ac6..000000000
--- a/core/src/net/sf/openrocket/gui/plugin/SwingMenuPlugin.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.sf.openrocket.gui.plugin;
-
-import javax.swing.Action;
-
-import net.sf.openrocket.document.OpenRocketDocument;
-import net.sf.openrocket.gui.main.BasicFrame;
-
-/**
- * A plugin that provides a menu item to the Swing GUI menus.
- * This may open a dialog window or perform some other action on
- * the current document.
- *
- * During plugin discovery, the BasicFrame and OpenRocketDocument
- * objects are passed to the plugin.
- *
- * @author Sampo Niskanen
- */
-public interface SwingMenuPlugin {
-
- /**
- * Return the menu position where the action is placed.
- * The first string in the array indicates the menu to place
- * the item in, the second is the sub-menu, the third is the
- * sub-sub-menu etc.
- *
- * The strings are translated menu names.
- *
- * @return the menu position for the action
- */
- public String[] getMenuPosition();
-
- /**
- * Return the Action that the menu item performs. This contains
- * the menu item text and may contain an icon.
- *
- * @return the action to perform on the menu item.
- */
- public Action getAction(BasicFrame frame, OpenRocketDocument document);
-
-}
diff --git a/core/src/net/sf/openrocket/plugin/Configurable.java b/core/src/net/sf/openrocket/plugin/Configurable.java
deleted file mode 100644
index b8ebf6e2c..000000000
--- a/core/src/net/sf/openrocket/plugin/Configurable.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.sf.openrocket.plugin;
-
-public interface Configurable {
-
-
- /**
- * Return the plugin ID. This is a text string uniquely identifying this plugin.
- * The recommended format is similar to the fully-qualified class name of the
- * plugin, though a shorter format starting with the developer's domain name
- * is also possible for future compatibility.
- *
- * @return the plugin ID
- */
- public String getPluginID();
-
- /**
- * Test whether this plugin provides functionality corresponding to the specified
- * plugin ID. This provides backwards compatibility if the plugin ID should change.
- *
- * @param pluginID the plugin ID to test
- * @return whether this plugin provides the requested functionality
- */
- public boolean isCompatible(String pluginID);
-
- public void loadFromXML(Object... objects);
-
- public void saveToXML(Object... objects);
-
-}
diff --git a/core/src/net/sf/openrocket/plugin/CopyOfExamplePluginImpl.java b/core/src/net/sf/openrocket/plugin/CopyOfExamplePluginImpl.java
new file mode 100644
index 000000000..8abe0020d
--- /dev/null
+++ b/core/src/net/sf/openrocket/plugin/CopyOfExamplePluginImpl.java
@@ -0,0 +1,10 @@
+package net.sf.openrocket.plugin;
+
+public class CopyOfExamplePluginImpl implements ExamplePlugin {
+
+ @Override
+ public void doit() {
+ System.out.println("CopyOfExamplePluginImpl.doit() called");
+ }
+
+}
diff --git a/core/src/net/sf/openrocket/plugin/ExamplePlugin.java b/core/src/net/sf/openrocket/plugin/ExamplePlugin.java
new file mode 100644
index 000000000..b69950e80
--- /dev/null
+++ b/core/src/net/sf/openrocket/plugin/ExamplePlugin.java
@@ -0,0 +1,8 @@
+package net.sf.openrocket.plugin;
+
+@Plugin
+public interface ExamplePlugin {
+
+ public void doit();
+
+}
diff --git a/core/src/net/sf/openrocket/plugin/ExamplePluginImpl.java b/core/src/net/sf/openrocket/plugin/ExamplePluginImpl.java
new file mode 100644
index 000000000..05a0aeb5b
--- /dev/null
+++ b/core/src/net/sf/openrocket/plugin/ExamplePluginImpl.java
@@ -0,0 +1,10 @@
+package net.sf.openrocket.plugin;
+
+public class ExamplePluginImpl implements ExamplePlugin {
+
+ @Override
+ public void doit() {
+ System.out.println("ExamplePluginImpl.doit() called");
+ }
+
+}
diff --git a/core/src/net/sf/openrocket/plugin/Plugin.java b/core/src/net/sf/openrocket/plugin/Plugin.java
new file mode 100644
index 000000000..de8eb4cdd
--- /dev/null
+++ b/core/src/net/sf/openrocket/plugin/Plugin.java
@@ -0,0 +1,19 @@
+package net.sf.openrocket.plugin;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+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
+ * registered as plugins in Guice.
+ *
+ * @author Sampo Niskanen
+ */
+@Target(value = { ElementType.TYPE })
+@Retention(value = RetentionPolicy.RUNTIME)
+public @interface Plugin {
+
+}
diff --git a/core/src/net/sf/openrocket/plugin/PluginModule.java b/core/src/net/sf/openrocket/plugin/PluginModule.java
new file mode 100644
index 000000000..88daae2e0
--- /dev/null
+++ b/core/src/net/sf/openrocket/plugin/PluginModule.java
@@ -0,0 +1,122 @@
+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;
+
+/**
+ * Guice module definition that searches for plugins in a list of provided
+ * JAR files and registers each found plugin to the corresponding plugin interface.
+ *
+ * @author Sampo Niskanen
+ */
+public class PluginModule extends AbstractModule {
+
+ private final File[] jars;
+ private final ClassLoader classLoader;
+
+ private Map, Multibinder>> binders = new HashMap, 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(File[] jars, ClassLoader classLoader) {
+ this.jars = jars.clone();
+ this.classLoader = classLoader;
+ }
+
+
+ @Override
+ protected void configure() {
+ for (File jar : jars) {
+ List classNames = readClassNames(jar);
+ for (String className : classNames) {
+ checkForPlugin(className);
+ }
+ }
+ }
+
+
+
+ @SuppressWarnings("unchecked")
+ private void checkForPlugin(String className) {
+ try {
+
+ 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");
+ // Ugly hack to enable dynamic binding... Can this be done type-safely?
+ Multibinder