Creating a Plugin   Currently, the list of available plugins is provided on demand by a jabber client with JID (simlink@buddyspace.org). This jabber bot client must be running in order to use the SimLink system.

The BuddySpace client issues a request to simlink@buddyspace.org whenever a list of SimLink plugins is required. The current implementation of the SimLink bot needs to be rebuilt and restarted in order to add to the list of available SimLink plugins. The BuddySpace client does not need modification in order to add to the list of available plugins because both the list and the plugins themselves are retrieved on-demand.

Here is an extract from SimLinkManger.java showing the currently available plugins, their titles, java class names and download location.
    private static Plugin plugins[] =
    {
    new Plugin(
    "Global warming and cooling",
    "edu.ou.kmi.simlink.plugins.globalwarming.GlobalWarming",
    "http://buddyspace.org/simlink/globwarm.jar"),
    new Plugin(
    "Web Browser",
    "edu.ou.kmi.simlink.plugins.webbrowser.LinkedWebBrowser",
    "http://buddyspace.org/simlink/browser.jar"),
    new Plugin(
    "Are you ready for S269?",
    "AppletMain",
    "http://buddyspace.org/simlink/s269.jar"),
    new Plugin(
    "Chess Board",
    "edu.ou.kmi.simlink.plugins.chessboard.ChessBoard",
    "http://buddyspace.org/simlink/chess.jar"),
    new Plugin(
    "4x4 Puzzle",
    "edu.ou.kmi.simlink.plugins.puzzle.Puzzle",
    "http://buddyspace.org/simlink/puzzle.jar")
    };
It would be fairly straightforward to modify SimLinkManager.java so that list is retrieved from a more dynamic source such as a database.

Create a plugin

I'll assume here that the reader is familiar with java programming and the creation of JAR files to deploy compiled code.

A vanilla plugin

If we don't need the plugin to be synchronised in a group chat environment, there's basically not much to do apart build a java component by extending from any class that has class java.awt.Component as one of its ancestors. In a typical case I would expect the usual class you would choose to extend was javax.swing.JPanel, but virtually any user interface component should work as well. e.g.
    package mypackage;
    class MyPlugin extends javax.swing.JPanel {
    public MyPlugin()
    {
    add(new javax.swing.JButton("hello world"));
    }
    }
The full class name of your extending class must be added to the list of plugins, e.g. in the example above you'd need to add mypackage.MyPlugin to the list.

A synchronised (yoked) plugin

In order to provide a mechanism for passing state information between users in a group chat environment, you are required to implement the methods of a very simple java interface called SimLinkPlugin. The example below shows how the linked web browser plugin was implemented.
    package edu.ou.kmi.simlink.plugins.webbrowser;

    import java.awt.*;

    import edu.ou.kmi.simlink.system.*;

    public class LinkedWebBrowser extends WebBrowser implements SimLinkPlugin
    {
    // This method will be called by BuddySpace and your implementation
    // must return component instance that is to be displayed.
    public Component createGUI(String userID)
    {
    return this;
    }

    // When the plugin changes to state that you requires synchronisation
    // with other users, your implementation of this method must return
    // a string representing the absolute state of the application.
    // In this case, we just need to send the URL, but can be more complex
    // data, such as the parameters of a simulation.
    public String getPackedParameters()
    {
    // Note that we add the classname as a prefix to the
    // parameters so we can rely on the setPackedParameters
    // method to filter out parameters intended for other
    // plugins.
    return getClass().getName() + "=" + address.getText();
    }

    // Your implemtation of this method must set the plugin to the
    // desired state based on the parameter string that it receives.
    public void setPackedParameters(String parameters)
    {
    if (parameters == null || parameters.length() == 0) return;

    // Check parameters belong to this plugin
    if (!parameters.startsWith(getClass().getName() + "=")) return;

    // Inorder to prevent a recursive loop, we need to
    // prevent state changes from being propogated during
    // a 'synched' update of the plugin. In this case we temporarily
    // disable the change listener whilst updating the page.
    ParameterChangeListener oldListener = parameterChangeListener;
    parameterChangeListener = null;
    setPage(parameters.substring(getClass().getName().length() + 1), true);
    parameterChangeListener = oldListener;

    }

    private ParameterChangeListener parameterChangeListener = null;

    // Whenever state changes in your plugin that requires synchronisation,
    // your plugin must call the parameterChanged method of the listener
    // provided by this method.
    public void setParameterChangeListener(ParameterChangeListener listener)
    {
    parameterChangeListener = listener;
    }

    // This method overrides the setPage method of the underlying WebBrowser
    // component. It is called whenever the user changes the webpage address that
    // they are viewing. So here we just notify the parameter change listener
    // that something has changed.
    public void setPage(String url, boolean addToHistory)
    {
    super.setPage(url, addToHistory);
    if (parameterChangeListener != null) {
    // Notify the change by passing the instance of the
    // SimLinkPlugin to the parameter change listener.
    parameterChangeListener.parameterChanged(this);
    }
    }

    }
   
Knowledge Media Institute
Knowledge Media Institute (KMi®) Registered Trademark
The Open University