J tricks - Little JIRA Tricks
  • Home
  • Plugins ↓
    • JQL Tricks Plugin
      • JQL Tricks Plugin - Cloud
        • JQLT Cloud Installation
        • JQLT Cloud Configuration
        • JQLT Cloud Usage
        • JQLT Cloud License
        • JQLT Cloud FAQ
      • JQL Tricks Plugin - DC
        • JQLT DC Installation
        • JQLT DC Configuration
        • JQLT DC Usage
          • JQLT Issue Functions
          • JQLT Subtask Functions
          • JQLT Links Functions
          • JQLT Development Functions
          • JQLT Worklog Functions
          • JQLT Project Functions
          • JQLT Component Functions
          • JQLT Version Functions
          • JQLT Group Functions
          • JQLT User Functions
          • JQLT Date Functions
        • JQLT DC License
        • JQLT DC FAQ
        • JQLT DC Known Issues
        • JQLT DC Performance
      • JQL Tricks Cloud Migration
    • Simplified Planner
      • J-Planner Installation
      • J-Planner Configuration
      • J-Planner Usage
        • Creating a plan
        • Editing a plan
        • Deleting a plan
        • Viewing a plan
        • Modifying a plan
      • J-Planner FAQ
    • Atla-Search Plugin
      • Atla-Search Installation
      • Atla-Search Configuration
      • Atla-Search Usage
      • Atla-Search License
      • Atla-Search FAQ
    • Heroku for Compass App
      • Heroku for Compass Installation
      • Heroku for Compass Configuration
      • Heroku for Compass Usage
    • Datadog for Compass App
      • Datadog for Compass Installation
      • Datadog for Compass Configuration
      • Datadog for Compass Usage
    • Copy to subtask Plugin
    • All Plugins
  • Tutorials
  • The Book
  • Contact Us
  • Home
  • Plugins ↓
    • JQL Tricks Plugin
      • JQL Tricks Plugin - Cloud
        • JQLT Cloud Installation
        • JQLT Cloud Configuration
        • JQLT Cloud Usage
        • JQLT Cloud License
        • JQLT Cloud FAQ
      • JQL Tricks Plugin - DC
        • JQLT DC Installation
        • JQLT DC Configuration
        • JQLT DC Usage
          • JQLT Issue Functions
          • JQLT Subtask Functions
          • JQLT Links Functions
          • JQLT Development Functions
          • JQLT Worklog Functions
          • JQLT Project Functions
          • JQLT Component Functions
          • JQLT Version Functions
          • JQLT Group Functions
          • JQLT User Functions
          • JQLT Date Functions
        • JQLT DC License
        • JQLT DC FAQ
        • JQLT DC Known Issues
        • JQLT DC Performance
      • JQL Tricks Cloud Migration
    • Simplified Planner
      • J-Planner Installation
      • J-Planner Configuration
      • J-Planner Usage
        • Creating a plan
        • Editing a plan
        • Deleting a plan
        • Viewing a plan
        • Modifying a plan
      • J-Planner FAQ
    • Atla-Search Plugin
      • Atla-Search Installation
      • Atla-Search Configuration
      • Atla-Search Usage
      • Atla-Search License
      • Atla-Search FAQ
    • Heroku for Compass App
      • Heroku for Compass Installation
      • Heroku for Compass Configuration
      • Heroku for Compass Usage
    • Datadog for Compass App
      • Datadog for Compass Installation
      • Datadog for Compass Configuration
      • Datadog for Compass Usage
    • Copy to subtask Plugin
    • All Plugins
  • Tutorials
  • The Book
  • Contact Us

Capturing Plugin installation/Un-installation Events

3/18/2012

20 Comments

 
It is simple. Really! To do things that can give a pretty good mileage during plugin configuration, especially for commercial plugins, is simple? Let us see.

In this short recipe, let us look at creating a custom field automatically during a plugin installation and deleting it while un-installation. Same applied for enabling/disabling of the plugin.

All you need to do is 2 simple steps:
  1. Write an event listener. We will use the atlassian-event library here.
  2. Implement the Spring interfaces InitializingBean and DisposableBean to capture the plugin lifecycle events.

Writing an event listener in JIRA is quite easy. 
  1. Import the EventPublisher instance used to register events. You can do this by adding the following component in atlassian-plugin.xml

    <component-import key="eventPublisher" interface="com.atlassian.event.api.EventPublisher"/>

  2. Now, instantiate our listener class

    <component key="eventListener" >
        <description>A Listener for plugin lifecycle events</description>
    </component>

So, what's the deal with a listener here? Basically, Atlassian plugins are implemented as Spring dynamic modules and the atlassian-plugin.xml is transformed into a Spring XML bean configuration before it is loaded by the JIRA. Since our listener is registered as a <component>, it will become a Sping bean when loaded and hence we can use the Spring interfaces InitializingBean and DisposableBean to capture plugin lifecycle events.

