Friday, May 24, 2013

Did my plug-in load?

One of the most frequent question I get asked is 'How to check if my plug-in is getting picked up properly?' The easiest way to verify is by using Host OSGi Console.


Note that if you do not see 'osgi>' prompt, just press Enter key once. Now you can issue OSGi commands and verify the status of your plug-in


ss is OSGi command to check the status of a plug-in.
Issue help command to see other commands possible as osgi prompt.

You may find some more info at


So the STARTING status means that the plug-in has been discovered but not loaded yet (lazy loading - no class from this plug-in has been requested yet). Once you invoke a functionality that shall need this plug-in, the status shall change to ACTIVE. This would mean that your plug-in is now been loaded into memory.

This is fine, how did we land to OSGi console and how to use Self Hosting?

Self Hosting is nothing but launching your plug-ins with 'Eclipse Application' launch configuration. This launches a new Eclipse instance (called guest instance) having your chosen plug-ins along with the Target Platform

So can be done now is, self-host your eclipse plug-ins. Invoke the Console view and switch to OSGi console and have a look at the state of your plug-ins. This will tell if the Eclipse was able to locate and load plug-ins.

But you want more.

How would you verify the manifest or plugin.xml for the plug-in that got loaded. Typical stuff to check when an extension is not behaving.

Invoke the Plug-ins view. It will show all the plug-ins with which the Guest Eclipse was launch. That is, target platform plus selected workspace plug-ins. You can find you plug-in in this view and expand it to see all its contents. Since, it not a binary plug-in but coming straight from the workspace, you can view the source code that got built and used for this plug-in.

Interestingly, there is one more friend - Plug-in Registry view. This would tell you the location from where the plug-in was picked. The extensions and extension points detected by Eclipse and the dependency tree.

With these views, you can pin point on what code got loaded, from where and what state it is in now.






Monday, December 26, 2011

OSGi Tracing in Equinox

The Equinox implementation of OSGi provides the tracing APIs in org.eclipse.osgi plug-in since Eclipse 3.5. The tracing options are generally Boolean flags stored in a .options file as key-value pair. A typical .options file would look like this

org.my.plugin/ui=true
org.my.plugin/ui/editor=true
org.my.plugin/ui/prefs=true
org.my.plugin/debug=false
org.my.plugin/debug/data=true

The hierarchy is defined using the slashes. But this is only a general practice. The tracing does not understand this.

-osgi.debug
To load the values from the .options file, provide the file name as command line parameter (or program parameter in launch config)

command line arg example
eclipse.exe -debug C:\tracing\.options

program argument (in launch config) example
-Dosgi.debug=C:\tracing\.options

Using -debug is same as setting the osgi.debug system property.

Accessing the option values at runtime
1. In RCP application
If the RCP application has access to the org.eclipse.core,runtime.Platform object and thus they can access it directly like this

String value = Platform.getDebugOption("org.my.plugin/ui");

User can validate if the program is running in debug mode using Platform.inDebugMode() API.

2. In pure OSGi application
An OSGi application can access these options using the DebugOptions service


ServiceTracker debugTracker = new ServiceTracker(bundleContext, DebugOptions.class.getName(), null);
debugTracker.open();
DebugOptions debugOptions = (DebugOptions) debugTracker.getService()
boolean uiOption = debugOptions.getBooleanOption("org.my.plugin/ui", false);

Using the API has the advantage that user does not have to check for nullness.

More Tracing API
org.eclipse.osgi provides more APIs which are very helpful in logging the trace.

1. Registering a debug option listener
The listener can be registered as service using the BundleContext (that you receive in the activator class when the bundle is started)


final Hashtable<String, String> properties = new Hashtable<String, String>(4);
properties.put(DebugOptions.LISTENER_SYMBOLICNAME, TracingConstants.BUNDLE_ID);
bundleContext.registerService(DebugOptionsListener.class.getName(), new MyDebugOptionsListener(), properties );

2. Listening to the debug option change events
Once the listener is registered, a callback will happen each time a debug option is changed. The callback does not tells you the delta and instead throws the whole lot. So we can use this place to read and init from the DebugOptions


/* (non-Javadoc)
* @see org.eclipse.osgi.service.debug.DebugOptionsListener#optionsChanged(org.eclipse.osgi.service.debug.DebugOptions)
*/
public void optionsChanged(final DebugOptions options) {
//DebugTrace trace;
trace = options.newDebugTrace("org.my.plugin");
// boolean field
DEBUG = options.getBooleanOption("org.my.plugin/debug", false);
}

this is just an indicative code. You don't have to necessarily do it this way.

3. Writing to trace
This is the easiest part. Afterall the reason we did the whole exercise was to make the tracing simple. A handle to trace object can be obtained from the debug options.


/** Trace object for this bundle */
private final static DebugTrace TRACE = MyPluginActivator.getDefault().getTrace();  // returns the trace object obtained using options.newDebugTrace("org.my.plugin");




@Override
protected Control createContents(final Composite parent) {
if (MyPluginActivator.DEBUG) {
TRACE.traceEntry("/debug", parent);
}
...
...
}

Checking MyPluginActivator.DEBUG is optional. TRACE.traceEntry will check for the flag "/debug" anyway. This is to improve of the performance. We store the the flag values to boolean fields and update them through the listener.



4. Where is the log file?
 The log is stored in the file as set in the debug options. By default, it tends to store them to workspace\.metadata\trace.log

options.setFile(new File("/path/to/trace/file"));

5. Controlling the trace logs
The logs are conntolled by two system properties

eclipse.trace.size.max : The system property used to specify size a trace file can grow before it is rotated
eclipse.trace.backup.max : The system property used to specify the maximum number of backup trace files to use

Easier way to manager the logs?
PDE will be providing UI for managing the logs and make them dynamic. See Bug 296631. This is mostly like to make it to Juno M5 release.

What do you mean by dynamic?
If you notice, the debug options can be loaded at the launch time (using -osgi.debug) or programatically when running. However, if you wish to turn the tracing on/off in a running product, its tricky. PDE will be providing an extension using which a plug-in can expose its debug option flags. The UI will display these flags in preferences where they can be turned on/off for a running application. Cool! isn't it?


* If you find any discrepancies in the above post, please bring it to my notice so that they can be updated.

Update: Tracing UI is now available in latest Integration builds and will be there from Juno M5.

Sunday, July 24, 2011

PDE Good Practices: #8 Set correct EE and Java compliance levels

The Execution Environment that is set on the plug-in manifest governs the lowest JRE version the plug-in can work with. If the OSGi runtime (equinox) is running with a lower JRE than the plug-in will not be loaded.

So marked the EE carefully to the lowest JRE you wish to support.


Similarly, ensure the Java compliance level matches the EE.

For example, assume the EE is set to J2SE-1.4 and the Java compliance to 1.5. Now, if you use annotations, the code would still compile in your workspace. However, when deploying, the plug-in would fail it will tell OSGi that it can run with 1.4 but actually it can not.