Enhanced RCP: How views can communicate


I’ve often seen the question in the eclipse newsgroups when it comes to view communication. People often face the problem that their views have to communicate with each other informing about state changes (selection changes are published best through ISelectionService).
It looks like many people are not familiar with the OSGi-EventAdmin-Service which is a generic Event-System using the publish and subscribe pattern and it can be used really easy in your RCP-Applications.

1. Setup

Add org.eclipse.osgi.services to your MANIFEST.MF and make sure org.eclipse.equinox.event is part of your Launch-Config and Product-Definition.

2. Sending events

public class SenderView extends ViewPart {
  public static final String ID = "viewcommunication.views.SenderView";
  private Button b;
	
  public void createPartControl(Composite parent) {
    parent.setLayout(new GridLayout());
    b = new Button(parent, SWT.PUSH);
    b.setText("Send Event");
    b.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
        BundleContext ctx = FrameworkUtil.getBundle(SenderView.class).getBundleContext();
        ServiceReference<EventAdmin> ref = ctx.getServiceReference(EventAdmin.class);
        EventAdmin eventAdmin = ctx.getService(ref);
        Map<String,Object> properties = new HashMap<String, Object>();
        properties.put("DATA", new Date());
	
        Event event = new Event("viewcommunication/syncEvent", properties);
        eventAdmin.sendEvent(event);
				
        event = new Event("viewcommunication/asyncEvent", properties);
        eventAdmin.postEvent(event);
      }
    });
  }

  public void setFocus() {
    b.setFocus();
  }
}

3. Receiving Events

public class ReceiverView extends ViewPart {
  private TableViewer viewer;
	
  @Override
  public void createPartControl(final Composite parent) {
    parent.setLayout(new FillLayout());
    viewer = new TableViewer(parent);
    viewer.getTable().setHeaderVisible(true);
    viewer.getTable().setLinesVisible(true);
    viewer.setLabelProvider(new ColumnLabelProvider() {
      @Override
      public String getText(Object element) {
        return DateFormat.getDateTimeInstance().format(element);
      }
    });
		
    BundleContext ctx = FrameworkUtil.getBundle(ReceiverView.class).getBundleContext();
    EventHandler handler = new EventHandler() {
      public void handleEvent(final Event event) {
        if( parent.getDisplay().getThread() == Thread.currentThread() ) {
          viewer.add(event.getProperty("DATA"));
        } else {
          parent.getDisplay().syncExec(new Runnable() {
            public void run() {
              viewer.add(event.getProperty("DATA"));
            }
          });
        }
      }
    };
	
    Dictionary<String,String> properties = new Hashtable<String, String>();
    properties.put(EventConstants.EVENT_TOPIC, "viewcommunication/*");
    ctx.registerService(EventHandler.class, handler, properties);
  }

  @Override
  public void setFocus() {
    viewer.getTable().setFocus();
  }	
}

Not too complex but is it possible in fewer lines or in other words without the many lines of glue code? Then stay tuned for a follow blog entry on how e4 provides easy access to the EventAdmin-Service or visit my Eclipse 2011 talk “Singlesourcing for Eclipse 4.x and Eclipse 3.x” where you’ll learn to apply the Eclipse 4.0 style to your 3.x applications.

Advertisements
This entry was posted in Enhanced RCP. Bookmark the permalink.

