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! :)

Thursday, July 13, 2006

Facelets on Resin

Facelets on Resin would have problems running 'out of the box'. Incorrectly parsed xml would break any attempts to use more or less complexc JavaScript. Other problems like removed DOCTYPE declarations, etc. are possible.

The problem lies in incompatiblities of Resin's xml parser. And it appears that override it pretty easy once you know where is the problem.

So, we download XML implementaion from apache: xercesImpl.jar

Then we put it in our /WEB-INF/lib/ directory

In WEB-INF/resin-web.xml (if it doesn't exist - create it, for syntax refer to the website of resin). Add the following entries:


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


After that everything should be O.K.

It is possible of course to configure this on global level in Resin (check the docs again), but this works with default Resin installation.

Sunday, June 11, 2006

JSF and AJAX together got easier

With ajax4jsf it is possible to embedd ajax capabilities in JSF relatively easy without a single javascript line!

Here is how we do it (example):

<%@ page language="java" contentType="text/html;charset=UTF-8"%>

<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://myfaces.apache.org/sandbox" prefix="s" %>
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t" %>

...


<body>
<f:view>

<a4j:region selfRendered="true">

<h:form id="selectCityForm">

<h:selectOneMenu id="selectCityMenu" value="#{cityHandler.city}" converter="CityBeanConverter">
<a4j:support event="onchange" reRender="editCityPanel" />
<f:selectItems value="#{cityHandler.allCities}" />
</h:selectOneMenu>

<a4j:commandButton id="loadButton"
action="#{cityHandler.ajaxFormSubmit}"
reRender="editCityPanel" value="Load"/>


<a4j:status startText=" Requesting..." startStyle="color:red" stopText=" Done" stopStyle="color:blue"/>


<h:selectBooleanCheckbox id="selectFilter" value="#{cityHandler.hideAlreadySetLatLng}">
<a4j:support event="onchange" reRender="selectCityForm"/>
</h:selectBooleanCheckbox>


</h:form>

...

The form (can be other elements) which gets updated:

...

<h:form id="editCityPanel" style="padding-top: 0.5cm;">
<h:outputLabel id="cityNameLbl" value="Name" for="cityName"/>
<h:inputText id="cityName" value="#{cityHandler.city.name}" required="true" />
</h:form>


Notice there is <a4j:status/> for better feedback. reRender attributes of <a4j:support /> and <a4j:commandButton /> specify id's of elements that need to be rerendered after the actions got triggered.

Friday, January 27, 2006

Receiving duplicate suggestions in InputSuggestAjax component

If you started from the example of myfaces sandbox and eventually got it working, implemented your ownbacking bean but receive duplicate suggestions. In the logs you see that the backing bean is also called twice... The problem may lay in using an example config file with a lot of sandbox components registered there (especially if you took it from SVN), such as:


<component>
<component-type>org.apache.myfaces.InputSuggestAjax</component-type>
<component-class>org.apache.myfaces.custom.inputsuggestajax.InputSuggestAjax</component-class>
</component>



To solve the problem make the <faces-config><faces-config/> empty and start from scratch (i.e. register there only your own backing beans and remove all those components!).