Showing posts with label osgi. Show all posts
Showing posts with label osgi. Show all posts

Monday, June 20, 2011

@ManagedBean inside OSGi bundle in GlassFish (3.1) - part 2

In previous post talked about utilizing javax.annotation.ManagedBean to create a ManagedBean in an OSGi bundle deployed in GlassFish.

A different (better) route would be to use CDI (Contexts and Dependency Injection) and utilize @Inject annotations instead of @Resource and @EJB for injecting the resources.

For this to work, there must be a 'beans.xml' file present. According to the docs:

An application that uses CDI must have a file named beans.xml. The file can be completely empty (it has content only in certain limited situations), but it must be present.

To make this possible in our bundles, added a 'META-INF' directory to the 'src' dir, with an empty 'beans.xml' file underneath.

Then in our bnd definition file (which builds the OSGi bundle for us), we define the resource to be included in our bundle:

Include-Resource:  META-INF/beans.xml=src/META-INF/beans.xml

With this in place, we no longer need to reference the 'com.sun.ejb.containers, com.sun.ejb.spi.io' libraries in our 'Import-Package' entry (since we are not using the ManagedBean annotation directly).

We can now replace all the @EJB and @Resource calls to @Inject.

@ManagedBean inside OSGi bundle in GlassFish (3.1)

Was struggling getting a @ManagedBean to be able compile correctly under GlassFish - needed to add the following packages to the Import-Package entry of the Manifest:

com.sun.ejb.containers,com.sun.ejb.spi.io

This allowed us to have a ManagedBean in the bundle.

For example - want to have a @Singleton class for some processing.

@Singleton
public class TestSingleton {
    public String testMySingleton() {
        return "This is a test from my singleton!";
    }
}

(this would be a javax.annotation.ManagedBean, not a Faces ManagedBean):

@ManagedBean
public class SingBean {
    @EJB
    private TestSingleton testSingleton;

and for testing purposes - within the MDB:

@MessageDriven(mappedName = "jms/MyQueue", activationConfig = {
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class ExtIncMDB {
    @Resource
    SingBean myBean;

Wednesday, August 18, 2010

OSGi, JavaMail, and the mailcap issue

When developing some of the components for our application, I have been seeing some issues with ClassLoaders when creating them as OSGi bundles.

One main case that had me curious for a while was using JavaMail inside an OSGi bundle, and having to send a multipart mail.

The issue was - JavaMail relies on JAF (the activation framework), which houses a file (mailcap) in it's META-INF directory. So, if these (the javamail and jaf) are stored in separate bundles, then javamail cannot access the configuration file to determine which MIME types it can handle, and thus throwing an UnsupportedDataTypeException:

javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative; 

An UnsupportedDataTypeException usually occurs because JAF cannot find the DataContentHandler (DCH) for a given MIME type by reading the mailcap.

Glassfish 3 actually bundles these together in one bundle (modules/mail.jar), but I was still having the issue described above.

So I went down the path trying to figure out what in the world I could do to get past this. You can't really export resources like you do packages in the manifest, so importing into my bnd file didn't work, and even trying to manually force new mailcaps (which seemed to work elsewhere) didn't work:

MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed; x-java-fallback-entry=true");
mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
CommandMap.setDefaultCommandMap(mc);

This is basically just pushing through exactly what is in the mailcap file directly. But - this didn't work either. Odd...

I then went as far as create a new instance of the specific handler that is being used, and testing the support for that DataFlavor:

DataContentHandler dhmm = new com.sun.mail.handlers.multipart_mixed();
DataFlavor[] dtf = dhmm.getTransferDataFlavors();
for (DataFlavor tmpdf : dtf) {
 log.debug("   isSupported? " + tmpdf.getMimeType() + ":" + message.getDataHandler().isDataFlavorSupported(tmpdf));
}

And it shows it is supported: isSupported? multipart/mixed:true

Yet - when sending the message, same Exception. Ugh...

Finally, Sahoo (from the Glassfish team) gave me a suggestion of manipulating the ClassLoaders when I needed to to make the calls, saving the current ClassLoader so it can be put back into place.

In our bundle, we create the session and send the message in two different methods, so this had to be implemented twice, but finally - it worked!

// There is an issue in the OSGi framework preventing the MailCap
// from loading correctly. When getting the session here,
// temporarily set the ClassLoader to the loader inside the bundle
// that houses javax.mail. Reset at the end.
ClassLoader tcl = Thread.currentThread().getContextClassLoader();

try {
    // Set the ClassLoader to the javax.mail bundle loader.
    Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());

    ...
} finally {
    // Reset the ClassLoader where it should be.
    Thread.currentThread().setContextClassLoader(tcl);
}

This is now working fine. I was a bit leery about mucking with the ClassLoaders in here - which was an issue with using JRuby code inside OSGi bundles as well, but this seems to be OK in that we are temporarily changing and immediately changing back.

Wednesday, March 17, 2010

Deciding on a platform

One of the tasks in this new role was to determine which platform to take this application/appliance to. We knew it was to move towards a Java/JEE platform, but we needed to make sure what we were choosing was right for the long term, and had the most viability for expansion and technology.

I have worked with many app servers/web containers in the past, and definitely had my mind on what I wanted to work with, but used the time to research as many alternatives as I could to make sure the conclusion was the right one.

The way this application works, we are relying on being able to plug in new "interfaces" that the core application can talk to - via JMS messaging, etc. The application is built using RoR (Ruby on Rails) with a Postgresql backing store.

Clustering and HA were of a concern as well, but the type of clustering that this application requires was beyond the scope of the normal web/http traffic type clustering that is solved via mod_jk or mod_cluster type solutions - although this can help for certain aspects of it.

JVM-level clustering - such as Terracotta - was also an option, but that didn't really solve what we were looking for as a turn-key solution either - so the decision here is to create our own custom solution, using what was available as a basis for the types of clustering that was needed for that type of traffic. Creating an observer of our JMS cloud(s) to peer for relevant information (via JMX hooks) such as acceptable load thresholds and speaking to other nodes to open/start new modules as need to offset the load.

This is going to be a challenge, but a welcome one. :)

I definitely wanted to utilize the OSGi concepts in creating the daemon like plugins that we would be using, as well as using the framework for monitoring activity, so having that capability was a big factor in the decision making. I looked at other modularity solutions, such as JPF (Java Plugin Framework) and Impala, as well as what Project Jigsaw would bring to the table, but decided OSGi would do well for what we needed.

There were many containers that were looked at, including:
  • Glassfish v2 and v3
  • JBoss 5 and JBoss 6 (M2)
  • Geronimo
  • WebSphere
  • Weblogic
  • resin
and others. The final decision for me boiled down to Glassfish v3 and JBoss 6, because of the JEE6 specifications and where they were headed.

So going forward, we will be building this platform using Glassfish v3 - which is exciting to me, because I always thought Glassfish was a great platform, and coming from the NAS world of old, it was great to see where this was going.

Clustering is a bit of an issue that will need to be tackled, but in reading Bill Shannon's roadmap for clustering in v3.1 of Glassfish, as well as needing to build our own, this was not as much of a deal breaker as I was worried about.

The current application also uses ActiveMessaging to communicate with an ActiveMQ server, and with Glassfish's embedded OpenMQ based messaging system, I think the ability to have as much as we can under one container is a big win in this situation.

Thanks to the support of the Glassfish community, and people such as Arun, Alexis, the Glassfish team (blog and twitter) and the others involved, I think using this going forward is going to a fun and exciting project!