You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@geronimo.apache.org by Jeremias Maerki <de...@jeremias-maerki.ch> on 2010/05/31 17:52:39 UTC

Trouble with Geronimo's javax.mail under OSGi

I'd like to share my experience with the Geronimo javax.mail bundles.
I've had to resort to a work-around in the end to get this to work after
spending half a day tracking down the problem.

I have an OSGi-based application and only use some Geronimo bundles. I'm
not actually running Geronimo. I've installed the following bundles in
my Apache Felix Karaf instance:

- geronimo-javamail_1.4_spec-1.7.jar
- geronimo-javamail_1.4_provider-1.8.jar
- geronimo-osgi-registry-1.0.jar

What I'm building is a bundle that forwards certain events from the
EventAdmin to e-mail. I've enabled debug output so I get some idea
what's going on in the background. When an event is received, I can see
that the provider information is found and loaded from the "provider"
bundle (ID 185 in this case).

> Loading META-INF/javamail.providers from bundle://185.0:1/META-INF/javamail.default.providers

But when I'm trying to send an e-mail, I get this exception:

> 17:25:12,615|ERROR| Thread-85    | EMailAdapter                     | wod.job.events.mail.EMailAdapter  127 | Error sending e-mail: Unable to load class for provider: protocol=smtp; type=javax.mail.Pr
> ovider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apache Software Foundation;version=1.0
> javax.mail.NoSuchProviderException: Unable to load class for provider: protocol=smtp; type=javax.mail.Provider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apa
> che Software Foundation;version=1.0
>         at javax.mail.Session.getService(Session.java:494)
>         at javax.mail.Session.getTransport(Session.java:387)
>         at javax.mail.Session.getTransport(Session.java:347)
>         at javax.mail.Session.getTransport(Session.java:376)
>         at javax.mail.Transport.send(Transport.java:67)
>         at javax.mail.Transport.send(Transport.java:48)
>         at ch.jm.wod.job.events.mail.EMailAdapter.handleEvent(EMailAdapter.java:124)
>         at org.apache.felix.eventadmin.impl.tasks.HandlerTaskImpl.execute(HandlerTaskImpl.java:87)
>         at org.apache.felix.eventadmin.impl.tasks.SyncDeliverTasks$1.run(SyncDeliverTasks.java:228)
>         at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown Source)
>         at java.lang.Thread.run(Thread.java:619)
> Caused by: java.lang.ClassNotFoundException: org.apache.geronimo.javamail.transport.smtp.SMTPTransport
>         at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:726)
>         at org.apache.felix.framework.ModuleImpl.access$100(ModuleImpl.java:60)
>         at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1629)
>         at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
>         at java.lang.Class.forName0(Native Method)
>         at java.lang.Class.forName(Class.java:247)
>         at org.apache.geronimo.osgi.locator.ProviderLocator.loadClass(ProviderLocator.java:195)
>         at javax.mail.Session.getService(Session.java:492)
>         ... 10 more

After some debugging, I found that while the providers are detected
properly, they are not loaded properly. Session.getClassLoader() checks
if there's a ContextClassLoader in the current thread which is what's
present in my case. The ClassLoader is a sun.misc.Launcher$AppClassLoader@601bb1
which seems to be the one with which Felix Karaf is started. So Session.getClassLoader()
takes the first ClassLoader it finds. Session.getService then tries to
actually load that class using ProviderLocator.loadClass(String, Class,
ClassLoader) which simply uses the given ClassLoader to load the class.
Since the Launcher$AppClassLoader doesn't see the classes in the
provider bundle, I get the ClassNotFoundException.

In the end I had to resort to a work-around: I've put the spec and
provider JARs in the endorsed directory and mapped the javax.mail.*
packages to the OSGi frameworks classloader. With this done, I get the
following in debug output and sending e-mail works:

> Loading javamail.default.providers from jar:file:/C:/Dev/..../karaf/endorsed/geronimo-javamail_1.4_provider-1.8.jar!/META-INF/javamail.default.providers

Obviously, that's not the nicest solution.

I've looked into loading classes using the standard SPI mechanism
(META-INF/services) under OSGi myself with [1], so I know a few things
about how this can be done. Essentially, I think MailProviderRegistry
needs to store the Bundle besides the URL to the javamail*.providers so
it can later load the provider classes using that Bundle's ClassLoader.
But that will mean extending the Provider class so it can carry the
Bundle for the Session.getService() method to load the providers.

So far, I haven't made any changes to geronimo-javamail_1.4_spec because
I wanted to get some input from the authors of that code. Maybe there's
a better way to do this. I'm also wondering why noone else seems to be
having that problem. I haven't found anything that fits exactly to my
problem on the net.

