I've done quite a deep dive in trying to figure out what seems to be a class loader issue.
I'm writing a plugin that can connect to an imap server. When I was using plugins-version-1 everything related to connecting always worked.
This now also works perfectly....sometimes in some ways, but not others. And I'm pretty sure it comes down to the OSGi container.
I actually have 4 ways to establish this connection to the email server:
1) stand alone unit test from stand alone jvm - always works 100%
2) Confluence -> servlet module - seems to always work
3) Confluence -> xwork module - not working, getting a: java.lang.NoSuchMethodException
4) Confluence -> job module - also doesn't work
So depending on which module my plugin uses it seems to have access to different objects?
I've enabled javax.mail debugging and here is the underlying issue (at least as far down as I know how to dig):
java.lang.NoSuchMethodException:
com.sun.mail.imap.IMAPSSLStore.<init>(javax.mail.Session, javax.mail.URLName)
This exact method is in the mail-1.4.5.jar I'm trying to use. And indeed it is found perfectly using methods (1) and (2) above.
I'm attaching my pom.xml (pom.txt) file as well as I've tried to define both the dependencies properly and the DynamicImport-Package section.
So two question:
* Any ideas why this class isn't being found?
* Why does the Confluence servlet module and xwork module have access to different classes? Shouldn't they be using the same APIs, same class loader?
Community moderators have prevented the ability to post new answers.
Short answer: You have multiple copies of Javax Mail on your classpath. Either remove your "java.mail........" dynamic import statements, or make your "javax.mail:mail" artifact provided-scoped.
Long answer:
I see that you are compile-scoping your "javax.mail:mail" artifact. Anything that is compile scoped does *not* (and should not) be specified as an OSGi bundle instruction (Import Package or Dynamic Import Package) because it will already be found on the classpath of your plugin's bundle. Anything that gets compile-scoped is essentially at the same level as the plugin's own code.
By specifying these dynamic import packages, your plugin is finding conflicting instances of this class: sometimes it uses the one bundled into the plugin, other times it uses the one which is provided from another bundle. And one of these versions does not have that method. You should check and see (via UPM's OSGi tab) in your plugin's supported product versions which package versions, if any, of this bundle are being exported. Best practice for plugins 2 plugins is to use exported packages like this when they exist. But if it either doesn't exist or is too old of a version, then remove the dynamic import packages and keep the compile-scoped artifact.
Additionally, you should only use DynamicImport-Package (as opposed to Import-Package) when you really need to, e.g. when a bundle may be installed at some point during runtime and your plugin needs to dynamically bind to it. This is the case with the Licensing API but should not be the case with any of your other specified packages. Switch those over to a <Import-Package> tag for additional plugin stability.
@Ben, are you looking to double your karma? :-)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
w00t! Great info! I will try toggling those.
I am pretty sure I have tried every iteration of scope and with + withtout DynamicImport-Package. However it's very good to know about the interplay here between those 'directives'.
I have cloned and debugged the JavaMailAPI source as well. I think this might actually have to do with the fact that the JavaMail API is trying to instantiate that class using reflection. Here is the offending code:
Class[] c = {javax.mail.Session.class, javax.mail.URLName.class}; Constructor cons = serviceClass.getConstructor(c);
I think OSGi + reflection = BAD is that right? I think that's what Don Brown told me at AtlasCamp 2011. What is the mitigation strategy for 3rd party libs that use reflection? I'm researching, but I think that's the problem point.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
OK thanks to Ben's comments I tried some more things and seem to be back to a partially working state. Here is my new (pom-v2.txt) Now methods 1, 2, 3 work. 4 does not - that's the scheduled job-module type. Same error. It must be loading classes differently. But I'm going try to hack around it.
I have looked through the OSGi tab from the beginning which is interesting and ususally listed what I thought it would.
I've learned a lot clearly but here are some extra learnings not documented anywhere else:
(I'll write more if I figure things out - Atlassians feel free to correct my so called 'learnings' :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Check out the Job Module docs. Note the part where it says:
In Confluence 4.0.1 and later, Jobs are autowired by Spring (see: CONF-20162 for workarounds in earlier versions).
By the way, you still have two compile-scoped dependencies (JUnit and Google Collections).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
OK I think I got everything working by routing invocations through the ServletModule.
The classloaders in one way or another seem to choke on the internal 'introspection' stuff that the Java API uses. In some cases a class cannot be found when the JavaMailAPI attempts a Class.forName("xyz").newInstance. In other cases I guess it can't read in an internal config file...this is the link to this issue (I'm amazed it's even documented)
http://www.oracle.com/technetwork/java/faq-135477.html#castmultipart
I read along the way that Confluence DOES wire different modules differently via Spring, but I don't know if that directly affects OSGi also. More reading and rereading is immenent :)
Thanks Ben and David for all your help. You guys are total Pro Circuit!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi David,
I'm 100% interested in that issue. Thanks so much for passing it along and all your other help too!!
Brendan
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Brendan: As an aside, when you get over this hurdle, you may also be interested in UPM-1954.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Do you need to update your DynamicImport-Package to be a bit more vague with the package, but more exact on the version, e.g.
com.sun.mail.imap*;version="1.4.5"
instead of
com.sun.mail.imap;version="0.0"
Version 1.4.5 of everything under com.sun.mail.imap
Perhaps it's grabbing a different version of the class which is missing the method? This may be what's resulting in a NoSuchMethodException
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
No half measures -- that's very bountiful.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I added a bounty for this question. Claim it! :)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Community moderators have prevented the ability to post new answers.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.