Page tree
Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 46 Next »

This article demonstrates the IGB plug-able architecture using a simple example plugin that adds a menu item to the IGB Tools menu.

Introduction

IGB runs within an OSGi framework, also called the OSGI "container" or "runtime." This means you can easily extend IGB without modifying the core IGB code base. By implementing a few well-described interfaces and using the Apache maven project management tool, you can add new menu items, create new kinds of tracks, or connect IGB to all-new data sources - all without re-installing or even re-starting IGB.

This tutorial introduces the IGB platform by demonstrating a very simple IGB App that adds a new entry to the IGB Tools menu. 

Clone IGB Hello World App

Clone the IGB Hello World App project - this contains complete, working example of the Hello World IGB App:

git clone https://bitbucket.org/lorainelab/igb-app-hello-world.git

 

 


Compile the App

To build your App, open the igb-app-hello-world project into Netbeans, select it project in the Projects tab, and then select Run > Build.

Alternatively, you can build it from the command line by entering:

mvn clean install

Building the App will create a new directory named "target" which can serve as a new App repository. This new directory contains compiled code as well as a meta-data about the App it contains.

Add target directory as new App repository

Normally, Apps are deployed on-line via an App Store or your own on-line App repository.

However, you can also deploy an App Store on your local computer - useful for developing and testing new Apps.

To add your target directory as a local App Store:

  1. Start IGB
  2. Select Tools > Open App Manager
  3. Click Manage Repositories... button (opens Plug-in Repositories tab in Preferences window)
  4. Click Add... button (opens Plugin Repository dialog)
  5. Enter a name for your repository (can be anything)
  6. Click Choose local folder button
  7. Select "target" in your igb-app-hello-world project folder

Once you add "target" as a new local App store, you should see the Hello World App added as a new App in the IGB App Manager window, as show below;

Install App

To install the hello world App:

  • Select Tools > Open App Manager
  • Select the App
  • Click Install

To check that installation worked correctly, select the Tools menu. Check that there is  now a new menu item named Hello World App.

Run App

To run the App:

  • Select Tools > Hello World App
  • Observe a dialog appears containing the message "Hello IGB World!"

 

Observe the message that appears:

 

Next step: Modify your code

Re-open your IGB App project. Edit the message your IGB App prints and re-build your App. Then, return to the IGB App Manager, un-install and then re-install your App. When you select the the menu item again, the new message will print instead of the old one.

Note that you can rapidly repeat this edit-build-uninstall-install cycle. You don't have to re-build IGB or even restart it, which makes development much faster than if you had to modify the IGB code directly.

Next step: Make README.md for your App (optional)

It's not enough to create and deploy an App; you should also provide an easy-to-understand README.md file suitable for display in the IGB App Manager. See Create Markdown to display in IGB App Manager

How this works

Apps can interact with and add new functionality to IGB by implementing services defined by the IGB API. In other words, Apps that implement services recognized by the IGB API, then IGB can automatically consume those services and provide them as new functionality for users.

The Hello World App contains a class that implements the MenuBarEntryProvider interface:


MenuBarEntryProvider interface
public interface MenuBarEntryProvider {
    public Optional<List<MenuItem>> getMenuItems();
	public MenuBarParentMenu getMenuExtensionParent();
 }

 

The Hello World App uses a specialization of the maven build system to package the Hello World App as a so-called "OSGi" bundle that can be added or removed dynamically from the OGSi run-time that runs IGB.

When you compile the App and add its "target" directory as a new local App store (plug-in repository) to IGB, the OSGi run-time detects the repository and adds all its Apps as optional Apps to the IGB App Manager interface. Then, when you install the App, the OSGi runtime then exposes its services to IGB.

The MenuBarEntryProvider is one such service; any App that provides this service - by implementing this interface - can therefore add new menus to IGB once they are installed into the run-time.

 

Using maven to develop Apps - the App directory structure