Any thoughts on this are appreciated.

[1] http://www.jeremias-maerki.ch/development/osgi/jar-services.html

Thanks,
Jeremias Maerki


Re: Trouble with Geronimo's javax.mail under OSGi

Posted by Jeremias Maerki <de...@jeremias-maerki.ch>.
On 01.06.2010 11:56:03 Rick McGuire wrote:
> On 5/31/2010 11:52 AM, Jeremias Maerki wrote:
> > I'd like to share my experience with the Geronimo javax.mail bundles.
> > I've had to resort to a work-around in the end to get this to work after
> > spending half a day tracking down the problem.
> >
> > I have an OSGi-based application and only use some Geronimo bundles. I'm
> > not actually running Geronimo. I've installed the following bundles in
> > my Apache Felix Karaf instance:
> >
> > - geronimo-javamail_1.4_spec-1.7.jar
> > - geronimo-javamail_1.4_provider-1.8.jar
> > - geronimo-osgi-registry-1.0.jar
> >
> > What I'm building is a bundle that forwards certain events from the
> > EventAdmin to e-mail. I've enabled debug output so I get some idea
> > what's going on in the background. When an event is received, I can see
> > that the provider information is found and loaded from the "provider"
> > bundle (ID 185 in this case).
> >
> >    
> >> Loading META-INF/javamail.providers from bundle://185.0:1/META-INF/javamail.default.providers
> >>      
> > But when I'm trying to send an e-mail, I get this exception:
> >
> >    
> >> 17:25:12,615|ERROR| Thread-85    | EMailAdapter                     | wod.job.events.mail.EMailAdapter  127 | Error sending e-mail: Unable to load class for provider: protocol=smtp; type=javax.mail.Pr
> >> ovider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apache Software Foundation;version=1.0
> >> javax.mail.NoSuchProviderException: Unable to load class for provider: protocol=smtp; type=javax.mail.Provider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apa
> >> che Software Foundation;version=1.0
> >>          at javax.mail.Session.getService(Session.java:494)
> >>          at javax.mail.Session.getTransport(Session.java:387)
> >>          at javax.mail.Session.getTransport(Session.java:347)
> >>          at javax.mail.Session.getTransport(Session.java:376)
> >>          at javax.mail.Transport.send(Transport.java:67)
> >>          at javax.mail.Transport.send(Transport.java:48)
> >>          at ch.jm.wod.job.events.mail.EMailAdapter.handleEvent(EMailAdapter.java:124)
> >>          at org.apache.felix.eventadmin.impl.tasks.HandlerTaskImpl.execute(HandlerTaskImpl.java:87)
> >>          at org.apache.felix.eventadmin.impl.tasks.SyncDeliverTasks$1.run(SyncDeliverTasks.java:228)
> >>          at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown Source)
> >>          at java.lang.Thread.run(Thread.java:619)
> >> Caused by: java.lang.ClassNotFoundException: org.apache.geronimo.javamail.transport.smtp.SMTPTransport
> >>          at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:726)
> >>          at org.apache.felix.framework.ModuleImpl.access$100(ModuleImpl.java:60)
> >>          at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1629)
> >>          at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
> >>          at java.lang.Class.forName0(Native Method)
> >>          at java.lang.Class.forName(Class.java:247)
> >>          at org.apache.geronimo.osgi.locator.ProviderLocator.loadClass(ProviderLocator.java:195)
> >>          at javax.mail.Session.getService(Session.java:492)
> >>          ... 10 more
> >>      
> > After some debugging, I found that while the providers are detected
> > properly, they are not loaded properly. Session.getClassLoader() checks
> > if there's a ContextClassLoader in the current thread which is what's
> > present in my case. The ClassLoader is a sun.misc.Launcher$AppClassLoader@601bb1
> > which seems to be the one with which Felix Karaf is started. So Session.getClassLoader()
> > takes the first ClassLoader it finds. Session.getService then tries to
> > actually load that class using ProviderLocator.loadClass(String, Class,
> > ClassLoader) which simply uses the given ClassLoader to load the class.
> > Since the Launcher$AppClassLoader doesn't see the classes in the
> > provider bundle, I get the ClassNotFoundException.
> >
> > In the end I had to resort to a work-around: I've put the spec and
> > provider JARs in the endorsed directory and mapped the javax.mail.*
> > packages to the OSGi frameworks classloader. With this done, I get the
> > following in debug output and sending e-mail works:
> >
> >    
> >> Loading javamail.default.providers from jar:file:/C:/Dev/..../karaf/endorsed/geronimo-javamail_1.4_provider-1.8.jar!/META-INF/javamail.default.providers
> >>      
> > Obviously, that's not the nicest solution.
> >
> > I've looked into loading classes using the standard SPI mechanism
> > (META-INF/services) under OSGi myself with [1], so I know a few things
> > about how this can be done. Essentially, I think MailProviderRegistry
> > needs to store the Bundle besides the URL to the javamail*.providers so
> > it can later load the provider classes using that Bundle's ClassLoader.
> > But that will mean extending the Provider class so it can carry the
> > Bundle for the Session.getService() method to load the providers.
> >
> > So far, I haven't made any changes to geronimo-javamail_1.4_spec because
> > I wanted to get some input from the authors of that code. Maybe there's
> > a better way to do this. I'm also wondering why noone else seems to be
> > having that problem. I haven't found anything that fits exactly to my
> > problem on the net.
> >
> > Any thoughts on this are appreciated.
> >    
> 
> I took a second look at how the ProviderLocator is handling this, and 
> this should be working without the OSGi registory.  However, it will 
> only work if you are using the mail uber jar rather than using the spec 
> and provider bundles separately.  That's really the intended way to use 
> these.  The combined jar can be found here:
> 
> http://repo1.maven.org/maven2/org/apache/geronimo/javamail/geronimo-javamail_1.4_mail/1.8/
> 
> This should work without installing the geronimo-osgi-registry bundle 
> first.
> 
> Rick

