Table of Contents |
---|
Introduction
Plugins
...
are software programs that can be dynamically added to existing programs to add / enhance functionality.
...
They are also called Add-ons or Bundles (the OSGi term).
...
You may have seen plugins in the software that you use, Internet browsers, text/graphics editors, games, etc.
...
Examples include Adobe Flash and Adobe Reader for browsers, and countless Photoshop filters.
...
Users can search for plugins and choose ones that address their needs.
...
Users can add a new plugin (download and install) whenever they want.
...
They can remove a plugin if they no longer need it.
...
The plugins can also be updated dynamically when the author(s) make changes.
IGB uses OSGi to implement plug-ins
The java standard for Plugins is OSGi (http://www.osgi.org). This is what IGB (written in java) uses.
...
The OSGi term for a Plugin is Bundle. They mean the same thing.
An OSGi bundle is a jar file. It must have a MANIFEST.MF file with the OSGi headers (see below).
An OSGi bundle can (usually will) have a special java class called an Activator. This class must extend org.osgi.framework.BundleActivator
, and implement the start()
and stop()
methods. The activator class is specified in the Bundle-Activator MANIFEST.MF header (see below). These methods are called when the bundle is started and stopped.
When a program is running with OSGi, the OSGi framework dynamically handles installing / uninstalling,
...
activating (starting), deactivating (stopping), and upgrading bundles.
OSGi caches bundles, saving them to a directory on the local hard disk, so that they don't need to be downloaded every time. So you can work offline after you have loaded IGB.
...
There are several implementations of OSGi, including:
- Apache Felix (http://felix.apache.org/)
- Eclipse Equinox (http://www.eclipse.org/equinox/)
- Knoplerfish (http://www.knopflerfish.org/)
The implementations are (for the most part) interchangeable and are free.
...
The implementations allow the user to run OSGi from a command line tool or to start it within a program.
IGB
...
uses the
...
Apache Felix implementation from within the com.affymetrix.igb.main.OSGiHandler class
...
.
...
There are several tutorials for OSGi, including:
- How to get Started with OSGi (http://www.osgi.org/About/HowOSGi)
- Apache Felix OSGi Tutorial (http://felix.apache.org/site/apache-felix-osgi-tutorial.html)
- OSGi for Beginners (http://www.theserverside.com/news/1363825/OSGi-for-Beginners)
- OSGi with Eclipse Equinox - Tutorial (http://www.vogella.de/articles/OSGi/article.html)
IGB uses OBR (http://felix.apache.org/site/apache-felix-osgi-bundle-repository.html) to find and load bundles from web servers (repositories). The web servers need to use OBR to create the repository.xml file listing all the available bundles.
Users can add / remove bundle repositories by choosing File>Preferences
...
, Plugin Repositories tab.
IGB uses OSGi Services to allow bundles to add new implementations of existing IGB elements. The new implementations will show up as soon as the bundle is started. Examples include IGB tabs and graph manipulation functions.
Extension Points
(TODO Differentiate our use this term from Eclipse's use of this term.)
IGB has several "extension points" designed specifically for plugins. These are interfaces or abstract classes that
are implemented or extended by plugin versions. Usually the Activator for the plugin will register the plugin as a
service in the start() method:
Code Block |
---|
bundleContext.registerService(<extension point>.class.getName(),
<plugin implementation>,
new Properties());
|
The extension points areinclude:
- com.affymetrix.genometryImpl.operator.Operator - operates on a selection of tracks from the GraphAdjuster tab or popup menu
- com.affymetrix.genometryImpl.parsers.FileTypeHandler - process a file type (by the file extension)
- com.affymetrix.igb.shared.TrackClickListener - called when the user clicks on the label portion of a track
- com.affymetrix.igb.shared.GlyphProcessor - called when IGB creates a glyph
- com.affymetrix.igb.shared.MapViewGlyphFactoryI - a new way to display a track
- com.affymetrix.igb.search.mode.ISearchMode - a new search method option on the Search View tab
- com.affymetrix.igb.osgi.service.IGBTabPanel - a tab in the JTabbedPane at the bottom and sides of IGB
- com.affymetrix.genometryImpl.util.ServerTypeI - a server type
- com.affymetrix.igb.osgi.service.IStopRoutine - a routine to be run when IGB terminates
- com.affymetrix.igb.prefs.IPrefEditorComponent - a Preferences window to let users enter preferences
...
In the MANIFEST.MF file, there are several headers that need to be specified - fill in parenthesis below:
Code Block |
---|
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: (name of bundle)
Bundle-SymbolicName: (name of bundle)
Bundle-Version: (bundle version, you can use 1.0.0 to start)
Bundle-Activator: (activator class name, including package)
Bundle-ActivationPolicy: lazy
Bundle-Vendor: (your company)
Bundle-DocURL: (URL of bundle documentation)
Import-Package: (list all external packages required by the bundle)
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ClassPath: (put the class path within the bundle itself, e.g.: ., resources/, lib/xyz.jar)
Bundle-Description: (description of bundle)
Require-Bundle: (list all bundles required by this bundle)
|
...
- To create our plugin, we will create three files, the MANIFEST.MF file, an activator (OSGi term), and a transformer (IGB term).
- We will create a bundle that adds a new graph function.
- Create the following MANIFEST.MF file:
Code Block |
---|
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MyTransformer
Bundle-SymbolicName: MyTransformer
Bundle-Version: 1.0.0
Bundle-Activator: mypackage.MyActivator
Import-Package: com.affymetrix.genometryImpl.util,
org.osgi.framework
|
...
- Now, create the Activator,
mypackage.MyActivator.java
Code Block | borderStyle | solid|||
---|---|---|---|---|
| ||||
package mypackage;
import java.util.Properties;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import com.affymetrix.genometryImpl.util.FloatTransformer;
public class MyActivator implements BundleActivator {
private BundleContext bundleContext;
private ServiceRegistration serviceRegistration;
protected BundleContext getContext() {
return bundleContext;
}
public void start(BundleContext _bundleContext) throws Exception {
bundleContext = _bundleContext;
serviceRegistration =
bundleContext.registerService(FloatTransformer.class.getName(),
new MyTransformer(), new Properties());
}
public void stop(BundleContext _bundleContext) throws Exception {
if (serviceRegistration != null) {
serviceRegistration.unregister();
}
bundleContext = null;
}
}
|
- And create the Transformer,
mypackage.MyTransformer.java
Code Block | borderStyle | solid||||
---|---|---|---|---|---|
|
| ||||
package mypackage; import com.affymetrix.genometryImpl.util.FloatTransformer; public class MyTransformer implements FloatTransformer { final String paramPrompt; final String name; public MyTransformer() { super(); paramPrompt = null; name = "MyTransformer"; } public String getParamPrompt() { return null; } public String getName() { return name; } public String getDisplay() { return name; } public float transform(float x) { return x; // boring, put your own math function here, return 1.0/x; or return 3*x*x*x - 2*x*x +8*x - 6; } public boolean setParameter(String s) { return true; } } |
...