This page last changed on Sep 28, 2009 by rosie@atlassian.com.

On this page:

Introduction

Plugins Framework

JIRA uses a library called the Atlassian Plugin Framework to manage its plugins. This library is developed separately to JIRA (it is a shared library used by all the Atlassian products) and therefore has its own versioning.

For example JIRA v4.0 uses Plugin Framework v2.3, JIRA v3.13 uses Plugin Framework v0.23.

Plugin versions

Before Plugins Framework v2 (JIRA v3.13 and earlier), plugins were installed in JIRA by adding the plugin JAR file to JIRA's classpath (WEB-INF/lib). This style of plugin is referred to as "Plugins1".

Plugins Framework v2 (JIRA v4.0 and higher) introduced a new way to install plugins. Plugins can be installed in JIRA's "installed-plugins" directory from where they will be installed and managed by an OSGi Container. This type of plugin is referred to as "Plugins2".

It is important to note that Plugins2 is not considered a replacement for Plugins1. Each provides some advantages and disadvantages. Plugin developers should consider their particular plugin, and choose which plugin type to use accordingly.

Plugins1

Plugins1 was the original way to install and manage plugins. In JIRA, these are installed by placing the plugin JAR in your WEB-INF/lib/ directory.
(This is a "static plugin". The framework also has another form called a "dynamic Plugins1 plugin", but these are not supported in JIRA).
This means the Java classes in your plugin live in the core application classpath, and are loaded just the same as the core JIRA classes.
If you install two Plugins1 plugins (A and B) in JIRA, then plugin B will be able to use the classes from plugin A as all the classes live in the same ClassLoader. However, Plugin B has no way to declare that it relies on Plugin A. If Plugin A is not installed, then this will cause ClassNotFound exceptions to occur at runtime.

Plugins2

Plugins2 plugins are not installed in the core ClassLoader. They are installed and managed by an OSGi container. This means each Plugin has its own child ClassLoader that loads the classes of that plugin. By default, plugins cannot use the classes of another plugin. However, one plugin can explicitly export some of its packages, and then other plugins can import these dependencies. In this way, the interdependencies can be much better managed.

In addition, a Plugins2 plugin can create its own custom extension points. Effectively, you can allow plugin points for your plugin.

Development and Installation

Configuration

The JAR file for a Plugins1 plugin looks exactly the same as one for Plugins2 with one difference in the configuration file.
The atlassian-plugin.xml for a Plugins2 plugin must declare it is Plugins2 in the <atlassian-plugin> tag.

<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">

Installation

A Plugins1 plugin must be on the application classpath, and therefore is installed in WEB-INF/lib.
On the other hand, a Plugins2 plugin must not be on the standard classpath. They are installed in a special subfolder of the JIRA Home directory - <jira-home>/plugins/installed-plugins/.

Dependency Injection

The Container

JIRA uses Pico Container to manage Dependency Injection in its core classes and in Plugins1 classes.

On the other hand, Dependency Injection in Plugins2 plugins is not managed directly from JIRA, it is done in the Plugin Framework.
The Plugin Framework uses the Spring Framework for Dependency Injection. This will normally not affect the development of plugins, however there can be some subtle differences.
Of particular note is the case when a class has multiple constructors; the constructor chosen by Pico and Spring can be different.

Also, JIRA does not make all of its internal components available to the Plugin Framework. Some are considered unsuitable for plugin developers to use as they really should only be used by core systems.
This means there are some components that a Plugins1 plugin can get injected, that Plugins2 plugins cannot get injected.

Components

Components in JIRA can considered as the "services" in a Service Oriented Architecture. They are the Dependency Objects that can be Dependency Injected into other objects.
JIRA allows plugin developers to create new components that can then be injected into other objects used in plugins.
The way that plugin Components work is rather different depending on whether the Component lives in a Plugins1 or Plugins2 plugin.

Plugins1 Components

If a Plugins1 plugin declares a component, then that component is added to JIRA's core dependency injection container, and will be available as a dependency to any other plugin.
In fact, it is even possible to create a component to replace existing core components, although this is not considered a good idea - it is difficult, error-prone, and can't be guaranteed to always work.

Plugins2 Components

If a Plugins2 plugin declares a component, then by default this component is "private". Other classes in this plugin will be able to get the component injected in them, but other plugins will not.
The developer can declare the component as public, and then the component will be available to other Plugins2 plugins if they explicitly import that component.

Java packages

OSGi exports and imports dependencies based on Java packages. Only one ClassLoader can export classes from any given package. Under Plugins2 this means it is even more important to not duplicate package names of core JIRA classes, or other plugins.

Of particular interest is the Webwork plugin module.
In JIRA v3.13 and earlier, most Plugin developers probably followed the example in the documentation that showed an Action class in the com.atlassian.jira.web.action package.
This meant they could declare a Webwork module with a "simple" class name. This is anyway a bad idea as it allows for possible name-space clashes. Furthermore, it will simply not work under Plugins2.
A plugin developer must create an action that lives in a unique package, and include the fully qualified class name of the action in the configuration file.
eg:

<webwork1 key="qquserissue" name="Quick Create User Issue" class="java.lang.Object">
    <actions>
        <action name="com.atlassian.jira.toolkit.action.QuickCreateUserIssueAction" alias="QuickCreateUserIssue">
            <view name="createuserissue">/templates/quickcreateuser.vm</view>
        </action>
    </actions>
</webwork1>
Document generated by Confluence on Oct 06, 2009 00:31