Thanks, Rick. I wasn't aware that there was a combined bundle. That's
definitely another way to work-around the provider problem as long as
you don't need additional providers. I can live with that. But the
problem with Session.getClassLoader() about the ContextClassLoader is
still getting in the way in my case. I've had to do the following to
make it work:

            ClassLoader bakCL = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(null);
            try {
                Transport.send(msg);
            } finally {
                Thread.currentThread().setContextClassLoader(bakCL);
            }

Just getting the first class loader that may fit is probably too easy.
In Apache XML Graphics Commons, we try multiple class loaders until we
really have to give up loading a particular provider class.

At least I now have a satisfying solution that doesn't have to resort to
providing javax.mail support via the endorsed mechanism.

<snip/>

Thanks,
Jeremias Maerki


Re: Trouble with Geronimo's javax.mail under OSGi

Posted by Rick McGuire <ri...@gmail.com>.
On 5/31/2010 11:52 AM, Jeremias Maerki wrote:
> I'd like to share my experience with the Geronimo javax.mail bundles.
> I've had to resort to a work-around in the end to get this to work after
> spending half a day tracking down the problem.
>
> I have an OSGi-based application and only use some Geronimo bundles. I'm
> not actually running Geronimo. I've installed the following bundles in
> my Apache Felix Karaf instance:
>
> - geronimo-javamail_1.4_spec-1.7.jar
> - geronimo-javamail_1.4_provider-1.8.jar
> - geronimo-osgi-registry-1.0.jar
>
> What I'm building is a bundle that forwards certain events from the
> EventAdmin to e-mail. I've enabled debug output so I get some idea
> what's going on in the background. When an event is received, I can see
> that the provider information is found and loaded from the "provider"
> bundle (ID 185 in this case).
>
>    
>> Loading META-INF/javamail.providers from bundle://185.0:1/META-INF/javamail.default.providers
>>      
> But when I'm trying to send an e-mail, I get this exception:
>
>    
>> 17:25:12,615|ERROR| Thread-85    | EMailAdapter                     | wod.job.events.mail.EMailAdapter  127 | Error sending e-mail: Unable to load class for provider: protocol=smtp; type=javax.mail.Pr
>> ovider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apache Software Foundation;version=1.0
>> javax.mail.NoSuchProviderException: Unable to load class for provider: protocol=smtp; type=javax.mail.Provider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apa
>> che Software Foundation;version=1.0
>>          at javax.mail.Session.getService(Session.java:494)
>>          at javax.mail.Session.getTransport(Session.java:387)
>>          at javax.mail.Session.getTransport(Session.java:347)
>>          at javax.mail.Session.getTransport(Session.java:376)
>>          at javax.mail.Transport.send(Transport.java:67)
>>          at javax.mail.Transport.send(Transport.java:48)
>>          at ch.jm.wod.job.events.mail.EMailAdapter.handleEvent(EMailAdapter.java:124)
>>          at org.apache.felix.eventadmin.impl.tasks.HandlerTaskImpl.execute(HandlerTaskImpl.java:87)
>>          at org.apache.felix.eventadmin.impl.tasks.SyncDeliverTasks$1.run(SyncDeliverTasks.java:228)
>>          at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown Source)
>>          at java.lang.Thread.run(Thread.java:619)
>> Caused by: java.lang.ClassNotFoundException: org.apache.geronimo.javamail.transport.smtp.SMTPTransport
>>          at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:726)
>>          at org.apache.felix.framework.ModuleImpl.access$100(ModuleImpl.java:60)
>>          at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1629)
>>          at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
>>          at java.lang.Class.forName0(Native Method)
>>          at java.lang.Class.forName(Class.java:247)
>>          at org.apache.geronimo.osgi.locator.ProviderLocator.loadClass(ProviderLocator.java:195)
>>          at javax.mail.Session.getService(Session.java:492)
>>          ... 10 more
>>      
> After some debugging, I found that while the providers are detected
> properly, they are not loaded properly. Session.getClassLoader() checks
> if there's a ContextClassLoader in the current thread which is what's
> present in my case. The ClassLoader is a sun.misc.Launcher$AppClassLoader@601bb1
> which seems to be the one with which Felix Karaf is started. So Session.getClassLoader()
> takes the first ClassLoader it finds. Session.getService then tries to
> actually load that class using ProviderLocator.loadClass(String, Class,
> ClassLoader) which simply uses the given ClassLoader to load the class.
> Since the Launcher$AppClassLoader doesn't see the classes in the
> provider bundle, I get the ClassNotFoundException.
>
> In the end I had to resort to a work-around: I've put the spec and
> provider JARs in the endorsed directory and mapped the javax.mail.*
> packages to the OSGi frameworks classloader. With this done, I get the
> following in debug output and sending e-mail works:
>
>    
>> Loading javamail.default.providers from jar:file:/C:/Dev/..../karaf/endorsed/geronimo-javamail_1.4_provider-1.8.jar!/META-INF/javamail.default.providers
>>      
> Obviously, that's not the nicest solution.
>
> I've looked into loading classes using the standard SPI mechanism
> (META-INF/services) under OSGi myself with [1], so I know a few things
> about how this can be done. Essentially, I think MailProviderRegistry
> needs to store the Bundle besides the URL to the javamail*.providers so
> it can later load the provider classes using that Bundle's ClassLoader.
> But that will mean extending the Provider class so it can carry the
> Bundle for the Session.getService() method to load the providers.
>
> So far, I haven't made any changes to geronimo-javamail_1.4_spec because
> I wanted to get some input from the authors of that code. Maybe there's
> a better way to do this. I'm also wondering why noone else seems to be
> having that problem. I haven't found anything that fits exactly to my
> problem on the net.
>
> Any thoughts on this are appreciated.
>    

