When customising JIRA, it is sometimes necessary to make code modifications. Most classes in JIRA conform to an interface (eg. the Webwork action classes, and *Manager classes), so it is possible to write your own implementation of JIRA interfaces and use yours instead of the default. This page describes the basics of how plug modified classes into JIRA with minimal pain.
If you wanted to register your overridden version of a pico-registered class, you could just register yours instead of the default in ComponentRegistrar above.
Sometimes it may be necessary for a plugin writer to override a component that JIRA ships with to provide some custom behaviour. There's two ways this can be achieved. The preferred way is to provide a plugins1 component module. Alternatively one can also provide an extension pico container via a jira-application.properties property which can be used in more complex scenarios.
To override a component in JIRA, one simply has to declare a component module for an interface that's already been registered in JIRA. For example to override JIRA's SearchService, one could declare a plugin component like this:
<component key="searchService" name="Search Service"
class="com.atlassian.docsprint.MySearchService">
<interface>com.atlassian.jira.bc.issue.search.SearchService</interface>
</component> |
Please note that components can only be overriden from a plugins1 component plugin module that is deployed to WEB-INF/lib. Overriding a component from a plugins2 plugin will not work. |
Since JIRA 3.0 there is another way of plugging in your customizations that avoids modifying JIRA code. In jira-application.properties, register an extension container provider:
|
jira.extension.container.provider = com.mycompany.jira.MyContainerProvider |
In this class, you can register your own implementations of interfaces, which will be used in preference to the defaults in ComponentManager:
package com.mycompany.jira;
import org.picocontainer.PicoContainer;
import org.picocontainer.defaults.DefaultPicoContainer;
import com.atlassian.jira.config.component.ProfilingComponentAdapterFactory;
import com.atlassian.jira.web.action.issue.BugAssociatorPrefs;
import com.atlassian.jira.security.PermissionManager;
import com.atlassian.jira.permission.PermissionSchemeManager;
import com.mycompany.jira.MyBugAssociatorPrefs;
import com.mycompany.jira.MyPermissionManager;
import com.mycompany.jira.MyPermissionSchemeManager;
public class MyContainerProvider implements ContainerProvider
{
private DefaultPicoContainer container;
public PicoContainer getContainer(PicoContainer parent)
{
if (container == null)
buildContainer(parent);
return container;
}
private void buildContainer(PicoContainer parent)
{
this.container = new DefaultPicoContainer(new ProfilingComponentAdapterFactory(), parent);
container.registerComponentImplementation(BugAssociatorPrefs.class, MyBugAssociatorPrefs.class);
container.registerComponentImplementation(PermissionManager.class, MyPermissionManager.class);
container.registerComponentImplementation(PermissionSchemeManager.class, MyPermissionSchemeManager.class);
}
}
|
Here we have registered our own implementations of three classes, after delegating to the default (so ours will take precedence). You can now keep MyContainerProvider and your modified com.mycompany.jira.* classes in their own jar, which can be dropped into any JIRA instance to customize it to your needs.