Whenever the component (here PluginListener) is registered, i.e. during the enabling or installation of the plugin, afterPropertiesSet() method from InitializingBean is invoked. Similarly, when the component is un-registered, during plugin disabling or un-installation, destroy() method from DisposableBean is invoked.

Our listener will look like this:

public class PluginListener implements InitializingBean, DisposableBean {

    @Override
    public void destroy() throws Exception {
        //Handle plugin disabling or un-installation here
    
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //Handle plugin enabling or installation here
    }
}


That's it! How does it help during plugin configurations? Read on..

Suppose we have a plugin that needs a Text custom field for its functionality, with a pre-defined name. Users will have to configure this manually when the install a plugin and remove it when they un-install it. This is also prone to manual errors. Why not do this in the plugin itself?

Let us create a Text CF during the plugin enabling/installation and associate it with a screen. We will also remove this when the plugin is disabled or un-installed. The code is an extention to the above and self explanatory. Here it goes:

public class PluginListener implements InitializingBean, DisposableBean {

    private static final String TEST_TEXT_CF = "Test Text CF";

     private final CustomFieldManager customFieldManager;
    private final FieldScreenManager fieldScreenManager;

    public PluginListener(CustomFieldManager customFieldManager, FieldScreenManager fieldScreenManager) {
        this.customFieldManager = customFieldManager;
        this.fieldScreenManager = fieldScreenManager;
    }

    @Override
    public void destroy() throws Exception {
        //Get the already installed custom field by name
        CustomField cField = this.customFieldManager.getCustomFieldObjectByName(TEST_TEXT_CF);
        //Remove if not null
        if (cField != null) {
            this.customFieldManager.removeCustomField(cField);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        //Create a list of issue types for which the custom field needs to be available
        List<GenericValue> issueTypes = new ArrayList<GenericValue>();
        issueTypes.add(null);

        //Create a list of project contexts for which the custom field needs to be available
        List<JiraContextNode> contexts = new ArrayList<JiraContextNode>();
        contexts.add(GlobalIssueContext.getInstance());

        //Add custom field
        CustomField cField = this.customFieldManager.createCustomField(TEST_TEXT_CF, "A Sample Text Field",
            this.customFieldManager.getCustomFieldType("com.atlassian.jira.plugin.system.customfieldtypes:textfield"),
            this.customFieldManager.getCustomFieldSearcher("com.atlassian.jira.plugin.system.customfieldtypes:textsearcher"),
            contexts, issueTypes);

        // Add field to default Screen
        FieldScreen defaultScreen = fieldScreenManager.getFieldScreen(FieldScreen.DEFAULT_SCREEN_ID);
        if (!defaultScreen.containsField(cField.getId())) {
            FieldScreenTab firstTab = defaultScreen.getTab(0);
            firstTab.addFieldScreenLayoutItem(cField.getId());
        }
    }
}


Here is a screenshot on how the field looks like once it is created.

Picture
Over to you to explore further! Have a look at the JIRA Development Cookbook if you liked this recipe. You will find more. Also, attached is the full code below.
plugin-listener.zip
File Size: 12 kb
File Type: zip
Download File

20 Comments
Matt Doar link
3/20/2012 01:34:28 pm

This is neat stuff and a handy reference - thanks.

Minor nits: there is a risk that removing the plugin will delete the custom field and all its data. This may be what is intended but there is also a risk if a user creates their own field named "Test Text CF" and then it is found instead of the intended one!

Reply
J-Tricks
3/20/2012 02:30:40 pm

Totally agree Matt :) I kind of merged 2 recipes into one for the sake of an example and I see where this can be an issue. Thanks for pointing out.

Reply
Ignasi
3/26/2013 01:07:21 am

I review project and seems me that a dependency to springframework is needed because in jira sdk it is not available as a library.

Reply
J-Tricks
3/26/2013 04:41:55 am

Yes, in the later versions, Spring is not a transitive dependency on the jira-api.

For example:

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>2.5.6</version>
<scope>provided</scope>
</dependency>

Reply
sisdog
7/17/2013 06:22:33 pm

I'm very new to JIRA and java (I'm a .net guy trying to customize JIRA). In following this example I'm getting the same dependency issue but I have no idea where this <dependency> tag goes and how, in general, this library is made available to the running JIRA app where my plugin is running. Is it always available and this tag is just a necessity to make it available to my plugin? How do I get the dependency error to go away in eclipse?

thanks.

J-Tricks
7/18/2013 05:02:29 am

It goes in the pom.xml. You will have to rebuild the Eclipse project using the below command and refresh/clean in Eclipse.

