Hi Jean-Baptiste,

Actually the three points below are not alternatives, the solution requires all 
three points (1. will prevent registering a wrong bundle if addMailcap(String) 
is called, 2. will enable to load this with the javax.activation bundle 
classloader if it is exported and 3. will make the attempt to load it with the 
javax.activation classloader if there is no bundle installed even if there is a 
ThreadContextClassloader defined).

I am aware that relying on dynamic imports is kind of ugly (but still better 
then the current state which relies on the dynamic import of some other 
bundle). The clean solution would be to register the bundle of the class that 
calls the addMailcap(String) method, but I have no idea how this could be 
achieved. (If we were able to determine this bundle this would also work for 
MIME handlers which are actually private to that bundle).

Best regards
Stephan

-----Original Message-----
From: Jean-Baptiste Onofré <j...@nanthrax.net> 
Sent: Montag, 11. Februar 2019 13:03
To: dev@karaf.apache.org
Subject: Re: News from the karaf 4.2.3/activation/saaj-impl/javamail issue on 
Java 8

Hi Stephan,

I think the dynamic import is a nice workaround short term.

I think 3 (with a handler) is more robust long term. WDYT ?

Regards
JB

On 11/02/2019 12:35, Siano, Stephan wrote:
> Hi,
> 
> A little more than a week ago I wrote about an issue about an interference 
> between the way javax.activation is installed on Karaf 4.2.3 for Java 8, and 
> the Javamail and the saaj-impl 1.3.1 bundles and the way they expose MIME 
> handlers, which resulted in a ClassCastException. In the meantime 
> Jean-Baptiste has released a new servicemix wrapper for saaj-impl 1.4.0 
> (1.4.0_2), and with this bundles the ClassCastException goes away (many 
> thanks for that!).
> 
> I have created some test coding for the issue:
> 
> A:
>             Session session = Session.getInstance(System.getProperties());
>             MimeMessage message = new MimeMessage(session);
>             message.setSubject("Testing Subject");
>             message.addHeader("X-Test-Header", "test value");
>             MimeMultipart mp = new MimeMultipart("mixed");
>             BodyPart part = new MimeBodyPart();
>             part.setText("Test body");
>             mp.addBodyPart(part);
>             message.setContent(mp);
>             message.saveChanges();
>             ByteArrayOutputStream bos = new ByteArrayOutputStream();
>             message.writeTo(bos);
> 
> B:
>             MessageFactory messageFactory = MessageFactory.newInstance();
>             SOAPMessage message = messageFactory.createMessage();
>             AttachmentPart attachmentPart = message.createAttachmentPart();
>             attachmentPart.setContentId("contentid");
> 
> On the first glance this seems to work now, I can invoke coding A and coding 
> B in arbitrary order. However, as soon as I have another bundle in the stack 
> that contains a mailcap file and is installed after the javamail bundle, code 
> A will start to fail again after B was invoked. (It will work fine before 
> that). The new error is now that there is no MIME handler registered for 
> text/plain
> 
> I think the root cause for the issue is in the OsgiMailcapCommandMap class.
> 
> If a bundle contains a mailcap file, the extender from the 
> org.apache.servicemix.specs.activation-api-1.1 bundle will call the 
> addMailcap(String line, Bundle bundle) method, which will set the 
> currentBundle attribute and then call addMailcap(String line) from the 
> superclass. Eventually the addCommand() method will be called, which will add 
> the current bundle to the bundles map (with the command as the key). Later in 
> the createDataContentHandler() method this map will be used to look up the 
> bundle and MIME handler is instantiated from the bundle classloader of that 
> bundle.
> 
> This works fine for all MIME handler registered via mailcap file. 
> Unfortunately, the constructor of 
> com.sun.xml.messaging.saaj.soap.AttachmentPartImpl (which is called by the 
> message.createAttachmentPart() call) will just call the addMailcap(String 
> line) method on the default command map, so the currentBundle attribute is 
> not updated and the MIME handlers are registered with the last bundle that 
> registered a MIME handler from a mailcap file. In the first case this is 
> javamail. This even works because the javamail bundle has a 
> "DynamicImport-Package: *" in it's Manifest, so the javamail classloader is 
> actually able to load the MIME handlers from saaj-impl.
> 
> The dirty workaround for this is to add the DynamicImport-Package: * manifest 
> header to all bundles with a mailcap file, but eventually I think the 
> org.apache.servicemix.specs.activation-api-1.1 should be fixed.
> 
> The first solution that comes into my mind would be the following:
> 
>   1.  change the addMailcap(String line, Bundle bundle) method of 
> OsgiMailcapCommandMap in a way that it sets currentBundle to null after 
> calling the addMailcap(line) method. This way the addCommand() method will 
> not add anything to the bundles map for it.
>   2.  Add the DynamicImport-Package: * header to the bundle manifest file. 
> This will allow OsgiMailcapCommandMap to load all Mime handler without 
> registered bundle which point to exported classes with its own ClassLoader.
>   3.  change the createDataContentHandler(String mimeType) to try to load the 
> MIME Handler with its own class loader if no bundle is found before trying 
> the ThreadContextClassloader.
> 
> Alternatively one might try to find out the bundle somehow in the 
> addCommand() method, but I have no good idea how to do that.
> 
> What do you think?
> 
> Best regards
> Stephan
> 

-- 
Jean-Baptiste Onofré
jbono...@apache.org
http://blog.nanthrax.net
Talend - http://www.talend.com

Reply via email to