Plugins

Posted by Shane McCormack's avatar Shane McCormack on May 26, 2007

Ok, so you’ve read about actions and seen just how amazingly useful they are, maybe you’ve even used them and feel like donating your life savings to the creator? (It’s me, honest! Don’t believe Chris!) Well then, what happens when you come across something that you just can’t manage to do with actions? (It’s rare, but it happens — though if you believe it should be possible with actions let us know in #DMDirc on Quakenet and we’ll see what we can do). The answer is simple: Plugins :D

Plugins, unlike actions, are made from compiled Java code. This means that (also unlike actions) they require a considerable bit more technical knowledge to create.

The plugins system is tied into the actions system for most events, and whilst using this is not required, it is probably desirable for a lot of plugins.

Plugins can do a lot of things, from adding new action types, to manipulating the actual IRC Parser callbacks and line processing, in summary they give you the most control over the client, but at the cost of being harder to get to grips with.

Some plugins are available in source-form from the SVN repository for the project (and are compiled into the nightly jar files, so you can extract the .class files if you’re not comfortable compiling plugins yourself) and before 0.4 is released http://addons.dmdirc.com/ will be completed to allow plugins to be downloaded in source and/or compiled form.

This section of the post assumes prior knowledge of Object Oriented Programming, and Java.

Firstly, we need to create a .java file for our plugin, this can be anything, but for the “Manage Plugins” window to automatically detect it, it must end in “Plugin”

So we shall create a plugin called MyFirstPlugin.java, it should be saved as ~/.DMDirc/plugins/package/MyFirstPlugin.java (Documents and Settings\Username\Application Data\DMDirc\plugins\package\MyFirstPlugin.java on Windows). The ‘package’ folder is not strictly needed, but is used to follow the java conventions and to keep the plugins directory tidy, This plugin will be in the ‘example’ package, and thus is saved as ~/.DMDIrc/plugins/example/MyFirstPlugin.java

Before we take a look at making a plugin, we should look at the API for the them. All plugins need to extend the abstract class com.dmdirc.plugins.Plugin, which shows us the methods we need to implement in our plugin.

Now that we have looked at the API guide, we can make the skeleton of our plugin:

package example;

import com.dmdirc.plugins.Plugin;

public class MyFirstPlugin extends Plugin {
    /** {@inheritDoc} */
    public String getAuthor() {
        return "Dataforce";
    }

    /** {@inheritDoc} */
    public String getDescription() {
        return "An example of plugin coding.";
    }

    /** {@inheritDoc} */
    public String getVersion() {
        return "1.0";
    }

    /** {@inheritDoc} */
    public String toString() {
        return "Example Plugin";
    }

    /** {@inheritDoc} */
    public boolean onLoad() {
        System.out.println("MyFirstPlugin loaded.");
        return true;
    }
}

This plugin pretty much does nothing, and as you can see is already twice the length of a relatively complex action.

If you look into the (Settings > Plugins > )”Manage Plugins” dialog now, you will be greeted with something like this:

Before Plugin is loaded

Before you can use this plugin, you need to compile it, and as it’s still just a Java application you will need the JDK to do this. Once you have the JDK you can issue the following command from the ~/.DMDirc/plugins/ directory:

javac -cp /home/shane/projects/dmdirc_google/trunk/dist/DMDirc.jar example/MyFirstPlugin.java

(Replacing “/home/shane/projects/dmdirc_google/trunk/dist/DMDirc.jar” with the path to your DMDIrc.jar file)

This will create a file in the example dir called “MyFirstPlugin.class” and it is this file that the plugin manager will look for.

Now if you re-open the “Manage Plugins” dialog you will see that the plugin has been detected:

After Plugin is loaded

If you are running DMDirc from a console you will see that the above plugin will print “MyFirstPlugin loaded.” to the console, as per the onLoad() method.

Plugins have 3 states:

When a plugin is first discovered by the “Manage Plugins” window, it it put into state #2, /loadplugin will put it into state #3. The enable/disable toggles on the dialog change between states 2 and 3. A plugin in state 2 is expected to do nothing apart from wait to be changed to state 3.

The onLoad() method returns a boolean to allow plugins to prevent themselves being loaded. For instance the dcop plugin will not load if the dcop system-command can not be used. This is where you should put any checks for plugin compatability.

There are 2 other important methods to take note of, onActivate() and onDeactivate(), These are not shown in the above example as it doesn’t actually do much, but these 2 methods are called when the plugin changes between states 2 and 3.

To show these 2 important methods, add the following to your code:

/** {@inheritDoc} */
public void onActivate() {
    System.out.println("MyFirstPlugin was changed to state 3 - Activated");
}

/** {@inheritDoc} */
public void onDeactivate() {
    System.out.println("MyFirstPlugin was changed to state 2 - Deactivated");
}

And recompile the plugin.

There is an important thing to note here, that the “Manage Plugins” dialog will not reload a changed plugin, and at present this has to be done manually using the following command:

/reloadplugin example.MyFirstPlugin

Now if you watch your console as you press enable/disable on the “Manage Plugins” dialog, it will tell you which state the plugin is in.

That’s it for this post, in later posts I will show more useful and more advanced things you can do with plugins.