If a bundle shall provide a user interface, it could create a JFrame, add some components and present it on screen. (For instance assume you built some home automation and a fridge monitoring bundle shall present some feedback when the temperature is too high.)
Create and Dispose the JFrame
One approach is to create the JFrame when the bundle's start method is called. When the bundle is stopped, it should clean up and thus dispose the JFrame. Bundles may have an "Activator" which is an implementation of the BundleActivator interface. The interface defines a start method - which is called by the framework when the bundle is started - and a stop method - which is called by the framework when the bundle is stopped.
The OSGi snippets project contains a "bundleswing1" project which contains exactly one class:
In the guitool, start the framework, install the bundle file named "bundleswing1" from the files list and start it in the bundles list. (Bundle files are on the right hand side and bundles are on the left hand side in the guitool scteen. Bundles appear when bundle files are installed.)
The bundle starts and a JFrame is shown:
Pressing the "Stop" button in the guitool stops the bundle and closes the JFrame.
To use Swing classes, they must be available to the bundle, otherwise a ClassNotFoundException is thrown. The bundle has a MANIFEST file which among other things contains these two lines:
The entry Bundle-Activator defines the class which is called when the bundle shall be started or stopped. The entry Import-Package defines the java packages which shall be available to the bundle which in this case must include javax.swing.
Playing with Import-Package
As a little exercise, you may want to change the Import-Package entry and see what happens. The build scripts create the Import-Package entry from information stored in the build.default.properties file in the project. This file is in the root of project bundleswing1. In the line prj.bundle.import-package=org.osgi.framework, org.slf4j, javax.swing remove the javax.swing package and save the file. Then build the bundle by either running build-bundles.xml or the project's build.xml script. Install the bundle and start it. The bundle information will contain "Activator start error in bundle" and the Eclipse console will show " java.lang.ClassNotFoundException: javax.swing.JLabel not found by example.swing1 ".
The Shared Owner Frame
When creating a JDialog with a null owner, Swing creates a so called "shared owner frame". This will prevent a clean exit, when - as usual - System.exit shall not be used.
The JFrame contains two buttons. The first refers to an Action which uses JOptionPane.createDialog with the main JFrame as owner. As a test, do these steps:
- Start guitool
- Start Framework
- Install and start bundleswing1
- Press the "Hello" button (a message box will apear - do not close it!)
- Stop the bundle
- Exit guitool
- The application will terminate and the JVM exits. This is the expected behaviour.
The class HelloSharedOwnerAction looks like shown below. Interesting are the lines marked with bold font. When passing null to createDialog, Swing sets a Shared Owner Frame as parent of the JDialog. The two bold lines in the propertyChange method fetch the owner and dispose it.
As a test, comment these two lines out (the ones around parent.dispose()) and repeat the steps listed above, except that the button "Hello Shared Owner" is used. The guitool will disappear when pressing "Exit", but the JVM will not terminate. It does so, because a displayable component still exists. The two commented lines were disposing that component.
Article about the JVM shutdown details: AWT Threading Issues
- Apache Felix: http://felix.apache.org/
Source code of OSGi snippets is at the project site: