Plugin Install Event - Error using ActiveObjects in Function afterPropertiesSet (InitializingBean)

Hey.

I have a class which implements the InitializingBean and DisposableBean Interfaces to trigger the Install/Uninstall Event of the plugin.

I want to generate a few Entitys in my ActiveObject Database when the plugin will be installed. In my afterPropertSet() Function I use a component which I wrote.

@Component
public class EmailTemplateManagerImpl implements EmailTemplateManager {

   AOMainService aoMainService;

    ...

    public void doSomething() {
            aoMainService.createEntity();
    }

}

Here is my ActiveObjects service implementation

@Component
public class AOMainServiceImpl implements AOMainService {
    @ComponentImport
    private ActiveObjects ao;

    @Autowired
    public AOMainServiceImpl(final ActiveObjects ao) {
        this.ao = ao;
    }

    public void createEntity() {
        final MyEntity entity = ao.create(MyEntity.class);
        ...
        entity.save();
    }

And finally my class with the InitializingBean & DisposableBean interfaces.

@Component
public class PluginListener implements InitializingBean, DisposableBean {
    private EmailTemplateManager emailTemplateManager;

    @Autowired
    public PluginListener(final EmailTemplateManager emailTemplateManager){
        this.emailTemplateManager = emailTemplateManager;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        emailTemplateManager.doSomething();
    }

When I debug the afterPropertiesSet I can see that all components are injected and not null!
But when activeobjects get called I got the following exception:

 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pluginListener': Invocation of init method failed; nested exception is java.lang.IllegalStateException: plugin [{de.scag.jira.plugin.mailhandler}] invoking ActiveObjects before <ao> configuration module is enabled or plugin is missing an <ao> configuration module. Note that scanning of entities from the ao.model package is no longer supported.
jira73x_1  |    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
jira73x_1  |    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
jira73x_1  |    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
jira73x_1  |    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
jira73x_1  |    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.access$1600(AbstractDelegatedExecutionApplicationContext.java:60)
jira73x_1  |    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext$4.run(AbstractDelegatedExecutionApplicationContext.java:325)
jira73x_1  |    at org.eclipse.gemini.blueprint.util.internal.PrivilegedUtils.executeWithCustomTCCL(PrivilegedUtils.java:85)
jira73x_1  |    at org.eclipse.gemini.blueprint.context.support.AbstractDelegatedExecutionApplicationContext.completeRefresh(AbstractDelegatedExecutionApplicationContext.java:290)
jira73x_1  |    at org.eclipse.gemini.blueprint.extender.internal.dependencies.startup.DependencyWaiterApplicationContextExecutor$CompleteRefreshTask.run(DependencyWaiterApplicationContextExecutor.java:137)
jira73x_1  |    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
jira73x_1  |    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
jira73x_1  |    at java.lang.Thread.run(Thread.java:748)
jira73x_1  | Caused by: java.lang.IllegalStateException: plugin [{de.scag.jira.plugin.mailhandler}] invoking ActiveObjects before <ao> configuration module is enabled or plugin is missing an <ao> configuration module. Note that scanning of entities from the ao.model package is no longer supported.
jira73x_1  |    at com.atlassian.activeobjects.osgi.TenantAwareActiveObjects.delegate(TenantAwareActiveObjects.java:165)
jira73x_1  |    at com.atlassian.activeobjects.osgi.TenantAwareActiveObjects.create(TenantAwareActiveObjects.java:266)
jira73x_1  |    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
jira73x_1  |    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
jira73x_1  |    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
jira73x_1  |    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
jira73x_1  |    at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:56)
jira73x_1  |    at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:60)
jira73x_1  |    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
jira73x_1  |    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
jira73x_1  |    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
jira73x_1  |    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
jira73x_1  |    at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:70)
jira73x_1  |    at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:53)
jira73x_1  |    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
jira73x_1  |    at org.eclipse.gemini.blueprint.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:57)
jira73x_1  |    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
jira73x_1  |    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
jira73x_1  |    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
jira73x_1  |    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
jira73x_1  |    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
jira73x_1  |    at com.sun.proxy.$Proxy3186.create(Unknown Source)
jira73x_1  |    at de.scag.jira.plugin.mailhandler.ao.impl.AOMainServiceImpl.createEmailTemplate(AOMainServiceImpl.java:145)
jira73x_1  |    at de.scag.jira.plugin.mailhandler.template.impl.EmailTemplateManagerImpl.installTemplate(EmailTemplateManagerImpl.java:158)
jira73x_1  |    at de.scag.jira.plugin.mailhandler.template.impl.EmailTemplateManagerImpl.installDefaultTemplate(EmailTemplateManagerImpl.java:144)
jira73x_1  |    at de.scag.jira.plugin.mailhandler.PluginListener.afterPropertiesSet(PluginListener.java:34)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
jira73x_1  |    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
jira73x_1  |    ... 16 more```

Before I implemented the InitializingBean & DisposableBean activeobjects was working just fine...
My Question right now:
**What do I have to consider when I implement the afterPropertieSet Function with activeobecjts?!**

Regards

I believe this might be because you are attempting to access ActiveObjects before the add-on has been fully initialized. Check out my answer to a similar question; it applies to your situation too.

1 Like

In addition to the answer from David, you can also use the JiraStartedEvent. This will ensure that Jira is fully initialised and ready for use. In most cases, this is the safest place to start your add-on background jobs as you might have dependencies on other parts of the system (compared to the PluginEnabledEvent, which is specific to your plugin)

Hi @M.Abdel-Mola,

Below is the working code for onPluginStarted event.

The JiraStartedEvent might be useful when Jira is starting or data is being restored; but it isn’t triggered when a plugin is installed or enabled. If you need to populate your database when your add-on is installed, you’ll need to listen for the PluginEnabledEvent.

ah yes, that is correct. My answer was only half of the solution. I was focussing on Jira startup because in most cases, this is where you would want to do some pre-processing for add-ons (i.e. task scheduling) which might require access to AO. However, this indeed does not cover add-on installation while the instance is triggered. For my own add-ons, I listen to both events. In the PluginEnabledEvent handler I check if Jira has been successfully started prior to running the code.

Many Thanks David, your solution works fine!

I still have a question

When I use my new function onPluginStarted with the PluginEnabledEvent, what can I actually do in the afterPropertiesSet Function? I got only a single line right now where I register the Event on the EventPublisher, is that everything I actually can do? I have a Book “JIRA 7 Development Cookbook” by Jobin Kuruvilla, there is an example for a PluginListener where he creates a customfield to make sure its available when the Plugin is installed, so Im wondering now how to implement the InitializingBean correctly…

Regards

Not a lot. The only guarantee you have in afterPropertiesSet is that all of the components have been injected. You don’t have any guarantee that the plugin system has been properly initialized, and other plugins on which your plugin depends may not yet be ready to roll. Since ActiveObjects is one such plugin, you shouldn’t interact with it in the afterPropertiesSet method.

You’ll either want to look at https://docs.atlassian.com/sal-api/3.0.0/sal-api/apidocs/com/atlassian/sal/api/lifecycle/LifecycleAware.html
or https://docs.atlassian.com/sal-api/3.0.0/sal-api/apidocs/com/atlassian/sal/api/upgrade/PluginUpgradeTask.html

LifecycleAware will get triggered each time after your add-on has been started (it’s life cycle aware - Atlassian was really imaginative with the name :wink: ). It’s really only safe to modify things after that.

But in your case - I would suggest the PluginUpgradeTask. It gets triggered after your add-on has been enabled and will let you do things like creating objects when the add-on gets installed. In theory you’re supposed to be able to have it only execute once - but there is a bug in regards to it - so you’ll want to make your add-on check to see if it needs to add things.

Do you have a reference for that bug, @daniel? I’d like to understand more about that.

@david.pinn: https://jira.atlassian.com/browse/JRASERVER-65294
Please ignore me ranting in that ticket, it has been a bit frustrating because there has been no response from Atlassian even though I have multiple very large (i.e unlimited user license) customers complaining about this.

2 Likes