Article    Discussion    Edit    History

Turning that "Hello World!" plug-in into something a little more useful

Jump to: navigation, search

Now that we have the shell of a plug-in, let's make it do something interesting. OK, this example isn't too interesting, but it will give you the idea.

Whenever the user searches for a person in Genesis, a search objective is placed in the research manager. Our plug-in will listen for new search objectives and satisfy them with fictional people. A real plug-in would work just the same, except that instead of making up people, it would search for data from real data sources.

[edit] Activator

The Activator class provides basic services for your plug-in. Of particular interest are the methods start() and stop(). These methods are called when your plug-in is starting up and shutting down, respectively. They just so happen to be a great place to start and stop listening for new search objectives.

In order to get access to the research manager, we'll need to create a dependency in our plug-in on the Eclipse UI and Genesis Core plug-ins. To do this, open the "MANIFEST.MF" file (it should be under "com.example.myplugin.core/META-INF" in the Package Explorer). Opening this file will show the "Plug-in Manifest" editor, which provides several shortcuts for changing plug-in settings. You are of course welcome to edit the file directly by clicking the "MANIFEST.MF" tab at the bottom, but why make things harder on yourself?

Plug-in Manifest Editor

Click on the "Dependencies" tab. This will bring up the list of required plug-ins on the left (which only lists "org.eclipse.core.runtime" at this time). Click "Add" and select both "org.dftproject.genesis.core" and "org.eclipse.ui". Then save and close the editor.

Now open "Activator.java" (it should be under "com.example.myplugin.core/src/com.example.myplugin.core" in the Package Explorer). Modify it so that it looks like this:

package com.example.myplugin.core;
 
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
 
import org.dftproject.genesis.core.data.DataManager;
import org.dftproject.genesis.core.data.DataView;
import org.dftproject.genesis.core.data.simple.Individual;
import org.dftproject.genesis.core.data.simple.Source;
import org.dftproject.genesis.core.research.IFamilyListener;
import org.dftproject.genesis.core.research.IResearchListener;
import org.dftproject.genesis.core.research.Objective;
import org.dftproject.genesis.core.research.ResearchListenerAdapter;
import org.dftproject.genesis.core.research.ResearchManager;
import org.dftproject.genesis.core.research.Task;
import org.dftproject.genesis.core.research.TaskFamily;
import org.dftproject.genesis.core.search.SearchObjective;
import org.dftproject.genesis.core.search.query.Query;
import org.dftproject.genesis.core.search.query.QueryAnd;
import org.dftproject.genesis.core.search.query.QueryCriteria;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.swt.graphics.Image;
import org.osgi.framework.BundleContext;
 
/**
 * The activator class controls the plug-in life cycle
 */
public class Activator extends Plugin {
 
	// The plug-in ID
	public static final String PLUGIN_ID = "com.example.myplugin.core";
 
	// The shared instance
	private static Activator plugin;
 
	// Our research listener
	private IResearchListener researchListener;
 
	// Our task families
	private final Set families = new HashSet();
 
	/**
	 * The constructor
	 */
	public Activator() {
	}
 
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;
 
		// Create our research listener
		researchListener = new ResearchListenerAdapter() {
			@Override
			public void objectiveAdded(final Objective objective) {
				if (objective instanceof SearchObjective) {
					// Create a new task family to group any tasks we create to
					// handle the search objective
					TaskFamily family = new TaskFamily(objective) {
						public String getDescription() {
							return "My Plug-in";
						}
 
						public Image getIcon() {
							return null;
						}
					};
 
					// Clean up after this task family when it's done
					family.addListener(new IFamilyListener() {
						public void finished(TaskFamily family) {
							families.remove(family);
						}
					});
 
					// Track this task family
					families.add(family);
 
					// Associate this task family with the search objective
					objective.addTaskFamily(family);
 
					// Create a task to handle the search objective
					Task task = new Task(family) {
						public String getDescription() {
							return "My Plug-in Task";
						}
 
						public Image getIcon() {
							return null;
						}
 
						public void run() {
							// Take what the user typed in and use it for the name
							String name = ((SearchObjective) objective).getQuery().getSource();
 
							// Get a view on the data store
							DataView view = DataManager.getDefault().getView();
 
							// Create/get a source representing our plug-in
							Source source = new Source(view.getResource("urn:com.example.myplugin"), null);
 
							// Create a person
							Individual person = new Individual(view.getResource("urn:person:"+name.hashCode()), source);
							person.addName(name, source);
						}
					};
 
					// Associate this task with the task family
					family.addTask(task);
 
					// Get to work on the task
					task.start();
				}
			}
		};
 
		// Start listening
		ResearchManager.getDefault().addListener(researchListener);
	}
 
	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		// Cancel all currently running task families
		Iterator iter = families.iterator();
		while (iter.hasNext()) {
			((TaskFamily) iter.next()).cancel();
			iter.remove();
		}
 
		// Stop listening
		ResearchManager.getDefault().removeListener(researchListener);
 
		plugin = null;
		super.stop(context);
	}
 
	/**
	 * Returns the shared instance
	 * 
	 * @return the shared instance
	 */
	public static Activator getDefault() {
		return plugin;
	}
 
}

Whenever the plug-in is notified of a search objective, it creates a task family. A task family is a logical grouping of tasks that are working to satisfy the objective. It then creates a task which does the actual work. In this example, it simply adds an individual to the data store with the same name as what was searched for. This new individual is detected by the search view and displayed to the user.

[edit] Startup

But wait, when I run Genesis at this point, the plug-in doesn't do anything! Why?

Well, because plug-ins are loaded lazily; until some other part of Genesis calls specifically on our plug-in to do something, it won't get loaded. To get around this, we'll force our plug-in to load when Genesis starts up.

To do this, open the "Plug-in Manifest" editor as described above and click the "Extensions" tab at the bottom. Then click "Add", select "org.eclipse.ui.startup", and click "Finish". This will create a "plugin.xml" file which, like the "MANIFEST.MF" file, describes the plug-in. You'll see a new tab at the bottom labeled "plugin.xml". Click this tab to see the contents of the "plugin.xml" file:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
   <extension
         point="org.eclipse.ui.startup">
   </extension>
 
</plugin>

Add a startup extension like so:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.2"?>
<plugin>
   <extension
         point="org.eclipse.ui.startup">
      <startup
            class="com.example.myplugin.core.Startup">
      </startup>
   </extension>
 
</plugin>

Then create the com.example.myplugin.core.Startup class. The easiest way to do this is to right-click "Activator.java" in the Package Explorer and click "New", then "Class". Type "Startup" for the name. Click "Add" next to the "Interfaces" section, type "IStartup", select the only item that comes up, click "Add", then click "OK". Finally click "Finish". This will create our startup class. We don't need to add any code to it, we just need it to exist.

Now we can run Genesis and see our (mostly) useless plug-in at work. Yay!

Retrieved from "http://www.dftproject.org/wiki/Turning_that_%22Hello_World%21%22_plug-in_into_something_a_little_more_useful"