Plug-in Developer Manual

This manual describes first how to create plug-ins for HIPE. In most cases, you will only have to read the relevant sections from the Quick Guide chapter. The final chapter describes the mechanism that HIPE component developers can use to become aware of plug-ins. For more information on the plug-in framework, see the Design document. User documentation on plugins is available on this page.

Plug-ins are available in HIPE starting version 5.0.

Quick Guide: Creating Simple Plug-ins

Plug-ins can be created to do lots of fancy things, but most of the time people will want to use them to share some pools, some Jython scripts, and/or possible some Java code. These standard cases are described in this chapter. One case (pools, Jython or Java) does not exclude the other; combining the steps from the different cases described here will work.

General procedure for creating a plug-in

In general, a plug-in is just a JAR or a ZIP-file with a name that follows the pattern: [name]_[version].[extension]. The name can be any string (it is allowed to contain underscores). The name is followed by an underscore. The version is a series of integers separated by dots: "1", "2.0", "2.3.4.5", etc, are allowed as the version. The extension should be "jar" or "zip" (lowercase). An example of a plug-in filename is myplugin_0.1.jar.

On Unix you can use the jar facility from the bin directory of the JDK to create jar-files. I recommend to cd to the directory where you have prepared your plug-in and create the jar-file in a different place, as follows:

> jar cvf $HOME/myplugin_0.1.jar *

The options to jar we used here are cvf: c for "create", v for "verbose" and f fore filename.

If you use Windows, you can use any compression program, as long as it a can write "zip" or "jar" file format. For example, I like PeaZip.

All components of a plug-in are optional: Even an empty JAR-file is a valid plug-in that you can install perfectly well. Only, it doesn't do anything of course. For that, see the next sections.

How to create a plug-in with some pools

Plug-ins can contain LocalStores. To create a plug-in with one or more LocalStores, create a directory called pools, copy the LocalStores in there and create a jar or zip with the pools directory.

Unix shell example: Assuming your LocalStores are in the default directory, $HOME/.hcss/lstore and you want to create a plug-in with poolA and poolB:

> mkdir pools
> cp -r $HOME/.hcss/lstore/poolA
> cp -r $HOME/.hcss/lstore/poolB
> jar cf $HOME/myplugin_0.1.jar pools

You probably will want to name your plug-in differently than "myplugin" though -- give it a name that says something about its contents. To change the name of the plug-in, you can just rename the file.

When the plug-in is installed, the pools will appear in the Data Access section of the preferences (see Edit --> Preferences).

Tip, idea You can also share LocalStores using the Export View in HIPE. This will give you a compressed file with the pool, in the format of your choosing. Another user can import this file using the Import View, to recreate the LocalStore in his HIPE session (and in future HIPE sessions). This is simple and straightforward and there's nothing wrong with it. Plug-ins have more features, such as versions, title and description, and a plug-in can contain accompanying scripts, for example. Also, pools delivered as part of a plug-in are not installed to your LocalStore directory, they are kept in the plug-in directory, so they do not mix with your personal LocalStores. If a plug-in is published on a web-site (HTTP or FTP), then installation of a plug-in is slightly easier, since the download and unpacking are done automatically in a single step instead of two steps.

How to create a plug-in with some Jython code

We make a distinction between two types of Jython code, and how you create the plug-in depends which type you have. First, there is what we call "user scripts". These are meant to be scripts that a user should execute, such as a script that does some kind of processing. The other kind is a script that defines some functionality, for example a Task. In this second case, the user should not execute the script to use it (which would define the Task), the user should run the Task. This kind of script should be run by HIPE when it starts, so that the user has the Task available for use. We therefore call that kind "initialization scripts".

To create a plug-in with one or more user scripts, copy them to a directory called scripts and create a zip or jar containing that directory.

Unix shell example:

