Hello World Plugin-in Example

The JLense platform is structured as a core runtime engine and a set of additional features that are installed as platform plug-ins. Plug-ins contribute functionality to the platform by contributing to pre-defined extension points. The workbench UI is contributed by one such plug-in. When you start up the workbench, you are not starting up a single Java program. You are activating a platform runtime which can dynamically discover registered plug-ins and start them as needed.

When you want to provide code that extends the platform, you do this by defining system extensions in your plug-in. The platform has a well-defined set of extension points - places where you can hook into the platform and contribute system behavior. From the platform's perspective, your plug-in is no different from basic plug-ins like the resource management system or the workbench itself.

So how does your code become a plug-in?

  • Decide how your plug-in will be integrated with the platform.
  • Identify the extension points that you need to contribute in order to integrate your plug-in.
  • Implement these extensions according to the specification for the extension points.
  • Provide a manifest file (plugin.xml) that describes the extensions you are providing and the packaging of your code.

Creating a plug-in is best demonstrated by implementing an old classic, "Hello World," as a plug-in. We'll gloss over some details at first in order to get it running. Then we'll look at extension points in more detail, see where they are defined, and learn how plug-ins describe their implementation of an extension.

A minimal plug-in

We all know what "Hello World" looks like in plain old Java without using any user interface or other framework.

   public class HelloWorld {
      public static void main(String[] args) {
         System.out.println("Hello World");
      }
   }

What happens to this old standard in the context of the JLense platform? Instead of thinking of Hello World as a self-contained program, we recast it as an extension of the platform. Since we want to say hello to the world, we need to figure out how to extend the workbench to include our greeting.

When we get deeper into the platform user interface components, we'll do an exhaustive review of the ways that you can extend and customize the workbench UI. For now, let's start with one of the simplest workbench extensions - a view.

You can think of the workbench window as a frame that presents various views. Views provide information about some object that the user is working with in the workbench. Views often change their content as the user selects different objects in the workbench.

Create the folders we need to get started

We are going to create a new plugin that will contribute a new view to the workbench. The first step in creating a new plugin is to create a directory that will hold all the files and artifacts associated with the plugin.

The JLense platform installation is structured in the same way that a JLense application is structured except that the JLense platform comes with extra files and directories that contain source, build and testing artifacts that allow you to build JLense and its sample applications from scratch.

The JLense platform comes with a simple command-line build system based on Ant. This example will walk you through the process of building our plugin using any text editor and the JLense build system. You can use any Java IDE you wish to build JLense plug-ins but the details of using any particular IDE are not covered here. (Note: the JLense platform comes with Eclipse project set files in its root directory so it's trivial to load the JLense platform project into Eclipse and start working).

There are three basic steps to creating a new plugin thats works well with JLense build system...

  1. Create a new plugin directory and plugin manifest file.

    We must first create a plugin directory to contain the plugin manifest, source files, class files, and any other required resources. This step has already been done for you, the directory is jlense/eclipse/plugins/org.jlense.examples.

    Underneath the jlense/eclipse/plugins/org.jlense.examples directory we have also created a plugin manifest file named "plugin.xml". Plugin-in manifest files are always named plugin.xml.

    Every plugin declares an id in its manifest file. When you create a source directory for a new plugin it is good practice to name the directory after the plugin id. In our case we are going to give the Hellow World plugin an id of org.jlense.examples. Therefore we created a directory named org.jlense.examples and will set the plugin id (declated at the top of plugin.xml) to 'org.jlense.examples'.

  2. Create a new source directory and build file.

    Create a directory for source files underneath the plugin directory. Create a directory named src and under the src directory create sub-directories for the Java packages that will be contained in your plugin. This step has already been done for you. We have created the src/org/jlense/examples/hello directory underneath the jlense/eclipse/plugins/org.jlense.examples directory.

  3. Create a new build file and hook it into the 'master' build.

    JLense comnes with Ant build files that build and configures the platform as well as any and all plugins. The Ant build system is driven by XML files. The default name of a build file is always build.xml. Generally the best way to create a new Ant build file for a new JLense plugin is to copy an existing build file and change a few items at the top. We have already done this for you. We copied an existing build file to jlense/eclipse/plugins/org.jlense.examples/build.xml and changed the following items at the top...

    1. Changed the project name to the name of your plugin
    2. Changed the value of the plugin.name property to the name of your plugin
    The top of the build.xml file now looks like this:

    <project name="org.jlense.examples" default="all" basedir="./">
              <property name="plugin.name" value="org.jlense.examples"/>

    To get the "master" build file to recognise your new plugin you must add an entry into the build.xml file located at the root of the JLense platform directory structure. We have already done this step for you. We added the following line to the build.xml file in the root directory that will invoke the build.xml in your new source directory whenever an Ant build command is issued...

    <ant antfile="jlense/eclipse/plugins/org.jlense.examples/build.xml" 
         target="${ant.target}"/>
                    

That's it! We hope that wasn't too bad :-). Now you're ready to rock.

Hello world view

For our hello world plug-in, we will implement our own view to greet the user with "Hello World."

The package org.jlense.uiworks and its sub packages contain the public interfaces that define the workbench user interface (UI) API. Many of these interfaces have default implementation classes that you can extend to provide simple modifications to the system. In our hello world example, we will extend a workbench view to provide a label that says hello.

The interface of interest is IViewPart, which defines the methods that must be implemented to contribute a view to the workbench. The class ViewPart provides a default implementation of this interface. In a nutshell, a view part is responsible for creating the components needed to show the view.