32 Responses to Enhanced RCP: How views can communicate

  1. Kerle Thomas says:

    Great solution to a problem in which runs every developer who starts programming RCP applications. I wasn’t aware of this solution until now. Thanks a lot!

  2. bobbalfe says:

    This is a great post and Event-Admin is awesome.

    Lotus has attempted to promote Event Admin for about 4 years now. I even posted a project on OpenNTF which is an Event-Admin to property broker bridge. Meaning you can bridge event-admin events and declarative property changes together in a composite application.

  3. Pingback: Poll: Do you have any idea what EventAdmin is? » Balfes.net

  4. Ashok says:

    Hi,

    I am getting this exception if run the code in Eclipse 3.5 (JDK 1.5)

    Caused by: java.lang.NullPointerException: A null service reference is not allowed.
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.g etService(BundleContextImpl.java:660)
    at
    DeleteJobUpdater.notifyAppEvent(DeleteSubJobUpdater.j ava:15 Cool
    DeleteSubJobUpdater$1.run(DeleteSubJobUpdater.java:1 08)
    at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:3 5)
    at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchr onizer.java:134)

    IF i run the same code in Eclipse helious the code is running fine … i dont know wht is wrong….. can u please help this is the impl i req….

    Nullpointer is comming bcoz ServiceReference ref object is comming nulll….

    Thanks
    ashok

    • Tom Schindl says:

      Your launch configuration is missing “org.eclipse.equinox.event”

      • gaurav says:

        i added code into my eclipse rcp application, but i m getting two errors one is in SenderView to remove type argument for ServiceReference ref = ctx.getServiceReference(EventAdmin.class);

        and second is in ReceiverView for ctx.registerService(EventHandler.class, handler, properties);
        i.e.
        The method registerService(String[], Object, Dictionary) in the type BundleContext is not applicable for the arguments (Class, EventHandler, Dictionary)

      • Tom Schindl says:

        Well you are running with compiler settings for 1.4 who don’t allow generics

  5. philk says:

    The code is very verbose though. Time for a wrapper 🙂
    new SimpleEvent(“topic”).add(“data”, new Date()).send()

    How does e4 solves this?

  6. ashok says:

    Hi,

    Thanks dude after adding this ” “org.eclipse.equinox.event” “plugin it started working ..

    Now my question Default galieo eclipse does not have “org.eclipse.equinox.event” plugin whether it support this impl.

    is there any other way to impl this kind of event passing mechanism. i my project build process uses
    eclipse deltapack and eclipse galieo target platform then this plugin will miss to add this plugin .. please provide me any other way to imple this kind…… any url and code sniphet will good.,

    thanks
    ashok

  7. Pingback: Enhanced RCP: How views can communicate – The e4 way « Tomsondev Blog

  8. Stephen Watson says:

    Hi Tom,

    I’ve copied this code exactly into a demo project, but also get the error “java.lang.NullPointerException: A null service reference is not allowed.
    at org.eclipse.osgi.framework.internal.core.BundleContextImpl.getService(BundleContextImpl.java:586)
    at demo.viewevent.SenderView$1.widgetSelected(SenderView.java:33)….”

    I do have org.eclipse.osgi.services in MANIFEST.MF and I do have org.eclipse.equinox.event in launch configuration. (I clicked Add Required Pugins and Validate Plugins to be sure).

    I’m on Eclipse 3.7, Windows 7.

  9. Shibaji says:

    Hi all

    I am facing one problem in one RCP application. My application is a server dependent application. Its a simple J2EE application which will run in Application Server, but as pre the requirement I need to add server control in my RCP application also, like user can start the server , stop the server or can change the server password all those things. Some thing like we generally we do in Server View of Eclipse IDE (I mean to say when we add the application server in IDE), only difference will be in eclipse IDE we can add the Server in server view as per our requirement and multiple times , but in this case there will be only one server and one ear file deployed in it. Is that possible in any way to extend that “Server View” in own RCP application , so that the user user can have some portion of server Admin control in RCP application or is there any other way to add Server Admin panel in own RCP application. Please help me out . Thanks a lot in advance.

    • Tom Schindl says:

      I don’t think I can really help you there. I have no idea how the J2EE stuff is structured and which dependencies it has. You need to ask at the WTP-newsgroup

  10. gingleby says:

    I copied you code and got my view to receive events, the view continutes to receive events after I close the view. I see the views dispose method gets called.

    How do I ungregister the event listener?

    • Tom Schindl says:

      IIRC the registerService call returns a registration object which have to use to clean up the registration.

  11. Adil says:

    Hi Tom,

    How is this different from using AbstractSourceProvider class and ISourceProviderListener interface.

    Just curious if the SourceProvider eclipse pattern is going away ?

    Thank for all the great articles.
    Adil

    • Tom Schindl says:

      SourceProviders have been created for something completely different. They are not a way to implement communication but to teach the command/handler framework variables to use in their expressions. Eclipse 4’s command/handler framework works ontop of the IEclipseContext so if you are using pure e4 technologies you simple annotate one of the methods in your handler-class with @CanExecute and it will be called by the framework for you.

  12. jazzelias says:

    Hi Tom,
    thanks a lot for the Tutorial. I am using Eclipse 3.7 and I am also getting the Null Pointer Exception:
    “java.lang.NullPointerException: A null service reference is not allowed. at org.eclipse.osgi.framework.internal.core.BundleContextImpl.getService(BundleContextImpl.java:586) at controllers.NewProjectHandler.sendEvent(NewProjectHandler.java:69) …”

    I am not quite sure if I understood it correctly where to put what dependency:
    1) I added “org.eclipse.osgi.services” to the “Required Plug-Ins” in the Dependencies tab of the plugin.xml
    2) I added “org.eclipse.equinox.ds” and “org.eclipse.equinox.event” to the “Plugins and Fragments” in the Dependencies tab of my xyz.product.
    3) manifest.mf: “Bundle-ActivationPolicy: lazy”

    Was this correct or what do you mean with Launch-Config and Product-Definition?

    Sorry for the newbie questions, but even after playing around with Eclipse 3.7 RCP for some months in my free time, the framework seems to me like a jungle. Everything is as complicated as it can be.

    I build my tool in 4.2 from scratch (4.2 was much easier to work with) but sadly GEF/Graphiti which I need, Isn’t ported yet.

    Thanks in advance
    Bjoern

    • Tom Schindl says:

      Yes they have to be in the .product-File only! If you had launched your product already before you need to Adjust your Run-Configuration (Run > Run Configurations) as well.

  13. Terry says:

    Terrific example, it works perfectly in our application when we run from inside the Eclipse IDE, however when I export our application as a deployable feature and create a top level JNLP, I get “null service reference is not allowed”. Top level JNLP contains:

    Client
    Me
    Client Application

    -nosplash

    Any ideas or suggestions would be greatly appreciated.

    • Tom Schindl says:

      Check that equinox.ds and equinox.event are exported and started appropriately

      • javadeveloper says:

        How the communication between Two RCP plugin takes place in which one plugin providing shell and other plugin gives insturction to create image within the shell provided by the first plugin. Is this thing possible in RCP communication or not

      • Tom Schindl says:

        This is not a help forum so please post your question to the eclipse forums.

  14. alex says:

    Very nice!
    But this does not work if your bundle-context changes due to installation/ removal of other packages.

    In this case you have to unget the service in the stop() method and re-register in start().

    RCP views will not be notified upon bundle-context change, therefore you will run into exceptions. My solution to this so far is to register the view as an event listener direcly to the Activator. This works since the view does not change itself on BundleContext change.

  15. Robin says:

    I have been doing this for awhile now, as I started with OSGi before I ever did any RCP. To make the RCP solution simpler, we created an EventCapableView to extend ViewPart. Then added methods for performing both UI and non UI operations as part of the event handling. We continually make more and more of our views event capable by using this class instead of ViewPart directly.

    In our case, we easily make some of these events distrubuted between clients by using an external messaging system (XMPP). The beauty of this is that all internal messaging is EventAdmin based, and if we make it distributed, it requires no extra coding at the UI level. Simply a adapter to exchange messages between EventAdmin and XMPP. Obvously other distributed messaging systems like JMS could also be used in the same fashion.

  16. tj says:

    view open -> close -> open
    org.eclipse.swt.SWTException: Widget is disposed

  17. Amar Mehta says:

    Hi, Can you please give some more example on view interaction. It was a great tut

    • Tom Schindl says:

      Not sure what examples you’d expect but I think the purpose of this communication strategy is well know and you should find enough resources on it on the web

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s