The Maven build system assumes that every Java project conforms to an expected directory structure. Here, the maven project includes

  • pom.xml - located at the top level of the project. In IGB, an App's pom.xml file specifies which services the App needs to import from the IGB code base as well as any 3rd party libraries used by your App.
  • src - contains source code, organized as shown. Every maven project contains src/main/java, which contains java packages organized as directories in the usual way. The example shows a single Java source code file/

To see the directory structure for your project in NetBeans, select the Files tab (next to the Projects tab).

HelloWorld pom.xml

The pom.xml file is the fundamental unit of work in the Maven build tool. The pom.xml contains information about the project and configuration details used by Maven to build the project. 


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.affymetrix</groupId>
        <artifactId>igb-project</artifactId>
        <version>9.0.0</version>
    </parent>
    <groupId>org.lorainelab.igb</groupId>
    <artifactId>org.lorainelab.igb.menu.api.example</artifactId>
    <version>1.0.0</version>
    <packaging>bundle</packaging>

    <name>IGB Menubar Extension</name>
    
    <dependencies>
        <dependency>
            <groupId>biz.aQute.bnd</groupId>
            <artifactId>bndlib</artifactId>
            <scope>provided</scope>
        </dependency>
          <dependency>
            <groupId>org.lorainelab.igb</groupId>
            <artifactId>org.lorainelab.igb.menu.api</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <id>build plugin repository</id>
                        <goals>
                            <goal>
                                index
                            </goal>                       
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <obrRepository>${project.build.directory}</obrRepository>    
                            <mavenRepository>${project.build.directory}</mavenRepository>                      
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <instructions>
                       <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Import-Package>*</Import-Package>
                        <Export-Package/>
                        <Service-Component>*</Service-Component>
                    </instructions>
                </configuration>
            </plugin>     
        </plugins>
    </build>
</project>

parent tag

The parent tag specifies which version of IGB your new App is compatible with. It also enables your project to inherit configurations from the parent pom.xml file, which will save you time and effort.
The version found in the parent tag of the App's pom.xml should match the version tag found in the IGB pom.xml at the top level of your cloned IGB project.
For example, if the IGB pom.xml contains version tag equal to 9.0.0, then the parent tag of the App's pom.xml should match the tag below.
<parent>
    <groupId>com.affymetrix</groupId>
    <artifactId>igb-project</artifactId>
    <version>9.0.0</version>
</parent>


In the image below, you can see that the IGB version of 9.0.0 is seen in the app's pom.xml.


packaging tag

This tag specifies packaging type - e.g., war or jar. In IGB, we use an OSGi-specific packaging structure called a "bundle," which is a jar file with additional metadata. This additional metadata transforms an ordinary jar file into a plug-able module in the OSGi runtime. The IGB project uses the Apache Felix Maven Bundle plugin (BND) to generate this metadata. The BND bundle defines the packaging type "bundle."

<packaging>bundle</packaging>

name tag

This should be a user-friendly name for your App suitable for display in the IGB App Manager list of available Apps. This tag is optional; if you don't include it, then the App Manager will list your App's artifactId.

pom.xml
<name>IGB Menubar Extension</name>

dependency tags (parent tag "dependencies")

The term "dependency" just means: third-party resources your project requires to compile and run, such as library files.

Your pom.xml file should contain a single "dependencies" tag with several "dependency" child tags:

Dependencies and dependency tags
<dependencies>
	<dependency>...</dependency>
	<dependency>...</dependency>
</dependencies>

biz.aQute.bnd:bndlib

This dependency enables the Declarative Services annotations used within the IGB code base that allow easy service consumption and registration with the IGB OSGi component runtime.

Note how that scope tag is "provided" - this is because the parent pom.xml file defines this dependency in its dependencyManagement tag. When mvn compiles your App, mvn will retrieve necessary metadata about the dependency, such as its version and other information, from the parent pom. 

