Writing a Plugin

Preliminaries

This document explains how a plugin for Gravisto can be realized and how Gravisto's plugin mechanism works. Please ensure that your plugin package is in the classpath of Gravisto to give Gravisto a chance to find your plugin.
The project Graffiti_Guide_Examples available via cvs contains various plugin examples including the running example of this page.
The editor contains a plugin manager which is responsible for loading and instantiating a plugin. For loading a plugin a configuration file called plugin.xml is required.

The Plugin Description file

The plugin manager searches for plugin descriptions in the classpath. Plugin descriptions are XML files which contain meta informations about the plugin, e.g., author version, or dependencies to other plugins. A simple plugin.xml may look as the following:

<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE plugin
    PUBLIC "-//GRAFFITI/DTD Plugin Description 1.0//EN"
    "http://gravisto.fim.uni-passau.de/dtd/1.0/plugin.dtd">

<plugin>
    <author>chris</author>
    <description>Algorithm plugin test.</description>

    <plugindesc>
        <name>Algorithm Test Plugin</name>
        <main>
            de.chris.plugins.algorithms.test.AlgorithmTestPlugin
        </main>
        <version>0.0.1</version>
        <available></available>
    </plugindesc>
</plugin>
      

Please not that the main tag specifies the plugin's main class which will be written in the next section.

The Plugin Adapter

A plugin class has to implement the org.graffiti.plugin.GenericPlugin interface. A more convenient way of doing this is to extend the abstract class GenericPluginAdapter.

package de.chris.plugins.algorithms.test;

import org.graffiti.plugin.GenericPluginAdapter;
import org.graffiti.plugin.algorithm.Algorithm;

public class AlgorithmTestPlugin
    extends GenericPluginAdapter
{
    public AlgorithmTestPlugin()
    {
        this.algorithms = new Algorithm[1];
        this.algorithms[0] = new AlgorithmTest();
    }
}
      

One plugin can contain more than one algorithm or other components. Therefore (in the case of an algorithm plugin) the member array algorithms is overwritten and filled with one ore more algorithm instances which do the actual work. For other kinds or mixed types of plugins different arrays exists. For further information on that have a look on the details of the respective plugin kind.

The Algorithm

To complete the example plugin above, it remains to show how the working class should look like. In this case it is a class which implements AbstractAlgorithm.

package de.chris.plugins.algorithms.test;

import java.awt.geom.Point2D;
import org.graffiti.attributes.Attribute;
import org.graffiti.graph.Node;
import org.graffiti.graphics.CoordinateAttribute;
import org.graffiti.graphics.GraphicAttributeConstants;
import org.graffiti.plugin.algorithm.AbstractAlgorithm;
import org.graffiti.plugin.algorithm.PreconditionException;
import org.graffiti.plugin.parameter.IntegerParameter;
import org.graffiti.plugin.parameter.Parameter;

/**
 * @author chris
 * An implementation of a simple algorithm plugin example which generates a
 * horizontal node chain with a user defined number of nodes.
 */
public class AlgorithmTest extends AbstractAlgorithm
{
    private IntegerParameter nodesParam;

    public AlgorithmTest()
    {
        nodesParam =
            new IntegerParameter(
                5,
                "number of nodes",
                "the number of nodes to generate");
    }

    public String getName()
    {
        return "Test Graph Algorithm";
    }

    public Parameter[] getParameters()
    {
        return new Parameter[] { nodesParam };
    }

    public void check() throws PreconditionException
    {
        PreconditionException errors = new PreconditionException();

        if (nodesParam.getInteger().compareTo(new Integer(0)) < 0)
        {
            errors.add("The number of nodes may not be smaller than zero.");
        }

        // The graph is inherited from AbstractAlgorithm.
        if (graph == null)
        {
            errors.add("The graph instance may not be null.");
        }

        if (!errors.isEmpty())
        {
            throw errors;
        }
    }

    public void execute()
    {
        int n = nodesParam.getInteger().intValue();

        Node[] nodes = new Node[n];

        // start a transaction
        graph.getListenerManager().transactionStarted(this);

        // generate nodes and assign coordinates to them
        for (int i = 0; i < n; ++i)
        {
            nodes[i] = graph.addNode();

            CoordinateAttribute ca =
                (CoordinateAttribute) nodes[i].getAttribute(
                    GraphicAttributeConstants.GRAPHICS
                        + Attribute.SEPARATOR
                        + GraphicAttributeConstants.COORDINATE);

            double x = 100 + i * 100;
            double y = 100;

            ca.setCoordinate(new Point2D.Double(x, y));
        }

        // add edges
        for (int i = 1; i < n; ++i)
        {
            graph.addEdge(nodes[i - 1], nodes[i], true);
        }

        // stop a transaction
        graph.getListenerManager().transactionFinished(this);

        // add arrows to edges
        graph.setDirected(true, true);
    }

    public void reset()
    {
        graph = null;
        nodesParam.setValue(new Integer(5));
    }
}
      

For further details about this class see section Writing an Algorithm Plugin.
Plugin.jar contains all files from the above example and can be used as a base for writing own plugins.

Packaging Plugins

Before distributing a plugin for Gravisto it is recommended to group all the files in a single jar archive. In the case of the above example the structure of this jar file is as follows:

de/
de/chris/
de/chris/plugins/
de/chris/plugins/algorithms/
de/chris/plugins/algorithms/test/
de/chris/plugins/algorithms/test/AlgorithmTest.class
de/chris/plugins/algorithms/test/AlgorithmTestPlugin.class
de/chris/plugins/algorithms/test/plugin.xml
      

To use this plugin, the jar file must be in the JAVA classpath before starting the Gravisto editor. Afterwards the menu item Plugin > Open Plugin Manager opens a graphical manager whose Search for plugins... button should find the plugin in the jar file. After adding this plugin it is available in the editor, e.g., an algorithm plugin appears under the Plugin menu.

Different Kinds of Plugins