Thursday, December 14, 2006

Running JBoss Seam on Resin 3.0.2x

Yes, it's working. With little Resin 'compatibility' workaround its' possible to run Seam 1.1 on Resin! In this example it run on Resin 3.0.21.
To make Seam working on Resin the following steps are necessary:

  • Make Resin to 'like' the web.xml by making the namespace empty: <web-app xmlns="">

  • Make Resin use apache xml parser by creating WEB-INF/resin-web.xml and putting the following in it:


    <web-app xmlns="http://caucho.com/ns/resin">

    <system-property javax.xml.parsers.DocumentBuilderFactory="org.apache.xerces.jaxp.DocumentBuilderFactoryImpl"/>
    <system-property javax.xml.parsers.SAXParserFactory="org.apache.xerces.jaxp.SAXParserFactoryImpl"/>

    </web-app>


  • Put xercesImpl.jar in the lib dir of the web app

  • If you want to run Seam in ejb3 micro-container you would have to delete the ejb-30.jar from Resin/lib directory otherwise you will get conflicts.





If it's not possible to delete ejb-30.jar from resin/lib (permissions don't allow or can't interfere with other virtual hosts) the the following can be still done to make ejb-3 work in jboss microcontainer:

Create the following class:


package org.emaps.resin;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Introduces a very specific classloader hack for Resin so that it uses ejb.*
* packages from deployed Seam. This hack wont be needed as soon as Resin
* catches up with ejb-3.
*
* @author Siarhei Dudzin
*
*/
public class ClassloaderHack implements ServletContextListener {

/** Log from apache commons logging */
private static final Log log = LogFactory
.getLog(ServletContextListener.class);

/**
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent arg0) {
// do nothing
}

/**
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent arg0) {
log.info("Starting Resin classloader hack for JBoss Seam");

try {
ClassLoader classLoader = ClassloaderHack.class.getClassLoader();
if (classLoader instanceof com.caucho.loader.DynamicClassLoader) {
com.caucho.loader.DynamicClassLoader resinCL = (com.caucho.loader.DynamicClassLoader) classLoader;

resinCL.addPriorityPackage("javax.persistence.");
resinCL.addPriorityPackage("javax.persistence.spi.");
resinCL.addPriorityPackage("javax.ejb.");
resinCL.addPriorityPackage("javax.ejb.spi.");
}
} catch (Throwable t) {
log.error("Could not get Resin classloader: " + t.getMessage());
t.printStackTrace();
}
}
}



and the following entry in the web.xml before the seam context listener entry:



<!-- Resin classloader hack (needs to be first before all listeners!) -->
<listener>
<listener-class>
org.emaps.resin.ClassloaderHack
</listener-class>
</listener>


This will make sure Resin will use ejb-3 interfaces from your webapp web-inf/lib directory!

That's about it! Enjoy! :)