<dependency>
   <groupId>biz.aQute.bnd</groupId>
   <artifactId>bndlib</artifactId>
   <scope>provided</scope>
</dependency>

org.lorainelab.igb

This dependency is the igb menu api module containing the MenuBarEntryProvider interface used in our code.

<dependency>
    <groupId>org.lorainelab.igb</groupId>
    <artifactId>org.lorainelab.igb.menu.api</artifactId>
    <scope>provided</scope>
</dependency>

build, plugins, and plugin tag

maven-bundle-plugin

This is the most important plugin to be aware of as an IGB module developer.  This plugin is known as the "Swiss army knife of OSGi" and is a wrapper around the BND project described in the previous section.

	<build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <id>build plugin repository</id>
                        <goals>
                            <goal>
                                index
                            </goal>                       
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <obrRepository>${project.build.directory}</obrRepository>    
                            <mavenRepository>${project.build.directory}</mavenRepository>                      
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <instructions>
                       <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Import-Package>*</Import-Package>
                        <Export-Package/>
                        <Service-Component>*</Service-Component>
                    </instructions>
                </configuration>
            </plugin>     
        </plugins>
    </build>

There are several important things to understand about the above configuration.

  • This plugin is responsible for generating all of the OSGi metadata required to build your App "artifact" - a jar file with metadata making it into an OSGi module.
    • The metadata can optionally include service component definition files as described in the OSGi Declarative Services Specification (See http://wiki.osgi.org/wiki/Declarative_Services for more information)
    • We use annotations in our java code which are processed at compile time by the felix maven bundle plugin to generate the service component definition files for a bundle.
  • This plugin is also configured above in the "build plugin repository" execution to generate OBR (Object Bundle Repository) metadata in the build directory (i.e. the target directory) of the project. This directive is useful because it allows you to add your App's target directory as a local App Store (plugin repository) to IGB so that you can run your new App

 

This deployment mode will allow you to install and un-install your App bundle without having to restart IGB. This means you can make changes to your IGB App, recompile it, and then simply re-install it without restarting IGB. This is why we now call IGB a programming "platform" - it functions like a development environment. Like any good development tool, you don't have to restart it to run new code. 


Creating a new Java class (MenuBarExtensionExample)

The Hello World IGB App from the completed project example uses a Java class called MenuBarExtensionExample. If you wish to create this class yourself, you can do so in Netbeans by following the instructions below.

  1. Within NetBeans, check that your IGB Menubar Extension project is the currently selected project. If it isn't, select File > Open Project to open it.
  2. Next, create a new Java class named MenuBarExtensionExample:
    • Select File > New File
    • Select Java Class as your file type.
    • Select Next
    • Enter class Name MenuBarExtensionExample
    • Select package org.lorainelab.igb.menu.api.example
    • Select Finish

 

Your newly created class should match the code seen below:

 

MenuBarExtensionExample
package org.lorainelab.igb.menu.api.example;
import aQute.bnd.annotation.component.Component;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import javax.swing.JOptionPane;
import org.lorainelab.igb.menu.api.MenuBarEntryProvider;
import org.lorainelab.igb.menu.api.model.MenuBarParentMenu;
import org.lorainelab.igb.menu.api.model.MenuItem;
@Component(immediate = true)
public class MenuBarExtensionExample implements MenuBarEntryProvider {

    @Override
    public Optional<List<MenuItem>> getMenuItems() {
        MenuItem menuItem = new MenuItem("Hello World App", (Void t) -> {
            JOptionPane.showMessageDialog(null, "Hello IGB World!");
            return t;
        });
        menuItem.setWeight(1000000000);
        return Optional.ofNullable(Arrays.asList(menuItem));
    }

    @Override
    public MenuBarParentMenu getMenuExtensionParent() {
        return MenuBarParentMenu.TOOLS;
    }
}

 

If you need help with this process or wish to discuss any other issues with the IGB team, please do not hesitate to contact us.

 

  • No labels