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

Reply via email to