I took a second look at how the ProviderLocator is handling this, and 
this should be working without the OSGi registory.  However, it will 
only work if you are using the mail uber jar rather than using the spec 
and provider bundles separately.  That's really the intended way to use 
these.  The combined jar can be found here:

http://repo1.maven.org/maven2/org/apache/geronimo/javamail/geronimo-javamail_1.4_mail/1.8/

This should work without installing the geronimo-osgi-registry bundle 
first.

Rick
> [1] http://www.jeremias-maerki.ch/development/osgi/jar-services.html
>
> Thanks,
> Jeremias Maerki
>
>
>    


Re: Trouble with Geronimo's javax.mail under OSGi

Posted by Rick McGuire <ri...@gmail.com>.
On 5/31/2010 11:52 AM, Jeremias Maerki wrote:
> I'd like to share my experience with the Geronimo javax.mail bundles.
> I've had to resort to a work-around in the end to get this to work after
> spending half a day tracking down the problem.
>
> I have an OSGi-based application and only use some Geronimo bundles. I'm
> not actually running Geronimo. I've installed the following bundles in
> my Apache Felix Karaf instance:
>
> - geronimo-javamail_1.4_spec-1.7.jar
> - geronimo-javamail_1.4_provider-1.8.jar
> - geronimo-osgi-registry-1.0.jar
>
> What I'm building is a bundle that forwards certain events from the
> EventAdmin to e-mail. I've enabled debug output so I get some idea
> what's going on in the background. When an event is received, I can see
> that the provider information is found and loaded from the "provider"
> bundle (ID 185 in this case).
>
>    
>> Loading META-INF/javamail.providers from bundle://185.0:1/META-INF/javamail.default.providers
>>      
> But when I'm trying to send an e-mail, I get this exception:
>
>    
>> 17:25:12,615|ERROR| Thread-85    | EMailAdapter                     | wod.job.events.mail.EMailAdapter  127 | Error sending e-mail: Unable to load class for provider: protocol=smtp; type=javax.mail.Pr
>> ovider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apache Software Foundation;version=1.0
>> javax.mail.NoSuchProviderException: Unable to load class for provider: protocol=smtp; type=javax.mail.Provider$Type@10c60d5; class=org.apache.geronimo.javamail.transport.smtp.SMTPTransport; vendor=Apa
>> che Software Foundation;version=1.0
>>          at javax.mail.Session.getService(Session.java:494)
>>          at javax.mail.Session.getTransport(Session.java:387)
>>          at javax.mail.Session.getTransport(Session.java:347)
>>          at javax.mail.Session.getTransport(Session.java:376)
>>          at javax.mail.Transport.send(Transport.java:67)
>>          at javax.mail.Transport.send(Transport.java:48)
>>          at ch.jm.wod.job.events.mail.EMailAdapter.handleEvent(EMailAdapter.java:124)
>>          at org.apache.felix.eventadmin.impl.tasks.HandlerTaskImpl.execute(HandlerTaskImpl.java:87)
>>          at org.apache.felix.eventadmin.impl.tasks.SyncDeliverTasks$1.run(SyncDeliverTasks.java:228)
>>          at EDU.oswego.cs.dl.util.concurrent.PooledExecutor$Worker.run(Unknown Source)
>>          at java.lang.Thread.run(Thread.java:619)
>> Caused by: java.lang.ClassNotFoundException: org.apache.geronimo.javamail.transport.smtp.SMTPTransport
>>          at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:726)
>>          at org.apache.felix.framework.ModuleImpl.access$100(ModuleImpl.java:60)
>>          at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1629)
>>          at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
>>          at java.lang.Class.forName0(Native Method)
>>          at java.lang.Class.forName(Class.java:247)
>>          at org.apache.geronimo.osgi.locator.ProviderLocator.loadClass(ProviderLocator.java:195)
>>          at javax.mail.Session.getService(Session.java:492)
>>          ... 10 more
>>      
> After some debugging, I found that while the providers are detected
> properly, they are not loaded properly. Session.getClassLoader() checks
> if there's a ContextClassLoader in the current thread which is what's
> present in my case. The ClassLoader is a sun.misc.Launcher$AppClassLoader@601bb1
> which seems to be the one with which Felix Karaf is started. So Session.getClassLoader()
> takes the first ClassLoader it finds. Session.getService then tries to
> actually load that class using ProviderLocator.loadClass(String, Class,
> ClassLoader) which simply uses the given ClassLoader to load the class.
> Since the Launcher$AppClassLoader doesn't see the classes in the
> provider bundle, I get the ClassNotFoundException.
>
> In the end I had to resort to a work-around: I've put the spec and
> provider JARs in the endorsed directory and mapped the javax.mail.*
> packages to the OSGi frameworks classloader. With this done, I get the
> following in debug output and sending e-mail works:
>
>    
>> Loading javamail.default.providers from jar:file:/C:/Dev/..../karaf/endorsed/geronimo-javamail_1.4_provider-1.8.jar!/META-INF/javamail.default.providers
>>      
> Obviously, that's not the nicest solution.
>
> I've looked into loading classes using the standard SPI mechanism
> (META-INF/services) under OSGi myself with [1], so I know a few things
> about how this can be done. Essentially, I think MailProviderRegistry
> needs to store the Bundle besides the URL to the javamail*.providers so
> it can later load the provider classes using that Bundle's ClassLoader.
> But that will mean extending the Provider class so it can carry the
> Bundle for the Session.getService() method to load the providers.
>
> So far, I haven't made any changes to geronimo-javamail_1.4_spec because
> I wanted to get some input from the authors of that code. Maybe there's
> a better way to do this. I'm also wondering why noone else seems to be
> having that problem. I haven't found anything that fits exactly to my
> problem on the net.
>
> Any thoughts on this are appreciated.
>    
The OSGi support in that version is designed to work together with the 
geronimo-osgi-registry bundle to get around these sorts of class loader 
issues.  If you install the registry first, it will detect that the 
javamail bundle is exporting providers and the ProviderLocator code will 
use that registry to locate and load the target classes.  The registry 
bundle can be found here:

http://repo1.maven.org/maven2/org/apache/geronimo/specs/geronimo-osgi-registry/1.0/

Rick
> [1] http://www.jeremias-maerki.ch/development/osgi/jar-services.html
>
> Thanks,
> Jeremias Maerki
>
>
>