Thursday, October 29, 2009

P2 Update Manager Not Allowing Update without restart

I am noticing that if my application requires Declarative Services bundle (in my case, I am using org.eclipse.equinox.p2.ds),. And, if my run launch configuration requires ds and the org.eclipse.core.runtime to be started at startup, I am forced to restart after any update to see the effect of the update.

update:
I stumbled on this link: which appears to address my problem. Apparently, if you configure your own start settings, then you must also explicitly setthe following start values for p2 to work properly:
BundleStart LevelAuto-Start
org.eclipse.equinox.simpleconfigurator1true
org.eclipse.equinox.common2true
org.eclipse.update.configurator4 (default)true
org.eclipse.core.runtime4 (default)true
org.eclipse.equinox.ds1true

Wednesday, October 28, 2009

P2 Update Manager Unable to read repository (local file)

If you get this failure during an update:
"an error occurred while collecting items to be installed" "unable to read repository".

Make sure you have this bundle included "org.eclipse.ecf.provider.filetransfer" as well as any associated "required plugins".

Thursday, October 1, 2009

How to use Declarative Services in RCP Applications

Context

OSGi Declarative Services is very attractive, which spares you from writing a lot of boiler plate code for things like registering/unregistering/consuming services.

I wanted to use OSGi's Declarative Services for dependency injection in RCP applications.  For example, I had a view, in which I would like to use a service SimpleService advertised by Declarative services.

Problem

My first naive approach was to create a component.xml, in which the view class consumes SimpleService. Well, it did not work as I liked, because the view did not have SimpleService injected.

What went wrong?

Nothing went wrong. Declarative Services work as advertised, but my approach was way wrong.

To allow Declarative Services (DS) work, you have to ask DS to instantiate an object for you. During this process, DS injects all necessary services in this newly created object.

However, a view object was created by RCP application launcher outside DS.  What I ended up with were a view object created by RCP application launcher, and another lonely view object created by DS with SimpleService injected but not used in my RCP application launcher.

What is a good approach to inject my SimpleService in my view object?

Solution (a solution)

In your RCP Application's Activator, use ServiceTracker to look up SimpleService. In your view, get SimpleService by Activator.getDefault().getSimpleService().

public class Activator extends AbstractUIPlugin {
    public void start(BundleContext context) throws Exception {
        super.start(context);
        this.context = context;
        lookupService(context);
        plugin = this;
    }

    public static Activator getDefault() {
        return plugin;
    }

    private ServiceTracker tracker;
    private ApplicationUserAdmin userAdmin;
    private void initializeServiceLooup(BundleContext context) {       
        if(userAdmin!=null) {
            return;
        }
        tracker = new ServiceTracker(context, SimpleService .class.getName(),null);
        tracker.open();
    }
    public SimpleService getSimpleService() {
        return (SimpleService ) tracker.getService();
    }

   //other omitted here
}

Wednesday, September 30, 2009

Using P2 Update Manager in an RCP App Based on Eclipse 3.5 (Galileo)

I have found using the new update manager (P2) in a standalone RCP application to be rather tricky. It's best to start by reading Equinox/p2/Adding Self-Update to an RCP Application and looking at the example (org.eclipse.equinox.p2.examples.rcp.sdkui) which can be retrieved from CVS: /cvsroot/rt (Eclipse CVS access info ). Place that application in your workspace.

Right-click your bundle project and make new Product Configuration
- select "Use an existing product" (and select the org.eclipse.equinox.p2.examples.rcp.sdkui.product)
- give product configuration file a name

After the product configuration is created, in the dependencies tab remove the org.eclipse.equinox.p2.examples.rcp.sdkui plugin.

Replace with your own bundle/plugin.

In your bundle, you must have a p2.inf file in the root. Mine has:
instructions.configure=\
addRepository(type:0,location:file:///C:/somepath/updatesite );\
addRepository(type:1,location:file:///C:/somepath/updatesite );
(Note that mine uses a file URL. You can of course also use an HTTP URL. If anyone can show me how to have multiple entries in here, let me know. I have yet to figure that out.)

You must also add the P2 UI elements to your application. The easiest way to do that is by adding the menu items to your application declaratively (i.e. via plugin.xml). On the extensions tab, click add and select org.eclipse.ui.menus. Then right-click that entry and add -> new -> menu contribution. Set the locationURI to menu:org.eclipse.ui.main.menu?after=additions. Now right-click -> new -> menu and give it a user friendly label. Then right click that menu and -> new -> command and I did this 4 times for these commandId's which each show up on the menu: org.eclipse.ui.window.preferences, org.eclipse.equinox.p2.ui.sdk.update, org.eclipse.equinox.p2.ui.sdk.install, org.eclipse.ui.help.aboutAction

Use Eclipse Product Export Wizard found in overview tab of product configuration file. During export, make sure "Generate metadata repository" is selected.

When you launch you should be able to use the install and update commands as well as verify installation configuration from the preferences and about menu items.

Ordering is significant in constructing a TableViewer

Context
I wanted to create a table viewer (3 columns) with my own content and label provider.


Problem
I found out that, if I set the content provider and label provider before I added all the columns to the table viewer, it would show no content, or only the columns that I added before I set the label provider.


Code


    TableViewer tableViewer = new TableViewer(tabFolder, SWT.BORDER | SWT.FULL_SELECTION);
    TableViewerColumn tableViewerColumn1 = new TableViewerColumn(tableViewer, SWT.NONE);
   ...

    //call setters before all columns are added, which will cause no content display for the column 2 and 3 

    tableViewer.setLabelProvider(new UserAssignmentLabelProvider());
    tableViewer.setContentProvider(new UserManagementContentProvider());
    tableViewer.setInput(...);

          ...
    TableViewerColumn tableViewerColumn2 = new TableViewerColumn(tableViewer, SWT.NONE);

         ..
    TableViewerColumn tableViewerColumn3 = new TableViewerColumn(tableViewer, SWT.NONE);
   ...
    tableViewer.setLabelProvider(new UserAssignmentLabelProvider());
    tableViewer.setContentProvider(new UserManagementContentProvider());
    tableViewer.setInput(...);

Why I abandoned Swing and went for SWT/RCP?

  1. Cleanly Structured Rich Client Application Framework (branding, integration, provisioning, etc)
  2. Better native look-n-feel.
  3. A lot of useful open source OSGi plug-ins for your application development
  4. Developer can manage resource directly (some people might argue this is a step backward)