Why do customers get a ClassNotFoundException for PluginLicenseStorageManager when using our plugin?

Tobias Reibling
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.
July 29, 2012

Hey,

so we finally managed to get a marketplace approval for our time tracking plugin, but approximately the half of all the customers that have downloaded a trial version yet werent able to use it, because they get this message:

"Sorry, but we cannot find the required licensing support to execute the requested operation. Please ensure that the Plugin License Storage plugin is installed and enabled. Restarting this plugin should resolve the problem."

I was never able to reproduce this behaviour neither in our own devlopment environment nor in our production environment, so I took a look at the customers log-files where I found this error:

1066x8044x1 18gu34e 10.77.105.88,0:0:0:0:0:0:0:1 /plugins/servlet/de.iconcept.ictime.jira-ictime/license [iconcept.ictime.managers.DefaultICTimeLicenseManager] PluginLicenseStoragePluginUnresolvedException occured
com.atlassian.upm.license.storage.lib.PluginLicenseStoragePluginUnresolvedException: com.atlassian.upm.license.storage.lib.LazyReference$InitializationException: com.atlassian.upm.license.storage.lib.PluginLicenseStoragePluginUnresolvedException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.atlassian.upm.license.storage.lib.ThirdPartyPlugin
LicenseStorageManagerAccessorImpl': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/atlassian/upm/license/storage/plugin/PluginLicenseStorageManager
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.execute(ThirdPartyPluginLicenseStorageManagerImpl.java:298)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.getLicense(ThirdPartyPluginLicenseStorageManagerImpl.java:74)
        at de.iconcept.ictime.managers.DefaultICTimeLicenseManager.validLicenseExists(DefaultICTimeLicenseManager.java:49)
        at de.iconcept.ictime.conditions.ValidLicenseCondition.shouldDisplay(ValidLicenseCondition.java:30)
        at com.atlassian.jira.plugin.webfragment.conditions.AbstractJiraCondition.shouldDisplay(AbstractJiraCondition.java:35)
        at com.atlassian.plugin.web.DefaultWebInterfaceManager.filterFragmentsByCondition(DefaultWebInterfaceManager.java:172)
        at com.atlassian.plugin.web.DefaultWebInterfaceManager.getDisplayableSections(DefaultWebInterfaceManager.java:73)
        at com.atlassian.jira.plugin.webfragment.JiraWebInterfaceManager.getDisplayableSections(JiraWebInterfaceManager.java:57)
        at com.atlassian.jira.plugin.webfragment.DefaultSimpleLinkManager.getSectionsForLocation(DefaultSimpleLinkManager.java:296)  <+2>
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:381)
        at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:370)
        at com.atlassian.velocity.htmlsafe.introspection.UnboxingMethod.invoke(UnboxingMethod.java:30)
        at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:270)
        at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:262)
        at org.apache.velocity.runtime.parser.node.ASTReference.value(ASTReference.java:507)
        at org.apache.velocity.runtime.parser.node.ASTExpression.value(ASTExpression.java:71)
        at org.apache.velocity.runtime.parser.node.ASTSetDirective.render(ASTSetDirective.java:142)
        at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
        at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:336)
        at org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:106)
        at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
        at org.apache.velocity.runtime.directive.Foreach.performIteration(Foreach.java:393)
        at org.apache.velocity.runtime.directive.Foreach.render(Foreach.java:316)
        at org.apache.velocity.runtime.parser.node.ASTDirective.render(ASTDirective.java:175)
        at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
        at org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:87)
        at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:336)
        at org.apache.velocity.Template.merge(Template.java:328)
        at org.apache.velocity.Template.merge(Template.java:235)
        at org.apache.velocity.app.VelocityEngine.mergeTemplate(VelocityEngine.java:381)
        at com.atlassian.velocity.DefaultVelocityManager.getEncodedBody(DefaultVelocityManager.java:67)
        at com.atlassian.jira.template.velocity.DefaultVelocityTemplatingEngine$DefaultRenderRequest.asHtml(DefaultVelocityTemplatingEngine.java:104)
        at com.atlassian.jira.web.component.AbstractWebComponent.getHtml(AbstractWebComponent.java:35)
        at com.atlassian.jira.web.component.webfragment.WebFragmentWebComponent.getHtml(WebFragmentWebComponent.java:48)  <+2>
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.doInvoke(UberspectImpl.java:381)
        at org.apache.velocity.util.introspection.UberspectImpl$VelMethodImpl.invoke(UberspectImpl.java:370)
        at com.atlassian.velocity.htmlsafe.introspection.AnnotationBoxingMethod.invoke(AnnotationBoxingMethod.java:26)
        at com.atlassian.velocity.htmlsafe.introspection.UnboxingMethod.invoke(UnboxingMethod.java:30)
        at org.apache.velocity.runtime.parser.node.ASTMethod.execute(ASTMethod.java:270)
        at org.apache.velocity.runtime.parser.node.ASTReference.execute(ASTReference.java:262)
        at org.apache.velocity.runtime.parser.node.ASTReference.render(ASTReference.java:342)
        at org.apache.velocity.runtime.parser.node.ASTBlock.render(ASTBlock.java:72)
        at org.apache.velocity.runtime.parser.node.ASTIfStatement.render(ASTIfStatement.java:87)
		at org.apache.velocity.runtime.parser.node.SimpleNode.render(SimpleNode.java:336)
        at org.apache.velocity.Template.merge(Template.java:328)
        at org.apache.velocity.Template.merge(Template.java:235)
        at org.apache.velocity.app.VelocityEngine.mergeTemplate(VelocityEngine.java:381)
        at com.atlassian.velocity.DefaultVelocityManager.getEncodedBody(DefaultVelocityManager.java:67)
        at com.atlassian.jira.template.velocity.DefaultVelocityTemplatingEngine$DefaultRenderRequest.asHtml(DefaultVelocityTemplatingEngine.java:104)
        at com.atlassian.jira.plugin.AbstractJiraModuleDescriptor.getHtml(AbstractJiraModuleDescriptor.java:112)
        at com.atlassian.jira.plugin.navigation.TopNavigationModuleDescriptorImpl.getTopNavigationHtml(TopNavigationModuleDescriptorImpl.java:93)
        at com.atlassian.jira.plugin.navigation.DefaultPluggableTopNavigation.getHtml(DefaultPluggableTopNavigation.java:23)
        at org.apache.jsp.decorators.admin_jsp._jspService(admin_jsp.java:560)
        at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:386)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  <+33> (ApplicationFilterChain.java:290) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ApplicationDispatcher.java:646) (ApplicationDispatcher.java:551) (ApplicationDispatcher.java:488) (OldDecorator2NewDecorator.java:46) (BaseWebAppDecorator.java:33) (SiteMeshFilter.java:84) (SitemeshPageFilter.java:124) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.remoteapps.modules.permissions.ApiScopingFilter.doFilter(ApiScopingFilter.java:71)  <+41> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SecurityFilter.java:234) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (TrustedApplicationsFilter.java:98) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (BaseLoginFilter.java:157) (JiraLoginFilter.java:70) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66) (OAuthFilter.java:71) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ProfilingFilter.java:99) (JIRAProfilingFilter.java:19) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractJohnsonFilter.java:71) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (UrlRewriteFilter.java:738) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (GzipFilter.java:80) (GzipFilter.java:51) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.remoteapps.modules.oauth.OAuth2LOFilter.doFilter(OAuth2LOFilter.java:70)  <+47> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (JWDSendRedirectFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractCachingFilter.java:33) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AbstractEncodingFilter.java:41) (AbstractHttpFilter.java:31) (PathMatchingEncodingFilter.java:49) (AbstractHttpFilter.java:31) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ActiveRequestsFilter.java:346) (ActiveRequestsFilter.java:463) (ActiveRequestsFilter.java:173) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (JiraStartupChecklistFilter.java:75) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (MultiTenantServletFilter.java:91) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (StandardWrapperValve.java:233) (StandardContextValve.java:191) (StandardHostValve.java:127) (ErrorReportValve.java:102) (StandardEngineValve.java:109) (AccessLogValve.java:554) (CoyoteAdapter.java:298) (Http11Processor.java:859) (Http11Protocol.java:588) (JIoEndpoint.java:489)
        at java.lang.Thread.run(Unknown Source)
