ActiveObjects before <ao> configuration module is enabled or plugin is missing

Hello,

recently after upgrading jira to 8.16 we encountered this issue while using AO. Plugin loads normally but when we want to store something or read we get this:

at com.erstegroup.dbo.snowSync.rest.SynchronisationSchemeResource.reset(SynchronisationSchemeResource.java:111)
	at com.erstegroup.dbo.snowSync.db.service.SynchronisationSchemeService.resetLastJobs(SynchronisationSchemeService.java:255)
	at com.sun.proxy.$Proxy5699.deleteWithSQL(Unknown Source)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.eclipse.gemini.blueprint.service.importer.support.LocalBundleContextAdvice.invoke(LocalBundleContextAdvice.java:57)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invoke(ServiceTCCLInterceptor.java:53)
	at org.eclipse.gemini.blueprint.service.util.internal.aop.ServiceTCCLInterceptor.invokeUnprivileged(ServiceTCCLInterceptor.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
	at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.invoke(ServiceInvoker.java:60)
	at org.eclipse.gemini.blueprint.service.importer.support.internal.aop.ServiceInvoker.doInvoke(ServiceInvoker.java:56)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at sun.reflect.GeneratedMethodAccessor1094.invoke(Unknown Source)
	at com.atlassian.activeobjects.osgi.TenantAwareActiveObjects.deleteWithSQL(TenantAwareActiveObjects.java:287)
	at com.atlassian.activeobjects.osgi.TenantAwareActiveObjects.delegate(TenantAwareActiveObjects.java:166)
java.lang.IllegalStateException: plugin [{com.erstegroup.dbo.snowSync}] 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.
2021-05-04 10:36:45,584 http-nio-8080-exec-9 ERROR H50RZ2A 636x35208x1 h3o7kz 10.8.244.134,10.8.248.11 /rest/snow-sync-plugin/1.0/synchronisation-scheme/reset-last-jobs [c.a.p.r.c.error.jersey.ThrowableExceptionMapper] Uncaught exception thrown by REST service: plugin [{com.erstegroup.dbo.snowSync}] 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.
2021-05-04 10:36:45,583 http-nio-8080-exec-9 DEBUG H50RZ2A 636x35208x1 h3o7kz 10.8.244.134,10.8.248.11 /rest/snow-sync-plugin/1.0/synchronisation-scheme/reset-last-jobs [c.e.d.snowSync.rest.SynchronisationSchemeResource] Endpoint: /synchronisation-scheme/reset-last-jobs

The problem with AO is that there is always the possibility of a race condition, where your app is loaded before AO is initialised.

You can wait for AO to be ready:

        int count = 0;
        boolean isInitialized = false;
        while (!isInitialized && count < 10) {
            try {
                activeObjects.moduleMetaData().awaitInitialization(1, TimeUnit.MINUTES);
                isInitialized = activeObjects.moduleMetaData().isInitialized();
            } catch (InterruptedException | ExecutionException | TimeoutException exp) {
                count++;
            }
        }

We use this in a component that is started when the app is enabled by Jira and fires an AOReadyEvent when AO is initialised. Any other component that requires AO listens to this AOReadyEvent. That way we ensure we are not doing any database operations until AO is ready for it.