Own component in ValuesGenerator for a custom Report

Kerem Caglar [Solveka]
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 24, 2015

We are implementing a custom report. In an overriden ValuesGenerator class, we need to get instance of a component implemented in the same plugin. We retrieve the instance with:

Service service = ComponentAccessor.getOSGiComponentInstanceOfType(Service.class);

When JIRA restarts component instance is retrieved normally. After we install a new version of the plugin without restarting JIRA we receive the following error:

Caused by: java.lang.ClassCastException: Cannot cast service.ServiceImpl to service.Service
	at java.lang.Class.cast(Class.java:3094)
	at com.atlassian.jira.plugin.JiraOsgiContainerManager.getOsgiComponentOfType(JiraOsgiContainerManager.java:66)
	at com.atlassian.jira.ComponentManager.getOSGiComponentInstanceOfType(ComponentManager.java:591)
	at com.atlassian.jira.component.ComponentAccessorWorker.getOSGiComponentInstanceOfType(ComponentAccessorWorker.java:27)
	at com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType(ComponentAccessor.java:168)
	at com.atlassian.configurable.ValuesGeneratorObjectConfigurationProperty.getInternalValues(ValuesGeneratorObjectConfigurationProperty.java:69)
	at com.atlassian.configurable.ObjectConfigurationPropertyImpl.isEmpty(ObjectConfigurationPropertyImpl.java:186)

After this error is received, we restart JIRA, the problem is gone, no cast exception.

Anybody who experienced a similar problem?

Thanks

2 answers

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

0 votes
Kerem Caglar [Solveka]
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 27, 2015

Hi Scott,
I tried out your suggestion, it did not help either. When JIRA restarts everything works fine. But when I re-install the plugin, it starts to fail. Your suggestion gave me an idea and  I tried another approach by implemeting the following

public class SjqaComponentAccessor implements InitializingBean, DisposableBean {
	
	private static SjqaComponentAccessor instance;

	Service service;
	public SjqaComponentAccessor(Service service) {
		this.service= service;
	}
	@Override
	public void destroy() throws Exception {
		instance = null;
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		instance = this;
	}
	
	public static Service getService() {
	    return instance.service;
	}
}

I get similar results. In the second run (after re-install),

When I access to instance from ValuesGenerator class instance is null

When I access to instance from another plugin component instance is OK.

It looks like ValuesGenerator class objects are instatiated once when JIRA starts but still I am puzzled how it cannot access to a static variable. 

Scott Dudley [Inactive]
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 27, 2015

"puzzled how it cannot access to a static variable." This situation could arise because your OSGi bundle is loaded twice (one copy of the old one, one copy of the new one). If JIRA truly is instantiating the ValuesGenerator only once, then when it calls the ValuesGenerator, those methods should only be able to reference the classes created as part of the original plugin load. From that point of view, if the first SjqaComponentAccessor gets torn down when the original OSGi context is (attempted to be) destroyed, the first ValuesGenerator would still be pointing at that first SqjaComponentAccessor, and it would still return null because the component already had its destroy() method called. Other plugin components would be accessing the second copy of your plugin that is loaded (and the second SqjaComponentAccessor), so they would be accessing the active service instance and seeing non-null return values. The part I don't understand is why the solution in my answer does not work: I would have thought that the ApplicationContext would only provide access to beans within the current OSGi bundle, so I am unclear about how calling applicationContext.getBean() from instance #1 of your plugin could fetch a bean from instance #2 (which is presumably the root cause of the ClassCastException).

0 votes
Scott Dudley [Inactive]
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
April 24, 2015

The best way to get your own plugin's components (other than by autowiring) is to create your own PluginContainerManager and get the component directly from that.

See Dan Hardiker's 24/Mar/09 3:56 AM comment on https://ecosystem.atlassian.net/browse/PLUG-280 for a good example.

TAGS
AUG Leaders

Atlassian Community Events