JIRA 4.0 : Customising JIRA code
This page last changed on Oct 10, 2006 by rosie@atlassian.com.
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. PicocontainerJIRA uses Picocontainer as a central object factory. Picocontainer is responsible for instantiating objects and resolving their constructor dependencies. This greatly simplifies code, in that any Picocontainer-instantiated object (eg. a Webwork action) can obtain an instance of another (eg. a Manager class) simply by requesting one in its constructor. PicoContainer will ensure each object required in the constructor is passed in (aka dependency injection). Eg. the ViewIssue action: ViewIssue.java public class ViewIssue extends AbstractViewIssue { .... public ViewIssue(RepositoryManager repositoryManager, PermissionManager permissionManager, TrackbackManager trackbackManager, ThumbnailManager thumbnailManager, SubTaskManager subTaskManager, IssueLinkManager issueLinkManager, IssueLinkTypeManager issueLinkTypeManager, VoteManager voteManager, WatcherManager watcherManager, PluginManager pluginManager) { super(issueLinkManager, subTaskManager); this.trackbackManager = trackbackManager; this.thumbnailManager = thumbnailManager; this.issueLinkTypeManager = issueLinkTypeManager; this.pluginManager = pluginManager; this.pagerManager = new PagerManager(ActionContext.getSession()); this.repositoryManager = repositoryManager; this.permissionManager = permissionManager; this.voteManager = voteManager; this.watcherManager = watcherManager; } .... } Non-managed classesClasses not managed by Picocontainer (eg. workflow conditions / functions, Services and Listeners, or JSP scriptlets) can still get pico-instantiated objects statically using static methods of ManagerFactory or ComponentManager.getInstance(). For example: ComponentManager.getInstance().getProjectManager(); ComponentManager.getInstance().getIssueFactory(); ManagerFactory.getCustomFieldManager(); //or ManagerFactory.getApplicationProperties(); Using ComponentManager.getInstance() is prefered as ManagerFactory will become obsolete. However, if a method that you are after does not exist on the ComponentManager, use ManagerFactory. Register new Picocontainer-managed classesPicocontainer-managed classes need to be registered with Picocontainer. This happens automatically for Webwork actions, but other classes need to be registered manually. This is done in ComponentManager's registerComponents() method: ComponentManager.java private void registerComponents() { .... internalContainer.registerComponentInstance(CoreFactory.getActionDispatcher()); internalContainer.registerComponentInstance(CoreFactory.getGenericDelegator()); internalContainer.registerComponentInstance(CoreFactory.getAssociationManager()); internalContainer.registerComponentInstance(MailFactory.getServerManager()); internalContainer.registerComponentInstance(UserManager.getInstance()); internalContainer.registerComponentInstance(SearchProviderFactory.getDefaultProvider()); ..... internalContainer.registerComponentImplementation(IssueUpdater.class, DefaultIssueUpdater.class); internalContainer.registerComponentImplementation(IssueEventDispatcher.class); internalContainer.registerComponentImplementation(ChangeLogUtils.class); internalContainer.registerComponentImplementation(QueryCreator.class); internalContainer.registerComponentImplementation(ReleaseNoteManager.class); internalContainer.registerComponentImplementation(ApplicationProperties.class, ApplicationPropertiesImpl.class); internalContainer.registerComponentImplementation(VelocityManager.class, JiraVelocityManager.class); internalContainer.registerComponentImplementation(ConstantsManager.class, DefaultConstantsManager.class); internalContainer.registerComponentImplementation(PermissionSchemeManager.class, DefaultPermissionSchemeManager.class); internalContainer.registerComponentImplementation(CacheManager.class, DefaultCacheManager.class); internalContainer.registerComponentImplementation(TrackbackManager.class, TrackbackManagerImpl.class); internalContainer.registerComponentImplementation(WatcherManager.class, DefaultWatcherManager.class); internalContainer.registerComponentImplementation(EntityUtils.class); internalContainer.registerComponentImplementation(AttachmentManager.class, DefaultAttachmentManager.class); internalContainer.registerComponentImplementation(FieldManager.class, DefaultFieldManager.class); ..... } If you wanted to register your overridden version of a pico-registered class, you could just register yours instead of the default in ComponentManager above. Overriding components in JIRA 3.0
In 3.0 there is a nicer 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: MyContainerProvider.java 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. |
![]() |
Document generated by Confluence on Oct 06, 2009 00:31 |