Caused by: com.atlassian.upm.license.storage.lib.LazyReference$InitializationException: com.atlassian.upm.license.storage.lib.PluginLicenseStoragePluginUnresolvedException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerAccessorImpl': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/atlassian/upm/license/storage/plugin/PluginLicenseStorageManager
        at com.atlassian.upm.license.storage.lib.LazyReference.getInterruptibly(LazyReference.java:167)
        at com.atlassian.upm.license.storage.lib.LazyReference.get(LazyReference.java:120)
        at com.atlassian.upm.license.storage.lib.ManagerAccessor.getStorageManager(ManagerAccessor.java:63)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.getStorageManager(ThirdPartyPluginLicenseStorageManagerImpl.java:304)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.access$100(ThirdPartyPluginLicenseStorageManagerImpl.java:25)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl$2.call(ThirdPartyPluginLicenseStorageManagerImpl.java:66)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.execute(ThirdPartyPluginLicenseStorageManagerImpl.java:272)
        ... 188 more
Caused by: com.atlassian.upm.license.storage.lib.PluginLicenseStoragePluginUnresolvedException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerAccessorImpl': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/atlassian/upm/license/storage/plugin/PluginLicenseStorageManager
        at com.atlassian.upm.license.storage.lib.ManagerAccessor$1.create(ManagerAccessor.java:36)
        at com.atlassian.upm.license.storage.lib.ManagerAccessor$1.create(ManagerAccessor.java:23)
        at com.atlassian.upm.license.storage.lib.LazyReference$Sync.run(LazyReference.java:377)
        at com.atlassian.upm.license.storage.lib.LazyReference.getInterruptibly(LazyReference.java:158)
		at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.getStorageManager(ThirdPartyPluginLicenseStorageManagerImpl.java:304)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.access$100(ThirdPartyPluginLicenseStorageManagerImpl.java:25)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl$2.call(ThirdPartyPluginLicenseStorageManagerImpl.java:70)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl$2.call(ThirdPartyPluginLicenseStorageManagerImpl.java:66)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.execute(ThirdPartyPluginLicenseStorageManagerImpl.java:272)
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerImpl.getLicense(ThirdPartyPluginLicenseStorageManagerImpl.java:74)
        at de.iconcept.ictime.servlets.LicenseServlet.initVelocityContext(LicenseServlet.java:181)
        at de.iconcept.ictime.servlets.LicenseServlet.doGet(LicenseServlet.java:90)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at com.atlassian.plugin.servlet.DelegatingPluginServlet.service(DelegatingPluginServlet.java:42)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at com.atlassian.plugin.servlet.ServletModuleContainerServlet.service(ServletModuleContainerServlet.java:52)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)  <+10> (ApplicationFilterChain.java:290) (ApplicationFilterChain.java:206) (ChainedFilterStepRunner.java:78) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (HeaderSanitisingFilter.java:44) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (IteratingFilterChain.java:46) (DelegatingPluginFilter.java:66)
        at com.atlassian.labs.botkiller.BotKillerFilter.doFilter(BotKillerFilter.java:36)  <+3> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66)
        at com.atlassian.jira.tzdetect.IncludeResourcesFilter.doFilter(IncludeResourcesFilter.java:39)  <+19> (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (DelegatingPluginFilter.java:66) (ContextFilter.java:25) (DelegatingPluginFilter.java:74) (IteratingFilterChain.java:42) (ServletFilterModuleContainerFilter.java:77) (ServletFilterModuleContainerFilter.java:63) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (AccessLogFilter.java:103) (AccessLogFilter.java:87) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (XsrfTokenAdditionRequestFilter.java:54) (ApplicationFilterChain.java:235) (ApplicationFilterChain.java:206) (SiteMeshFilter.java:129) (SiteMeshFilter.java:77)
        ... 96 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerAccessorImpl': Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: com/atlassian/upm/license/storage/plugin/PluginLicenseStorageManager
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1338)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
        at com.atlassian.upm.license.storage.lib.ManagerAccessor$1.create(ManagerAccessor.java:31)
        ... 149 more