The class OutlookPart provides a slightly fancier implementation of the IViewPart interface so we'll actually use this implementation class. Among other things, the names of OutlookParts are automagically added to the workbench title when those parts have the focus.

The standard views in the workbench often display some information about an object that the user has selected or is navigating. Views update their contents based on actions that occur in the workbench. In our case, we are just saying hello, so our view is quite simple.

Writing the code

Now we're ready to study some code. Here is everything you need in your HelloWorldView.

package org.jlense.examples.hello;

import javax.swing.JComponent;
import javax.swing.JLabel;

import org.jlense.uiworks.part.OutlookPart;

public class HelloWorldView  extends OutlookPart
{
    public JComponent createPartControl()
    {
        return new JLabel("Hello World");
    }

}

The view part creates the widgets that will represent it in the createPartControl method. In this example, we create a label that displays the phrase "Hello World".

This is all we need! We can now compile our class, and create our plugin jar file. To compile, simply run this command from the JLense startup directory:

run-ant build-all

Okay, so we've now build the org.jlense.examples plugin.

How do we add this view to the workbench and run the code?

The hello world plug-in

We need to inform the platform that we want to contribute our view. This is done by extending the org.jlense.uiworks.views extension point. We register our extension by providing a manifest file, plugin.xml, which describes our plug-in, including where its code is located, and the extension we are adding.

This step has also already been done for you. A plugin.xml file has been created in the jlense/eclipse/plugins/org.jlense.examples folder. Here are the contents of that file:

<?xml version="1.0" encoding="UTF-8"?>
<plugin
   id="org.jlense.examples"
   name="JLense Examples"
   version="1.0.0"
   provider-name="jlense.org">

<requires>
   <import plugin="org.jlense.uiworks"/>
</requires>

<runtime>
   <library name="./classes/"><export name="*"/></library>
</runtime>


<!-- add workbench views  -->
<extension point="org.jlense.uiworks.views">
    <view
        name="Hello World"
        class="org.jlense.examples.hello.HelloWorldView"
        id="org.jlense.examples.hello.HelloWorldView"
        showTitleBar="false"  />
</extension>

<!-- create perspectives for example applications  -->
<extension  point="org.jlense.uiworks.perspectives">

    <!-- A perspective category for the JLense example applications.  -->
    <category name="&Examples" id="org.jlense.examples" />

    <perspective id="org.jlense.examples.helloworld"
        name="Hello World"
        class="org.jlense.uiworks.part.EmptyPerspective"
        category="org.jlense.examples"
        availableAsShortcut="true"
        />

</extension>


<!-- add views to perspectives  -->
<extension point="org.jlense.uiworks.perspectiveExtensions">

    <perspectiveExtension targetID="org.jlense.examples.helloworld">

        <actionSet id="org.jlense.uiworks.standardPerspectiveActions"/>
        <view id="org.jlense.examples.hello.HelloWorldView" />

    </perspectiveExtension>

</extension>

</plugin>

In this file, we define the name, id, and version for our plug-in.

We also list our required plug-ins. Since we use the JLense workbench in our plug-in, we must list org.jlense.uiworks. We must also describe where our executable code is located. The code for our plugin is under the classes directory so we register that as our library name.

We also declare views that our plug-in is contributing. In this example we are contributing the Hello World view that we implemented above. The org.jlense.uiworks.views extension has several different configuration parameters. We declare a unique id for our view and specify the name of the class that provides the implementation of the view. We also specify a name for the view, "Hello World" which will be shown in the view's title bar.

Here's a little background to explain the final few declarations. Views are contributed to the workbench by adding the view to some existing perspective. Perspectives are contributed to the workbench via an org.jlense.uiworks.perspectives extension definition in a plugin manifest file. Views are added to perspectives by via an org.jlense.uiworks.perspectiveExtensions extension declaration in a plugin manifest file. Finally, a shortcut to a perspective may be added to the Workbench Shortcuts Bar via an org.jlense.uiworks.perspectiveExtensions extension declaration in a plugin manifest file.

So, in our plugin manifest above:

  • We first declare a new perspective to hold our new view with a org.jlense.uiworks.perspectives extension definition. We use
  • then we add our new view to the new perspective via an org.jlense.uiworks.perspectiveExtensions extension declaration.
  • and then we want to add our new perspective to the Workbench Shortcuts Bar via an org.jlense.uiworks.perspectiveExtensions extension declaration.

Run the JLense Workbench

We're ready to run the workbench and take a look at our view!

To run the default JLense workbench run this command from the JLense startup directory: start-jlense-workbench

After the workbench starts click on the icon in the shortcuts window that say "Hello World" and the Hello World window will be displayed. The workbench should look something like this (the application was resized so that its image would fit in the documentation better):

Plug-in ids

There are many ids used in a plug-in manifest file. Individual extension points often define configuration parameters that require ids (such as the category id used above for the views extension point). We also define a plug-in id. In general, you should use Java package name prefixes for all of your ids in order to ensure uniqueness among all the installed plug-ins.

The specific name that you use after the prefix is completely up to you. However, if your plug-in id prefix is exactly the same name as one of your packages, you should avoid using class names from that package. Otherwise it will become difficult to tell whether you are looking at an id name or a class name.

You should also avoid using the same id for different extension configuration parameters. In the above manifest, we have used a common id prefix (org.jlense.examples.hello) but all of our ids are unique. This naming approach helps us to read the file and see which ids are related.