Plugin: foo() bar() getValue() setValue() Service: getPlugins(args...) capabilities() -> "pluginid:service" SwingConfigurator: getConfigurationComponent(plugin) capabilities() -> "pluginid:config" OpenRocketSimulationListener extends SimulationListener implements Service, SwingConfigurator: constructor: pluginid = class name getPlugins(): return new this capabilities: pluginid:service, pluginid:config getConfigurationComponent(plugin) plugin.getConfigurationComponent() abstract getConfigurationComponent() Types of plugins: AtmosphericModel - Name -> dropdown - Config component -> dialog window (or button) - stateful, non-dynamic - stored SimulationListener - Name + menu position -> Add extension menu - Config component -> dialog after edit button - stateful, (dynamic?) - stored OptimizationModifier - contains its own name, description, related object - config N/A - stateful, dynamic - not stored OptimizationParameter - name - config N/A - stateful, (dynamic?) - not stored PluginDialogWindow - name + menu position -> Menu - stateful, non-dynamic - not stored Motor - Name -> Config tab - Config component -> tab contents ???? - or a separate configuration interface? - stored Name is common - out, instead have name separately in plugin interfaces? Menu position used twice - out Leave common configuration out -> :config supported by those that make sense -> may have separate interface from SwingConfigurator (e.g. SwingMotorConfigurator) Motor -> :loader separately? for injecting placeholders or store data and call loaders later 100.0 Gold bulk 16000 100.0 Gold bulk 16000