Plugin ideas

35 views
Skip to first unread message

Maxence Bernard

unread,
Mar 8, 2009, 4:15:21 PM3/8/09
to mucomma...@googlegroups.com
Hi Alex, all,

As promised, here's a list of ideas for the plugin subsystem, many of which we had with Nicolas when we brainstormed on the subject a while ago. Though most of the topics raised here will need to be addressed by the plugin subsystem one way or the other, everything is open for discussion and by no means set in stone. So feel free to challenge those ideas or suggest better solutions.

1) Plugin files
Plugins are Jar/Zip archives and contain class files and resources. It may be a good idea to use a specific file extension for muCommander plugins like .mpl, instead of just going for the obvious .jar extension. While I don't have a particular reason in mind, I think we may have a use for this down the road.

2) Plugin directory
Plugins could live inside a subdirectory of the preferences directory, e.g. ~/.mucommander/plugins/ . This directory would be scanned by muCommander when it starts up, and the plugins that are there would be added to the classpath dynamically. Note that we already have a custom classloader (AbstractFileClassLoader) that was designed with this purpose in mind.

3) Meta-information / Versioning
Just like the main application, plugins will have to be versioned. The version information could be stored in a MANIFEST.MF file inside the plugin's mpl/jar file (e.g. Plugin-Version: 1.0), along with some meta-information such as a displayable name and description (Plugin-Name, Plugin-Description). We'll also have to address dependencies towards the main application : a plugin built for a specific version of muCommander may or may not work with a more recent version of the application. If we know the app version that the plugin was built for, we can warn the user that the plugin may need to be upgraded and/or choose not to load the plugin. We could add a property to the manifest for that purpose, e.g.  'Built-For-Version: 0.9'.
It would also be nice for plugins to report when a newer version is available for download. We could extend the existing version-checking mechanism that exists in the main application, and allow plugins to specify a URL that points to the XML file that describes the latest plugin version. Again, this could be stored as a manifest property, e.g. Plugin-Version-Check-URL: http://whatever.org/latest.xml.

4) Configuration
Plugins may want to let the user configure certain things. We should offer a standard way for plugins to store and retrieve configuration variables. The com.mucommander.conf API (the one used for the main preferences.xml file) lets multiples configuration instances be used, so we can reuse it and have one configuration instance per plugin. This will leave the main preferences.xml clean of plugin configuration values, and limit chances of conf variable collision.
The plugin configuration file should be located somewhere stable, for instance in a '<plugin-name>_config.xml' file located in the same directory as the plugin's mpl/jar file.
A Configuration instance would be given to the plugin on initialization and would be saved when the application quits. 
Alternatively, the configuration could be stored inside the plugin's mpl/jar file, for instance as a 'config.xml' at the root of the archive, but in that case, special care should be taken to ensure that the configuration does not get lost when the plugin is updated. That means plugins would need to be updated by muCommander, and not manually by overwriting the plugin file or else the configuration would be lost, which may not be ideal.

5) Localization
Plugins that offer GUI should be localized. We should offer a standard way for plugins to do so. The com.mucommander.text.Translator class and dictionary file format (the one used for the localization of the main application) could be used for that. Plugins could have a 'dictionary.txt' entry at the root of the archive that contains the localized entries. A corresponding Translator instance would be automatically be created and passed to the plugin on startup.
Note that the Translator class would have to be modified to let multiple Translator instances exist -- currently it's all static.

6) Draft interface
To sum it all up, below is a proposal for a simple plugin interface (Plugin) and supporting classes (PluginContext and PlugInfo).


What do you think ?

Cheers,
Maxence

------------------------------------------------------------

// The interface to be implemented by plugins 
public interface Plugin {

    // This is where the plugin initializes itself: register actions, filesystems, ... 
    public void init(PluginContext context);

    // This is where the plugin shuts itself down to leave the application as it was before: unregister actions, filesystem, ...
    public void deinit(PluginContext context);
}

// Exposes the different amenities provided to plugins
public interface PluginContext {

    // Allows the plugin to be configured.
    public Configuration getConfiguration();

    // Provides access to the plugin's dictionary.
    public Translator getTranslator();

    // Provides access to the meta-information contained by the plugin's manifest.
    public PluginInfo getPluginInfo();

    // Returns the plugin file, some plugins may have a use for it.
    public AbstractFile getPluginFile();
    
    // Returns the current muCommander version.
    public String getApplicationVersion();
}

// Exposes the meta-information contained by a plugin's MANIFEST.MF file.
public interface PluginInfo {

    // Plugin name, e.g. "Directory synchronizer".
    public String getName();

    // Plugin description, e.g. "Synchronizes two directories, copying files that are not present in both directories".
    public String getDescription();

    // Plugin author, e.g. "John Doe".
    public String getAuthor();

    // Plugin version, e.g. "1.0".
    public String getVersion();

    // muCommander version the plugin was built for, e.g. "0.9".
    public String getBuiltForVersion();

    // Points to the XML file that describes the latest plugin version, e.g. "http://whatever.org/latest.xml"
    public FileURL getVersionCheckURL();
}


A.Yerenkow

unread,
Mar 10, 2009, 5:05:43 AM3/10/09
to mucomma...@googlegroups.com
On 08.03.2009 22:15, Maxence Bernard wrote:
Hi Alex, all,

As promised, here's a list of ideas for the plugin subsystem, many of which we had with Nicolas when we brainstormed on the subject a while ago. Though most of the topics raised here will need to be addressed by the plugin subsystem one way or the other, everything is open for discussion and by no means set in stone. So feel free to challenge those ideas or suggest better solutions.

1) Plugin files
Plugins are Jar/Zip archives and contain class files and resources. It may be a good idea to use a specific file extension for muCommander plugins like .mpl, instead of just going for the obvious .jar extension. While I don't have a particular reason in mind, I think we may have a use for this down the road.

