Monday, August 26, 2013

Preferences Browser plug-in

Another week, another tool: this time I developed a small utility to browse the preferences store.

The preferences dialog allows to conveniently edit user preferences. But there seems to be no easy way to find out which preference key is used for a dedicated dialog checkbox. Additionally not all preferences are customizable using the preferences dialog.

The Preferences Browser allows to view all available keys and automatically updates on any change. Editing support is available too, but use it with care as you might corrupt your preferences.

By enabling Track changes you can highlight changed keys while you are editing your preferences.


Finally you may export selected nodes and their values to a text file.

If you find this little tool useful you may install it directly from my update site:
http://codeandme.googlecode.com/svn/trunk/tools/com.codeandme.tools.releng.p2/update/


Wednesday, August 21, 2013

Event Broker Spy plug-in

As we had a look at the Event Broker just recently, I was wondering which types of events were published at all. So I wrote a little plug-in to keep track of them:


Hover over an event to see the event properties (as far as .toString() handles them).

By default it subscribes to all events, but you may narrow it down by providing a Filter string.


Try it out for yourself and grab it from my update site:

http://codeandme.googlecode.com/svn/trunk/tools/com.codeandme.tools.releng.p2/update/



Monday, August 5, 2013

Using the Event Broker without DI

The new EventBroker in e4 is a very handy tool to send events globally without the need to allow listeners to register. Listeners may subscribe to events on the event bus instead of finding an instance that supports addEventListener().

If you are running an E4 application you may directly inject the IEventBroker. If DI is not available you may consume the IEventBroker as a service, which works nicely for "old school" plug-ins that run within an e4 application.

Source code for this tutorial is available on googlecode as a single zip archive, as a Team Project Set or you can checkout the SVN projects directly.

Step 1: Creating an event publisher

Lets start with a fresh Plug-in Project named com.example.eventbroker. Then continue by creating a PublisherJob implementation:
package com.example.eventbroker;

import java.util.HashMap;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.ui.PlatformUI;

public class PublisherJob extends Job {

 private static int mCounter = 0;
 
 public PublisherJob() {
  super("Publisher");

  schedule();
 }

 @Override
 protected IStatus run(IProgressMonitor monitor) {
  Object service = PlatformUI.getWorkbench().getService(IEventBroker.class);
  if (service instanceof IEventBroker) {
   ((IEventBroker) service).post("com/example/eventbroker/basic", new Object());

   HashMap<String, Object> data = new HashMap<String, Object>();
   data.put("Event origin", "unknown");
   data.put("Event number", mCounter++);
   ((IEventBroker) service).post("com/example/eventbroker/advanced", data);
   schedule(1000);
   return Status.OK_STATUS;
  }
  
  return Status.OK_STATUS;
 }
}
Each posted event contains a topic and optional event data. Topics use hierarchies separated by slashes. If the data parameter is a Map it will be directly used for the event. If it is something else it will be wrapped inside a Map. So if you want to transport more than a single object use a Map<String, Object> to encapsulate your data.

To resolve IEventBroker you need to add a dependency to org.eclipse.e4.core.services. For the rest we additionally need org.eclipse.core.runtime and org.eclipse.ui.workbench.

The Job in the example will publish 2 events each second.

Step 2: Creating a subscriber

Create the Subscriber class:
package com.example.eventbroker;

import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.ui.PlatformUI;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;

public class Subscriber implements EventHandler {

 public Subscriber() {
  Object service = PlatformUI.getWorkbench().getService(IEventBroker.class);
  if (service instanceof IEventBroker) 
   ((IEventBroker) service).subscribe("com/example/eventbroker/*", this);
 }

 @Override
 public void handleEvent(Event e) {
  System.out.println("-------------------------------------------");
  System.out.println(e.getTopic());
  for (String name: e.getPropertyNames())
   System.out.println("\t" + name + ": " + e.getProperty(name));
 }
}
The subscriber subscribes to dedicated topics. Wildcards (*) may be used to subscribe to event groups. Subscribing to "*" will create notifications on any event.

e.getPropertyNames() may be used to retrieve the keys of the event data.

You need to add an additional dependency to org.eclipse.osgi.services to resolve EventHandler.

Step 3: Autostart our sample code

To run our little example we have to add an Activator:
package com.example.eventbroker;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.e4.core.services.events.IEventBroker;
import org.eclipse.ui.PlatformUI;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

 public void start(BundleContext bundleContext) throws Exception {

  Job job = new Job("Starting Publisher/Subscriber") {

   @Override
   protected IStatus run(IProgressMonitor monitor) {
    if (PlatformUI.isWorkbenchRunning()) {

     Object service = PlatformUI.getWorkbench().getService(IEventBroker.class);
     if (service instanceof IEventBroker) {
      // broker available, create publisher
      new PublisherJob();
      new Subscriber();
     }
     
    } else
     // workbench not running yet, try again in 1 second
     schedule(1000);

    return Status.OK_STATUS;
   }
  };

  job.schedule();
 }

 public void stop(BundleContext bundleContext) throws Exception {
 }
}
Basically a job runs continuously until the workbench is up and running. Afterwards we look for the Broker and create publisher and listener.

Register the Activator in your plugin.xml and set Auto-Start to true for com.example.eventbroker in your launch configuration.