under construction
Introduction
Plugins
- Plugins are software programs that can be dynamically added to existing programs to add / enhance the 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.
- The user can add the 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.
OSGi
- 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() method. The activator class is specified in the Bundle-Activator bundle 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. - 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 starts the felix implementation from with the com.affymetrix.igb.main.OSGiHandler class, but IGB can
be run using the Felix command line tool by runningant gogo
- 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. Web Servers that host bundles (repositories) need to use OBR to create the repository.xml file
listing all the available bundles. - Users can add /remove bundle repositories on the Preferences page.
- 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 are the IGB tabs and the graph functions.
Explain:
- What is a bundle? Give an example.
- What is OSGi and how does it work?
- Explain what an Activator is.
- Provide references to tutorials developers new to the concept of bundles can read to get familiar with the topic.
- Explain the concept of extension point.
- Explain the advantages of bundles, plug-ins. (Ann can write this part after talking more with Michael and Lance.)
Developing IGB bundles
IGB bundles are OSGi compatible, so they must have an Activator, a class that extends org.osgi.framework.BundleActivator, and they must have a manifest.mf file that is found in the META-INF directory. These are compiled and jarred with all required classes, jars, and resources. The resulting jar is the bundle. This can then be uploaded to the bundle repository. At that point, any one can use the bundle with IGB. IGB uses the Apache Felix OSGi implementation, but this could change, so no Felix specific code should be used. In the Activator class, there is a start() and stop() method that are called when the bundle is activated / deactivated (not installed / uninstalled). This is where you want to put all the code to start and stop the bundle.
In the manifest.mf file, there are several headers that need to be specified - fill in parenthesis below:
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)
If you look at the Plug-ins tab, you will see the Bundle-SymbolicName under the Name column, the Bundle-Description under the Description column, and the Bundle-Version under the Version column. If the Bundle-DocURL is there, the Name cell will have a blue info icon that links to this URL.
- Import-Package and Require-Bundle don't need to overlap, you can specify a requirement in one or the other. To have a multi line header, start the continuation line after a blank in column 1.
- Put a blank line at the end of the manifest.mf file - due to a bug in felix.
- The igb, genometry and genoviz projects can by accessed as bundles. If a class/method is needed from igb/genometry/genoviz, it must be public, and the package must be exported in the manifest.mf Export-Package list. Ann's note: manifest.mf of what?
- If you want to add a tab panel as a bundle, there is a helper abstract class, com.affymetrix.igb.window.service.WindowActivator, that you can extend.
- If you need access to other bundles (like IGBService), you will not be sure when the
bundle is available. (Ann's note: Please explain more) For Services, like IGBService and WindowService, you can use a ServiceTracker to be notified when the required service is available - see WindowActivator
for an example. - In the IGB source code repository, in the plugins/ directory, you will find several embedded bundles that IGB uses. Look through
these to help you understand bundles.
Sample plug-in
- to create a plugin, you will create (at least) two files, the MANIFEST.MF file and the Activator
- we will create a bundle that adds a new graph function
- create the following MANIFEST.MF file:
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: MyBundle
Bundle-SymbolicName: MyBundle
Bundle-Version: 1.0.0
Bundle-Activator: mypackage.MyActivator
Import-Package: com.affymetrix.genometryImpl.util,
org.osgi.framework
-
- (note - there are spaces at the beginning of the extension lines, and a blank line at the end)
- Now, create the Activator,
mypackage.MyActivator.java
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
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 float inverseTransform(float x) { return 0.0f; } public boolean isInvertible() { return false; } public boolean setParameter(String s) { return true; } }
To create plug-ins using eclipse - a Quick-Start Guide
Eclipse (http://www.eclipse.org) makes it a lot easier to develop bundles. You can create a new project
as a plug in project, and it will give you wizards, etc. for development. see:http://www.vogella.de/articles/OSGi/article.html
(using eclipse Helios)
- check out IGB from https://genoviz.svn.sourceforge.net/svnroot/genoviz/trunk
into a new project in eclipse - make a new IGB_HOME environment variable to point to the IGB project (Ann's Note: What directory should it point to in the checked out code - maybe give an example?)
- open a command prompt in IGB_HOME, and do an "ant clean" and "ant jar"
- in eclipse, project explorer, right click the IGB project and select "refresh"
- in eclipse, project explorer, right click on open space, and select "Import..."
- Select "Plug-ins and Fragments" under "Plug-in Development", click the "Next >" button
- under "Import From", select "Directory:",
- under "Plug-ins and Fragments to Import" select "Select from all plug-ins and Fragments",
- under "Import As" select "Binary Projects"
- for "Directory:", click the "Browse..." button and select the IGB_HOME/ext, click the "OK" button
- click the "Next >" button
- under "Plug-ins and Fragments Found:", select affx_fusion, colt, freehep, image4j, jlfgr, picard, and sam
- click the "Add -->" button to add these all to "Plug-ins and Fragments to Import:", click the "Finish" button
- Do the following for the directories under IGB_HOME, genometryImpl, genoviz_sdk, igb, plugins/igb_service, plugins/window_service
- in eclipse, project explorer, right click on open space, and select "Import..."
- Select "Existing Projects into Workspace" under "General", click the "Next >" button
- click "Select root directory:" and click the "Browse..." button on the right
- select the project under IGB_HOME, and click "OK"
- click "Finish"
Sample plug-in using eclipse
- In the Project Explorer - blank area, right-click
- New > Project ... > Plug-in Project > "Next >" button
- Project name: "HelloWorld"
- "Next >" button
- Version: "1.0.0"
- check "Generate an activator ..."
- Activator
helloworld.Activator
- Rich Client Application click "No"
- "Next >" button
- Uncheck "Create a plug-in using one of the templates"
- "Finish" button
- Under the new HelloWorld project, find the META-INF directory, and open the MANIFEST.MF file by double-clicking on it.
- Click on the "Dependencies" tab,
- in the "Required Plug-ins" box, highlight org.eclipse.core.runtime, and click the "Remove" button on the right.
- next to the "Imported Packages" box, click the "Add..." button, in the "Package Selection" popup in the text box, enter
com.affymetrix.genoviz.util
and click the "OK" button. - Do the same for
org.osgi.framework
(there may be a version number in parentheses after the name).
- Right click on the blank area at the top, next to "Dependencies" and
- a context menu comes up, click "Save".
- Open the Activator.java file under src/helloworld
- add the import statement
import com.affymetrix.genoviz.util.ErrorHandler;
- at the top, and add the line
ErrorHandler.errorPanel("Hello World");
- at the end of the start() method, and
ErrorHandler.errorPanel("Goodbye World");
- at the end of the stop method
- Save the file
- In the Project Explorer
- Right click the HelloWorld project
- > "Export ..."
- "Deployable plug-ins and fragments"
- "Next >" button
- Under "Available Plug-ins and Fragments:", check only Hello World
- "Directory:" use any directory you like
- click the "Finish" button.
- The HelloWorld_1.0.0.jar file will be in the plugins directory under the directory the you specified. This is your bundle
- In the plugins directory, from the command line run
java -cp IGB_HOME/igb_server/lib/bindex.jar -jar bindex.jar -n IGB -q -r repository.xml .
- where IGB_HOME is your IGB directory.
- Now, if you can access your plugins directory from a local web server, you can open up the Plug ins tab in IGB
- (http://wiki.transvar.org/confluence/display/igbman/IGB+Tabbed+Panels#IGBTabbedPanels-PluginsPanel)
- click on the "Repositories..." button on the lower right
- Click the "Add..." button
- put the URL for your local plugin directory
- Click the "Add Server" button
- close the Preferences popup
- uncheck and recheck the "Show Uninstalled" checkbox at the bottom of the Plug-ins tab
- You should now see your Hello World plugin.
- If you install the plugin you will see an Error popup "Hello World"
- When you uninstall the plugin, you will see an Error popup "Goodbye World"
- Congratulations!
To create plug-ins using NetBeans - a Quick-Start Guide
Is this possible? Easy?