no problem

2) Plugin directory
Plugins could live inside a subdirectory of the preferences directory, e.g. ~/.mucommander/plugins/ . This directory would be scanned by muCommander when it starts up, and the plugins that are there would be added to the classpath dynamically. Note that we already have a custom classloader (AbstractFileClassLoader) that was designed with this purpose in mind.
no problem

3) Meta-information / Versioning
Just like the main application, plugins will have to be versioned. The version information could be stored in a MANIFEST.MF file inside the plugin's mpl/jar file (e.g. Plugin-Version: 1.0), along with some meta-information such as a displayable name and description (Plugin-Name, Plugin-Description). We'll also have to address dependencies towards the main application : a plugin built for a specific version of muCommander may or may not work with a more recent version of the application. If we know the app version that the plugin was built for, we can warn the user that the plugin may need to be upgraded and/or choose not to load the plugin. We could add a property to the manifest for that purpose, e.g.  'Built-For-Version: 0.9'.
1. I'm not quite agree. You know, I'm not believe in proper software version names :) For example, A works good in version 0.B.5, but went broken in 0.B.9 because of some major change.
I believe in API version names :) So, Plugin sub-system get own api version number, and, in future all we have to do - is improve plugin loader for each plugin API.
Example:
Plugin A built for "API: 1.0".
But after fourty years of hard work we came to api 3.0. But we have no reason drop loader for api 1.0 - and old plugins works well.

2. But this system will work proper always, only if PluginContext  or some other interface provide for plugin required actions (register extension, add toolbar, add action, etc) - so plugins itself didn't "talk" to muCommander components.

If you really want that all internal actions plugin need do calling public mucommader API - ok, but sometimes we'll see some old version plugin which wouldnt work in some new build of mu :) This isn't so bad, and my proposed scheme is optional, just for  thoughts.

It would also be nice for plugins to report when a newer version is available for download. We could extend the existing version-checking mechanism that exists in the main application, and allow plugins to specify a URL that points to the XML file that describes the latest plugin version. Again, this could be stored as a manifest property, e.g. Plugin-Version-Check-URL: http://whatever.org/latest.xml.

4) Configuration
Plugins may want to let the user configure certain things. We should offer a standard way for plugins to store and retrieve configuration variables. The com.mucommander.conf API (the one used for the main preferences.xml file) lets multiples configuration instances be used, so we can reuse it and have one configuration instance per plugin. This will leave the main preferences.xml clean of plugin configuration values, and limit chances of conf variable collision.
The plugin configuration file should be located somewhere stable, for instance in a '<plugin-name>_config.xml' file located in the same directory as the plugin's mpl/jar file.
BTW, xml configs is required pretty time for generate; and some FileSystem is known to fail sometime. Do you write configs to the same file or to new file with other name, and after success delete old one, and rename new ? That's a bit safer, as for me :)

A Configuration instance would be given to the plugin on initialization and would be saved when the application quits. 
Alternatively, the configuration could be stored inside the plugin's mpl/jar file, for instance as a 'config.xml' at the root of the archive, but in that case, special care should be taken to ensure that the configuration does not get lost when the plugin is updated. That means plugins would need to be updated by muCommander, and not manually by overwriting the plugin file or else the configuration would be lost, which may not be ideal.

5) Localization
Plugins that offer GUI should be localized. We should offer a standard way for plugins to do so. The com.mucommander.text.Translator class and dictionary file format (the one used for the localization of the main application) could be used for that. Plugins could have a 'dictionary.txt' entry at the root of the archive that contains the localized entries. A corresponding Translator instance would be automatically be created and passed to the plugin on startup.
Note that the Translator class would have to be modified to let multiple Translator instances exist -- currently it's all static.

6) Draft interface
To sum it all up, below is a proposal for a simple plugin interface (Plugin) and supporting classes (PluginContext and PlugInfo).


What do you think ?

Cheers,
Maxence

------------------------------------------------------------

// The interface to be implemented by plugins 
public interface Plugin {

    // This is where the plugin initializes itself: register actions, filesystems, ... 
    public void init(PluginContext context);

    // This is where the plugin shuts itself down to leave the application as it was before: unregister actions, filesystem, ...
    public void deinit(PluginContext context);
}


Do we really need all this different plugin contextes? Maybe one would be sufficient (static), and all parameters (like  public Configuration getConfiguration();) will accept parameter - ID of plugin.
ID could be internal name with version, or integer which plugin will get while registering self; or else;

One more reason why I want to make some wrapper for plugins: Someone write archive plugin for bz2; it'll register; Someone write plugin for multiple archives, bz2 too; What would happen in registration phase? Which plugin will work? Can user make choice what functionality of every plugin need to be turned on, which turned off?

Here's proposed wrapper for plugin calls:

public interface PluginHelper10 {

    //For file plugins
    public void registerExtension(String extension);

    //For file plugins too
    public void registerMimeType(String type);

    //For any plugins
    public void addMenuItem(MenuItem item, String menuPath);

    //For any plugins; Maybe required additional parameter - handler;
    public void addRootItem(String item);

    //For any plugins
    public void addToolbar(Toolbar item, LayoutRecommendation where);

    //For any plugins;
    public void addKeyAction(String command, String keyCombination);

    //For any plugins
    public void addFileInfoTab(----a bit of thinking required );

    //For any plugins
    public void registerSyntaxHighlightingExtension(String extension, String fileTypeId);

    //For any plugins
    public void registerSyntaxHighlightingMimeType(String type, String fileTypeId);

    //For file plugins; protocols - like smb://, ftp://, etc
    public void registerProtocol(String protocol);


}

Something like that :)
Reply all
Reply to author
Forward
0 new messages