> mkdir scripts
> cp ~/work/scriptsForPlugin/*.py scripts
> jar cf $HOME/myplugin_0.1.jar scripts

When this plug-in is installed, a menu item with the name of the plug-in will appear on the Tools menu. Pointing to the menu item opens a submenu with all scripts. Clicking on one of the scripts will open it in the editor.

Plug-ins support only one initialization script, but you can define multiple Tasks from a single script. The initialization script must be called plugin.py and it must be at the top or root-level of the jar or zip.

Unix shell example:

> mkdir scripts
> cp ~/work/myTasks.py plugin.py
> jar cf $HOME/myplugin_0.1.jar plugin.py

This plugin.py script is similar in function to the __init__.py script that is contained in many of the Java packages in the HCSS. However, the __init__.py must have some obligatory lines of code, which are not required for the plugin.py script.

How to create a plug-in with some Java code

To add (compiled) Java code to a plug-in, the Java code has to be in a JAR itself. Add the JAR to a directory called "jars" and create a plug-in with this directory:

> mkdir jars
> cp ~/work/out/library.jar jars
> jar cf $HOME/myplugin_0.1.jar jars

Note that the JARs are included integrally in the plug-in JAR; you should not unpack your JARs with Java code and include the loose class files in the plug-in JAR. To clarify further, if you get a listing from your plug-in JAR using jar tf plugin-1.0.jar, you might get a listing like this:

META-INF/
META-INF/MANIFEST.MF
jars/
jars/filtering.jar
plugin.py

This plug-in contains a JAR called filtering.jar, which in turn might contain any number of Java classes.

For information on how to create a JAR file with your Java code, see the JAR Documentation.

Combinations of the above

If you want to create a plug-in that has an initialization script, some user scripts and a handful of pools, the easiest thing is to create a separate directory. Copy everything in there (the scripts directory, pools directory, etc) and create a zip or jar with everything:

> jar cf $HOME/myplugin_0.1.jar *

What you must avoid / Invalid plug-ins

When sharing things with plug-ins, you are not limited the items described in the previous section. You can add anything to a plug-in, but there are a few things that would make the plug-in invalid. An invalid plug-in would fail to install.

The following would make the plug-in invalid:

  • a file called scripts, pools or jars at the top-level of the file
  • a file or directory called work at the top-level of the file. HIPE uses this directory as an internal workspace.

Slightly more advanced topics

Compatibility information

It is highly recommended to include a file called plugin.xml at the top-level (root directory) of your plug-in and use it to specify the compatible HIPE versions. You do this by specifying a minimum version which with HIPE is compatible, and a maximum version. You should always specify a maximum version, because you don't know if your plug-in will be compatible with the next version of HIPE. If you distribute a plug-in when HIPE v1.0 is current, you should specify that is compatible with versions up to 1.0.*. This means that your plug-in is compatible with all builds from the 1.0 track, which means all 1.x releases. This is correct, because if 1.1 has been released now, and your plug-in is compatible, you know that it will be compatible with release 1.2 as well. No compatible changes are allowed in existing release tracks.

Note that the version is specified using build track plus build number, not with the release number. So, for example, release 4.6 was built on the 4.0 track and it's build 1467. In the version compatibility information in plugin.xml you would specify release 4.6 as 4.0.1467.

The plugin.xml allows for much more customization. An example plugin.xml, which includes compatibility information, is given in the next section.

You can also specify (for instance) "all builds on the 5.0 track", using "5.0.*". Note, however, the asterisk is not a wildcard. It's interpreted as a very high number, so it is only intended to be used to specify the upper limit of compatible versions (maxVersion). Using it in the lower limit, minVersion, is allowed, but this is normally not what you want. See the example in the next section.

Warning, important The compatibility checking was added in HIPE v7.0. Earlier versions of HIPE ignore this information.

Customizing your plug-in

HIPE allows for the plug-in to specify additional information about itself using a file called plugin.xml at the root-level of the plug-in jar or zip.

Below is an example of plugin.xml file with some of the different elements it can have:

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns:em="http://www.mozilla.org/2004/em-rdf#">

   <description>This plug-in provides tasks for analysis of data.</description>
   <contributors_page>http://www.esa.int</contributors_page>
   <icon>herschel/ia/gui/apps/plugin/Extension.png</icon>
   <properties>custom.properties</properties>

   <!-- Compatible starting user release 5.0 (build 1760), not with earlier builds -->
   <em:minVersion>5.0.1760</em:minVersion>
   <!-- Compatible with all 6.x releases (all builds from the 6.0 track) -->
   <em:maxVersion>6.0.*</em:maxVersion>

</plugin>

All of the elements of this XML file are optional, except <plugin>. If you're not interested in any of the elements, just don't add this file.

The description and the contributors page are shown on the plug-in details panel. In HIPE, select Plug-ins from the Tools menu. Select a plug-in (if you have one installed!) and click "Details".

The icon is used on the Plug-ins panel (the one that opens when you select Plug-ins from the Tools menu in HIPE). The value is the location of a "resource" on the classpath. The value given here gives the default plug-in icon, which is a green puzzle piece. To add your own icon, add it to a jar, add the jar to the jars directory and specify the filename of the icon in the plugin.xml.

The properties elements specifies a properties file in the plug-in, containing properties that are loaded when the plug-in is started. The plug-in is started at HIPE start-up, unless it is disabled from the GUI. If the custom properties file contains properties that are already defined in the system, they are ignored and a warning is printed.

Adding a license

It is possible to add a license text to a plug-in. All you have to do is add a file called LICENSE.txt to the root-level of the plug-in. This license will be displayed on the License tab of the Plug-in details panel.

Using your plug-in under jylaunch

HIPE plug-ins are centered, logically, on HIPE. You need HIPE to install them (unless you know and perform all installation steps manually), and they are installed in a HIPE-specific directory. Note that HIPE is one HCSS application, and jylaunch is an entirely different HCSS application. Even so, jylaunch loads and activates plug-ins when it starts in much the same way as HIPE does.

For example, if your plug-in contains a script defining some Tasks and it also contains some data pools, and you have installed your plug-in using HIPE, then you will be able to use these Tasks and the data from a script that is run with jylaunch.

However, there is a difference between scripts run under HIPE and under jylaunch, which can have the effect that a plug-in cannot be correctly started under jylaunch, because its initialization script does not run. The difference is that HIPE at start-up first imports all Herschel code, using the general Herschel import statement:

from herschel.all import *

A typical error caused by not having imported all Herschel code is:

NameError: TableDataset

TableDataset is a class that is readily imported after start-up, in HIPE, but not under jylaunch. To make a plug-in work under jylaunch, the recommended approach is to import the classes that are needed at the start of the plugin.py file. You can also use the above general Herschel import statement, but note that it takes significant time to execute.

Advanced topics

The plug-in installation process

The standard plug-in installation process just decompresses the plug-in into the plug-in directory and "starts" the plug-in. The plug-in directory is $HOME/.hcss/apps/hipe/plugins/[name]/[version]. You can view this directory by opening the plug-ins panel in HIPE (select Plug-ins from the Tools menu). Select the plug-in and click Browse.

Starting the plug-in means:

  • add all JARs to the Java classpath and the Jython system path
  • load the custom properties
  • execute the initialization script, load
  • add the menu items for the user scripts
  • execute any registered PluginProcessors (see below)
In this order.

In general, the installation process of a plug-in consists of three steps or phases. For simple plug-ins, such as have been described until now, nothing is done during the second and third phase. Only the first phase, which is called "bootstrap", is executed. During this installation, the plug-in is downloaded from the URL that indicates its location, and the jar or zip is decompressed in the plug-in directory. Not that the directory, that the plug-in is unpacked into, contains the version of the plug-in. This means that multiple versions of a plug-in can exist on a user's disk, but when HIPE starts, only the latest version of each plug-in will be started.

The second phase is called "custom installation". During this phase, a complete, stand-alone installation program can be executed. Often such programs are Java WebStart programs, but you can also include the installation program in the plug-in itself. If you want to include the custom installation in the plug-in, see the next section for details. If you want to use a WebStart installation program, see the section "Using a WebStart installer".

The third and final phase is called "configuration". This allows the plug-in developer to execute some steps after the custom installation. For example, if the custom installation installs an external Java program somewhere on the user's disk, then for this plug-in to contribute something to HIPE, probably the JARs of the external program have to be added to the HIPE classpath. This can be done during this step. How, is described in the section "Configuring the plug-in post-installation".

While phase 1 is always executed, phase 2 and 3 are optional and independently optional: You can create a plug-in that does something during phase 2 but not during phase 3, and vice versa.

There is currently no mechanism to check for successful completion of the custom installation programs, executed during phase 2.

Using a custom installer

This section explains how to run a custom program during phase 2 of the plug-in installation.

First, the plug-in must contain a file plugin.xml at the root-level of the jar or zip, with at least the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
   <installer className="MyCustomInstaller" />
</plugin>

And second, a .class file (a compiled Java file) containing the class MyCustomInstaller should be added to the plug-in, also at the root-level of the jar/zip.

The name of the class can be any legal class name except "Installer", because this used for the class that is executed in phase 3. The package must be the default package, i.e. no package.

The class must have either a regular main method, or it can implement the interface herschel.ia.gui.apps.plugin.Installer. If the latter is chosen, the method install(PluginEnv) will be called to execute the installer, which has the advantage that the installer gets access to several properties of the plug-in via the PluginEnv object that is passed as an argument.

Using a WebStart installer

To run a WebStart installer during phase 2 of the plug-in installation, the plug-in must contain a file plugin.xml at the root-level of the jar or zip, with at least the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
   <installer url="http://www.esa.int/webstartfile.jnlp" />
</plugin>

The URL should point to the JNLP file of the WebStart program, which is an XML file that tells Java WebStart where the JARs of the WebStart program are found and which class contains the main method, among other things. The JNLP file can also be used to pass properties to the WebStart program: If you need to pass special properties to the installer, if it is run from a plug-in installation process, then we recommend to create a separate JNLP file for this case. That is, one JNLP file for the normal, stand-alone installation of the program, and one JLNP file when the installation happens as part of the installation process of a plug-in. The second file can then contain some additional properties, to tailor the installation.

Configuring the plug-in post-installation

To perform some steps after completion of phase 2, you can add a class called Installer to the plug-in top-level dir. This class must implement the interface herschel.ia.gui.apps.plugin.Installer and it must be in the default package (i.e. no package).

After completion of phase 2 (whether anything was actually done is irrelevant), the install(PluginEnv) method of this interface is called.

As said before, this can be used for example to add references to external JARs installed during phase 2. For this example you can use the method addJar of the PluginEnv class.

Uninstallation

The Plug-ins panel in HIPE shows a button "Uninstall". Clicking this button will simply delete the plug-in directory (all versions). It undoes, in effect, phase 1 of all installations of a given plug-in.

There is no way to undo phases 2 and/or 3 of the installation process. No custom uninstaller can be configured.

Enabling and disabling plug-ins

The Plug-ins panel in HIPE also allows to "disable" or to "enable" a plug-in (depending on whether it is currently enabled or disabled). A disabled plug-in is simply not started. It is loaded into the Plug-in Registry (see below), but it is not started.

The disabled or enabled status is persisted to disk, so that if a plug-in is disabled or enabled, it will still be in that state when HIPE is restarted.

Loading classes from included JARs

Normally, when including one or more JARs in your plug-in, you don't have to worry about class paths, class loaders, etcetera. If you import and instantiate a class from such a JAR using Jython or in Java, this will work as normal.

The exception is when you explicitly use a class loader to load a class. Suppose you include a JAR with a JDBC driver to connect to a relational database. Typically you will have to load the driver by its class name, to be able to use it. To be able to load such a class, which is in a JAR that is not on the standard Java class path but inside a plug-in, you must use a class loader that knows about this JAR. The recommended way to do this is to use the ObjectUtil class:

// to get the Class object:
Class<?> c = ObjectUtil.getClass("my.package.MyClass");
// or to create an object of this class
my.package.MyClass object = ObjectUtil<my.package.MyClass>.newInstance("my.package.MyClass");

The newInstance method uses the default constructor. If you need to use a different constructor, use the Class object.

Examples

For examples, see DpHipePlugins. Any of the plug-ins can be downloaded and inspected using the jar tool or any other zip program. Among examples offered are:

  • SPIA: This plug-in contains:
    • A HIPE SPIA perspective
    • An initialization script defining Tasks. This initialization scripts also has the registration for the perspective at the bottom.
  • The "demonstration plug-in" contains:
    • A more fully-featured plug-in descriptor file, plugin.xml
    • An initialization script
    • A few user scripts (the scripts themselves are trivial)
    • Custom properties that are added to the HIPE configuration
    • A custom installer for phase 3 ("configuration" -- see advanced topics). The source code for this installer is also included, this is for your convenience only.
    • A license

For HIPE component developers: Working with plug-ins in HIPE

Some HIPE components may have to perform some actions when a plug-in is installed. For example, the Preferences panel is the one that picks up the pools from the plug-ins when they are installed. Such things are done by registering a PluginProcessor.

Once plug-ins have been installed and are started, HIPE components can find them in the Plug-in Registry (for example, the Plug-ins Panel that can be opened from the Tools menu).

PluginRegistry and Plugin class

The Plug-in Registry, implemented by the PluginRegistry class, is a singleton that allows access to all plug-ins currently installed (latest versions only). The elements that in the registry are of the Plugin class. They are keyed by the plug-in name and sorted alphabetically.

The Plugin class reflects the installed plug-in in its plug-in directory: It has accessors to get the information from the plugin.xml file, you can ask it which JARs and scripts the user has installed, etc. And finally, you can use this class to start, stop and enable/disable the plug-in. Starting and stopping is normally managed by HIPE though, so it is unlikely that you will need to call those methods.

PluginProcessor

You can implement the PluginProcessor interface (herschel.ia.gui.apps.plugin package) and register it on the PluginRegistry. This processor will be called when any plug-in is started (the onStart method) and also when any plug-in is stopped (onStop method).

In principle, all plug-ins are started when HIPE is started, and presumably you will also register your PluginProcessor when HIPE is started. This gives rise to a race condition: Depending on whether you manage to register the processor a little bit earlier or later, it may or may not get called for some of the plug-ins. This is solved by making sure that all PluginProcessors that are registered are also called for all plug-ins that have been started already. Effectively this simply means you do not have to worry about this; if you register your processor, it will be called for all plug-ins that have been started and those that will still be started during HIPE start-up.

-- PaulBalm - 27 Aug 2010


This topic: Public > DpHipe > DpHipePlugins > DpHipePluginsDeveloperManual
Topic revision: r9 - 2011-01-12 - PaulBalm
 
This site is powered by the TWiki collaboration platform Powered by Perl