Caused by: java.lang.NoClassDefFoundError: com/atlassian/upm/license/storage/plugin/PluginLicenseStorageManager
        at com.atlassian.upm.license.storage.lib.ThirdPartyPluginLicenseStorageManagerAccessorImpl.afterPropertiesSet(ThirdPartyPluginLicenseStorageManagerAccessorImpl.java:23)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
        ... 155 more
Caused by: java.lang.ClassNotFoundException: com.atlassian.upm.license.storage.plugin.PluginLicenseStorageManager
        at org.apache.felix.framework.ModuleImpl.access$200(ModuleImpl.java:73)
        at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1690)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 158 more

So obviously the jira classloader wasnt able to load the PluginLicenseStorageManger, which is very confusing regarding the fact that the customer has an UPM 2+ installed. I thought the PluginLicenseStorageManager is only necessary if there is no UPM.

To implement the licensing support in our plugin, I followed the tutorial at https://developer.atlassian.com/display/UPM/Understanding+the+Generated+License+API+Support and everything was working fine in our own environments. This is a part of the pom.xml of our plugin:

<dependencies>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-api</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- Add dependency on jira-core if you want access to JIRA implementation classes as well as the sanctioned API. -->
        <!-- This is not normally recommended, but may be required eg when migrating a plugin originally developed against JIRA 4.x -->
        <!--
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-core</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        -->
        <dependency>
            <groupId>com.atlassian.templaterenderer</groupId>
            <artifactId>atlassian-template-renderer-api</artifactId>
            <version>1.1.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-api</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-tests</artifactId>
            <version>${jira.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-func-tests</artifactId>
            <version>${jira.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.8.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.1.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-core-asl</artifactId>
            <version>1.6.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.activeobjects</groupId>
            <artifactId>activeobjects-plugin</artifactId>
            <version>0.19.3</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.sal</groupId>
            <artifactId>sal-api</artifactId>
            <version>2.4.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.plugins.rest</groupId>
            <artifactId>atlassian-rest-common</artifactId>
            <version>1.0.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.upm</groupId>
            <artifactId>plugin-license-storage-lib</artifactId>
            <version>${upm.license.compatibility.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.upm</groupId>
            <artifactId>plugin-license-storage-plugin</artifactId>
            <version>${upm.license.compatibility.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.upm</groupId>
            <artifactId>licensing-api</artifactId>
            <version>${upm.license.compatibility.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.upm</groupId>
            <artifactId>upm-api</artifactId>
            <version>${upm.license.compatibility.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.osgi</groupId>
            <artifactId>spring-osgi-core</artifactId>
            <version>1.1.3</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>com.atlassian.maven.plugins</groupId>
                <artifactId>maven-jira-plugin</artifactId>
                <version>${amps.version}</version>
                <extensions>true</extensions>
                <configuration>
                    <productVersion>${jira.version}</productVersion>
                    <productDataVersion>${jira.version}</productDataVersion>
                    <instructions>
                        <Private-Package>com.atlassian.upm.license.storage.lib*</Private-Package>
                        <Import-Package>
                        com.atlassian.upm.api.license.entity;version="2.0.1", 
                        com.atlassian.upm.api.license;version="2.0.1",
                        com.atlassian.upm.api.util;version="2.0.1",
                        com.atlassian.upm.license.storage.plugin;version="${upm.license.compatibility.version}"
                        </Import-Package>
                    </instructions>
                    <bundledArtifacts>
                        <bundledArtifact>
                            <groupId>com.atlassian.upm</groupId>
                            <artifactId>atlassian-universal-plugin-manager-plugin</artifactId>
                            <version>1.6.3</version>
                        </bundledArtifact>
                        <bundledArtifact>
                            <groupId>com.atlassian.upm</groupId>
                            <artifactId>plugin-license-storage-plugin</artifactId>
                            <version>${upm.license.compatibility.version}</version>
                        </bundledArtifact>
                    </bundledArtifacts>
                    <pluginDependencies>
			            <pluginDependency>
			                <groupId>com.atlassian.upm</groupId>
			                <artifactId>plugin-license-storage-plugin</artifactId>
			            </pluginDependency>
		    </pluginDependencies>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-storage-plugin</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}</outputDirectory>
                            <includeArtifactIds>plugin-license-storage-plugin</includeArtifactIds>
                            <stripVersion>true</stripVersion>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <properties>
        <jira.version>5.0.5</jira.version>
        <amps.version>3.9.1</amps.version>
        <upm.license.compatibility.version>2.3</upm.license.compatibility.version>
    </properties>

As you can see, I did exactly what is suggested by the license tutorial, still some customers get this ClassNotFoundException.

My next step was to try the alternate licensing deployment model, as explained at https://developer.atlassian.com/display/UPM/Alternate+Deployment+Model+for+Licensed+Plugins , and to let the customer install our plugin with the generated OBR instead of the JAR. But after having our plugin installed that way, the customer suddenly noticed that their evaluation version of the famous TEMPO plugin has deactivated itself. Even a deinstallation of our plugin was not enough to activate the TEMPO plugin again.

To be honest, we had a hard time getting the license support to work in our own environments without knowing exactly the different purposes of the plugin storage license plugin and the UPM, but its even more frustrating to see it not working for some customers without any exact clue. As a sidenote, we developed the plugin with sdk 3.11, which should be fine I guess.

We would really appreciate anyone having some more hints on implementing the license support in a way that it works in every environment. At least more information than the tutorials include would be helpful, because we did everything suggested there :)

Thanks!

2 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

4 votes
Answer accepted
BenW
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
July 29, 2012

Hi jtwic,

A couple things stood out to me when looking at your pom.xml snippet. First, your plugin-license-storage-plugin dependency should be provided-scoped. Only the plugin-license-storage-lib artifact should be compile-scoped.

Secondly, you should decide whether you want to distribute a JAR or an OBR. Most plugin vendors distribute with a JAR unless they run into classpath issues requiring them to use the OBR path. Your problems may or may not require you to use an OBR - depending on what happens after my recommended fixes.

But your pom in its current state will only work when distributed as an OBR and not as a JAR because the JAR distribution model requires the four declared packages to be specified as DynamicImport-Package. Currently you have them as Import-Package, which should only be used for the OBR solution.

So to recap, what you should do to resolve (or at least better diagnose) your problem, based on the above pom.xml, is:

  • If deploying as a JAR:
    • plugin-license-storage-plugin should be provided scoped
    • Switch Import-Package to be DynamicImport-Package
    • Remove pluginDependencies section (it is only used for OBRs)
  • If deploying as an OBR:
    • plugin-license-storage-plugin should be provided scoped
    • Remove your Import-Package section as currently you are specifying it to import the required licensing libraries but not any additional libraries that your plugin requires. If unspecified, the plugins framework will determine these for you automatically.

As for the purpose of the Plugin License Storage artifacts, the Plugin License Storage library is used by your plugins at all times. It is the gateway library from your plugin into the licensing system. However, the "licensing system" differs based on the environment - if UPM 2.x is installed then the licensing is provided by UPM 2. Otherwise, it is provided by the Plugin License Storage plugin. I hope this clears it up a bit.

Ben

EddieW
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.
March 21, 2013

@ben, I wonder if you wouldn't mind taking a look at https://answers.atlassian.com/questions/150727/user-getting-license-storage-exception-with-supported-version-of-jira-and-upm, as my plugin aligned to your advice above, and uses supported versions of JIRA and UPM, but the user still suffers this error. A number of other user's successfully installed.

Pablo Beltran
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.
July 7, 2015

It did not work for me: I've removed the Import package and no success! I've also verified the scope of the plugin-license-storage-plugin is set to "provided" (OBR). Any alternative idea?

0 votes
Tobias Reibling
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.
July 30, 2012

Thank you Ben for you answer, it made me understand some things a little bit more, but I still got 2 questions:

1) Am I able to get the ThirdPartyPluginLicenseStorageManger with the ComponentAccessor instead of injecting it through the constructor of the classes that use it? The reason for my question is, that I do a license check in some condition classes which determine whether to show or to hide sections of the main menu of our plugin.

Therefore the ClassNotFoundException could be raised because I am injecting the ThirdPartyPluginLicenseStorageManager too early. I already tried to get it by calling ComponentAccessor.getComponent(ThirdPartyPluginLicenseStorageManager.class) but it always returns null.

2) Refering to the tutorial to deploy our plugin as a jar, it says that if the target environment doesnt provide the version of the plugin license storage plugin declared in the pom.xml, it will automatically update it by the bundledArtifact instructions. Is it possible for me to provide our plugin as a jar without the auto update funtionality, even it that means it will only run in an appropiate environment? Basically we want to prevent our plugin from changing the customers environment in any way.

Thanks!

BenW
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
July 30, 2012

1) I don't believe using a ComponentAccessor will work (but have not confirmed this either way). Constructor injection is preferred.

2) The functionality you refer to happens when your plugin requires version X of Plugin License Storage but only an earlier version is installed. In that case, since your plugin requires a newer version, it will have to install the newer version. You can't get around this - otherwise, your plugin may not be able to access newer functionality and bugfixes included in a newer version.

TAGS
AUG Leaders

Atlassian Community Events