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