mvn eclipse:clean eclipse:eclipse

Vista College link
7/29/2013 02:10:03 am

Is there any problem with the .zip file which you have shared above? because I have tried twice to download the file but it showing 'missing file' error.

Reply
J-Tricks
7/30/2013 03:26:55 pm

Not sure what the issue is but works fine for us. If you are still facing the issue, write to [email protected] and we will send you the zip file.

Reply
ищу работу в грроде сочи адлеркий район link
5/14/2014 05:59:30 pm

That you are my inhalation , I own couple of blogs and rarely run out from to post : (.

Reply
Brad
7/3/2014 09:53:10 am

Should this still work if the PluginLoader component and the Custom Field that it is adding are both contained int he same plugin?

My call to customFieldManager.getCustomFieldType is returning null. I'm suspecting that's because the Custom field is not available yet. Is there any way to specify the order so that the Custom Field is already loaded by the time the PluginLoader is executed?

Reply
J-Tricks
7/3/2014 10:41:22 am

Interesting. That might well be the case. Can you try using the Startable (https://docs.atlassian.com/jira/6.2.1/com/atlassian/jira/extension/Startable.html) interface instead of InitializingBean? JIRA will be fully initialized by then.

Reply
Adrián
6/21/2015 11:48:59 pm

You could fix the problem? i have the same

Reply
Chris
8/18/2014 07:47:28 am

I am getting the error below whenever I run atlas-run and the plugin tries to activate. I have to atlas-run and use the atlas-cli to install the plugin

[jira.issue.managers.DefaultCustomFieldManager] Custom field searcher module: com.atlassian.jira.plugin.system.customfieldtypes:textsearcher is invalid. Null being returned.

Reply
J-Tricks
8/18/2014 08:49:02 am

Never seen that. Might be an issue with SDK.

Reply
Amrit
4/11/2016 06:44:47 am

Hi , I tried converting this to spring scanner way - used @Named("PluginListener")
How to convert this one ?
<component-import key="eventPublisher" interface="com.atlassian.event.api.EventPublisher"/>

Reply
J-Tricks
4/11/2016 09:57:37 pm

Use @ComponentImport.

Check http://www.j-tricks.com/tutorials/atlassian-spring-scanner-and-nosuchbeandefinitionexception

Reply
Humsawani
9/4/2017 09:08:47 am

Hi..I got below error while executing this pluginListener.java.
I am using atlas version 6.2.14.
Error:
incompatible types: java.util.List<org.ofbiz.core.entity.GenericValue> cannot be converted to java.util.List<com.atlassian.jira.issue.issuetype.IssueType>

please help me to resolve this issue.

Reply
J-Tricks
9/5/2017 07:13:49 am

It looks like you are developing against a newer version of JIRA. Please modify the code to comply with the latest API method signatures.

In the above case, just change the type to IssueType and use it to retrieve the properties.

Reply
Humsawani
9/7/2017 02:02:01 am

Thank you J-tricks.
I changed to GenericValue to IssueType like
List<IssueType> issueTypes = new ArrayList<IssueType>();
issueTypes.add(null);
It said like,"atlassian-plugin.xml contains a definition of component-import. This is not allo wed when Atlassian-Plugin-Key is set"
So, I removed Atlassian-Plugin-Key in pom.xml. Now, Build is success and the field is not added to default screen.

J-Tricks
9/7/2017 07:10:51 am

It looks like you are dealing with the Atlassian Spring Scanner issues here. Check the logs for errors.


Your comment will be posted after it is approved.


Leave a Reply.

    Enter your email address:

    Author

    Jobin Kuruvilla - Works in Adaptavist as Head of DevOps Professional Services. 

    Author of JIRA Development Cookbook and JIRA 5.x Development Cookbook.


    RSS Feed

    Categories

    All
    Acive Objects
    Ajs
    Book
    Components
    Condition
    Custom Fields
    Customization
    Events
    Gadgets
    Javascript
    Jql
    Listener
    Mail
    Permissions
    Plugin Framework
    Post Function
    Properties
    Remote Invocation
    Reporting
    Rest
    Scheduled Tasks
    Search
    Services
    Soap
    Summit
    User Interface
    Validator
    Webwork Actions
    Workflow

    Archives

    October 2016
    August 2016
    March 2016
    January 2016
    December 2015
    May 2014
    December 2013
    November 2013
    July 2013
    June 2013
    April 2013
    October 2012
    September 2012
    August 2012
    July 2012
    May 2012
    March 2012
    February 2012
    January 2012
    December 2011
    November 2011
    June 2011
    May 2011
    April 2011
    March 2011
    February 2011
    January 2011
    November 2010
    October 2010
    September 2010
    August 2010

SUPPORT
APPS
TUTORIALS
THE BOOK
© J-Tricks