lundi 31 janvier 2011

Minimum set of dependencies for Glassfish 3.0.1 client : The JMS client use case


Glassfish is a great JEE server but when it comes to client classpath, it's the same headache as other JEE servers.
Glassfish documentation tells us to put gf-client.jar on our classpath.
It works well but this tiny JAR comes with a huge classpath which can seriously break your existing code.
So, how can i get a minimal classpath to interact with Glassfish ?
In this post, we'll see how to determine the minimum set of dependencies for a JMS use case : getting a queue connection and post a message on this queue.
The trick exposed here fits in many use cases.

The sample code


import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.Session;
import javax.naming.InitialContext;

import junit.framework.TestCase; 

public class JMSTestCase extends TestCase {

        public void testJMS() throws Exception {

                InitialContext jndi = new InitialContext();
                // Lookup queue connection factory
                QueueConnectionFactory queueConnectionFactory = (QueueConnectionFactory) jndi
                                .lookup("myCF");

                // Lookup queue
                Queue queue = (Queue) jndi.lookup("myQueue");
                // Get queue connection
                QueueConnection qConn = (QueueConnection) queueConnectionFactory
                                .createConnection();

                // Get session
                Session session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);

                // Set the JMS message
                ObjectMessage msg = session.createObjectMessage();
                msg.setObject("Test");

                // Send JMS message
                session.createProducer(queue).send(msg);

        }
}
Add gf-client.jar and jms.jar to your classpath, both found in Glassfish 3.0.1 installation.
The test case should work if you have created the connection factory and the queue.

The trick


You have to put extra arguments on your jvm command line.
The -verbose:class tells your JVM to output to STDOUT every class loaded and where it comes from.
Add this option to your JVM and re-run the test.
Here is a sample output :
Loaded com.sun.enterprise.resource.naming.AdministeredObjectFactory from file:/Users/oschmitt/java/servers/glassfish/glassfishv3.0.1-full/glassfish/modules/connectors-runtime.jar
Loaded com.sun.enterprise.resource.beans.AdministeredObjectResource$1 from file:/Users/oschmitt/java/servers/glassfish/glassfishv3.0.1-full/glassfish/modules/connectors-runtime.jar
Loaded javax.jms.Queue from file:/Users/oschmitt/java/servers/glassfish/glassfishv3.0.1-full/mq/lib/jms.jar
Loaded com.sun.messaging.Destination from file:/Users/oschmitt/java/servers/glassfish/glassfishv3.0.1-full/mq/lib/imq.jar

Capture output in a file, say console-debug.log.
With a little bit of shell magic, you can get your minimal client classpath :
cat console-debug.log|grep "from file"|awk -F "from file:" '{print substr($2,0,length($2)-2)}'|sort|uniq > gf-mini-jars.csv

You should get the following JARs :
glassfish-3.0.1/glassfish/lib/install/applications/jmsra/imqjmsra.jar
glassfish-3.0.1/glassfish/modules/annotation-framework.jar
glassfish-3.0.1/glassfish/modules/appclient.security.jar
glassfish-3.0.1/glassfish/modules/auto-depends.jar
glassfish-3.0.1/glassfish/modules/bean-validator.jar
glassfish-3.0.1/glassfish/modules/common-util.jar
glassfish-3.0.1/glassfish/modules/config-api.jar
glassfish-3.0.1/glassfish/modules/config.jar
glassfish-3.0.1/glassfish/modules/config-types.jar
glassfish-3.0.1/glassfish/modules/connectors-inbound-runtime.jar
glassfish-3.0.1/glassfish/modules/connectors-internal-api.jar
glassfish-3.0.1/glassfish/modules/connectors-runtime.jar
glassfish-3.0.1/glassfish/modules/container-common.jar
glassfish-3.0.1/glassfish/modules/deployment-common.jar
glassfish-3.0.1/glassfish/modules/dol.jar
glassfish-3.0.1/glassfish/modules/ejb-container.jar
glassfish-3.0.1/glassfish/modules/ejb.security.jar
glassfish-3.0.1/glassfish/modules/glassfish-api.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-asm.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-codegen.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-csiv2-idl.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-newtimer.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-omgapi.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-orbgeneric.jar
glassfish-3.0.1/glassfish/modules/glassfish-corba-orb.jar
glassfish-3.0.1/glassfish/modules/glassfish-ee-api.jar
glassfish-3.0.1/glassfish/modules/glassfish-naming.jar
glassfish-3.0.1/glassfish/modules/gmbal.jar
glassfish-3.0.1/glassfish/modules/hk2-core.jar
glassfish-3.0.1/glassfish/modules/internal-api.jar
glassfish-3.0.1/glassfish/modules/javax.jms.jar
glassfish-3.0.1/glassfish/modules/javax.persistence.jar
glassfish-3.0.1/glassfish/modules/javax.resource.jar
glassfish-3.0.1/glassfish/modules/javax.transaction.jar
glassfish-3.0.1/glassfish/modules/jms-core.jar
glassfish-3.0.1/glassfish/modules/jta.jar
glassfish-3.0.1/glassfish/modules/jts.jar
glassfish-3.0.1/glassfish/modules/kernel.jar
glassfish-3.0.1/glassfish/modules/management-api.jar
glassfish-3.0.1/glassfish/modules/orb-connector.jar
glassfish-3.0.1/glassfish/modules/orb-iiop.jar
glassfish-3.0.1/glassfish/modules/security.jar
glassfish-3.0.1/glassfish/modules/tiger-types-osgi.jar
glassfish-3.0.1/glassfish/modules/transaction-internal-api.jar
glassfish-3.0.1/glassfish/modules/work-management.jar
glassfish-3.0.1/mq/lib/imq.jar
glassfish-3.0.1/mq/lib/imqutil.jar

Remove all Glassfish JARs from your classpath and add the loaded JARs : it should work !
Then if you use Maven you can build a dedicated POM, see POM Best Practices.
Two dependencies are not mavenified : imqjmsra and imqutil. You can find them in Glassfish 3.0.1 installation.
You have to put yourself in your local repo or in your proxy repo.

Important note : this trick is quite dirty, you have to re-compute the classpath every time you upgrade Glassfish runtime. Do use it only if it's absolutely necessary.

Contrat Creative Commons
the jee architect cookbook by Olivier SCHMITT est mis à disposition selon les termes de la licence Creative Commons Paternité - Pas d'Utilisation Commerciale - Pas de Modification 3.0 Unported.

Aucun commentaire:

Enregistrer un commentaire