Tuesday, June 23, 2009

Hibernate Event Listeners with Spring

You can configure your Hibernate event listeners via your spring-context.xml.
When you declare your Bean from type org.springframework.orm.hibernate3.LocalSessionFactoryBean you can initilize the property "eventListeners". This attribute is from type Map. The key defines the type of the event listeners (e.g. flush, load, delete, etc.). The value defines the corresponding class which implements the EventListener interface or extend the DefaultEventListener implementation class.


Sample of your context.xml

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
...
<property name="eventListeners">
<map>
<entry key="flush">
<bean class="org.j4fry.hibernate.eventlisteners.FlushEventListener" />
</entry>
</map>
</property>
...
</bean>
Sample of a FlushEventListener

package org.j4fry.hibernate.eventlisteners;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.event.FlushEvent;
import org.hibernate.event.def.DefaultFlushEventListener;

public class FlushEventListener extends DefaultFlushEventListener {
public void onFlush(FlushEvent fe) throws HibernateException {
super.onFlush(fe);
}
}
List of keys and the corresponding Interfaces and implementation-classes
Map-KeyInterfaceDefault implementation class
auto-flushAutoFlushEventListener
deleteDeleteEventListener
dirty-checkDirtyCheckEventListener
evictEvictEventListener
flush-entityFlushEntityEventListener
flushFlushEventListener
load-collectionInitializeCollectionEventListener
loadLoadEventListener
lockLockEventListener
mergeMergeEventListener
create-onflushPersistEventListener
post-deletePostDeleteEventListener
post-insertPostInsertEventListener
post-loadPostLoadEventListener
post-updatePostUpdateEventListener
pre-deletePreDeleteEventListener
pre-insertPreInsertEventListener
pre-loadPreLoadEventListener
pre-updatePreUpdateEventListener
refreshRefreshEventListener
replicateReplicateEventListener
save-updateSaveOrUpdateEventListener

Saturday, June 20, 2009

IE8 script cache and AJAX script replace

Today I tried debugging the MyFaces 2.0 AJAXS scripts in IE8. The debugger is quite nice. The hard side came in when I starting changing the scripts and tried testing my new script versions. IE8 prooved to be a resilient beast like it's anchestors and insisted on running an old script version. The nice button "clear browser cache" in the developer tools didn't do anything. What finally helped was the first menu option in menu "cache" - in german it says: Immer vom Server aktualisieren.
Now that I could step into my Javascript code things got even weirder. I had a simple

<span id="test"><script ... ></span>

construction and I tried do replace element "test" with an AJAX call. So what do you think happened? I did:

item.insertAdjacentHTML('beforeBegin', '<span id="test"><script ... ></span>');

and then checked item.previousSibling. I turned out IE8 had inserted:

<span id="test"></span>

It just left out my new script. I changed the HTML code to look like (don't ask me what gave me the idea to do so, years of suffering train intuition):

<span id="test">
<input type="hidden" />
<script ... >
</span>

and suddenly IE inserted it all like it should. If you want to know which tricks are necessary to trigger script execution have a look at the MyFaces repository:
http://svn.apache.org/repos/asf/myfaces/core/branches/2_0_0/api/src/main/javascript/META-INF/resources/myfaces/_impl/_util/_Utils.js

It's interesting code - external and embedded scripts need to be treated differently.

Friday, June 19, 2009

HowTo integrate JUnit and WebBeans

WebBeans provides an easy way to integrate it with JUnit.
I use for the examples WebBeans 1.0.0.PREVIEW1 and Junit4.

Follw these steps to integrate JUnit and WebBeans.

1. Create a base class called AbstractWebBeansContextTest
This super class contains the setup of the WebBeans Context and makes the WebBeans Manager available for its subclasses. You have to add the webbeans-se.jar to your build path. This jar provides the possibility to initialize the WebBeans context within a SE (Java StandardEdtion) environment.

import javax.inject.manager.Manager;
import org.jboss.webbeans.CurrentManager;
import org.jboss.webbeans.environment.se.StartMain;

public abstract class AbstractWebBeansContextTest {
public static final Manager manager;
static {
StartMain.main(new String[]{});
manager = CurrentManager.rootManager();
}
}

2. Put a beans.xml into the root-source directory of your testing project
In that beans.xml you could define your testing deployment types (e.g. @Mock, etc.). In our case this beans.xml left blank.

3. Create your test class
Create a new test class which is a subclass of AbstractWebBeansContextTest.
Annotate a method with @BeforeClass and initialize your WebBeans which you wan to use in your test case.
Annotate some other methods with @Test and use your initialized WebBeans.

public class MyTestCase extends AbstractWebBeansContextTest {

public static MyService service;

@BeforeClass
public static void startup() {
service = manager.getInstanceByType(MyService.class);
}

@Test
public void testServiceMethod() throws Exception {
...
service.myServiceMethod();
...
}
}

Wednesday, June 17, 2009

JSF 2.0 and dojo create NO_MODIFICATION_ALLOWED_ERR: DOM Exception 7 on Safari

When testing our dojo facelets examples in Safari I realized that they don't work with Mojarra 2.0. After some investigation it turned out that Mojarra 2.0 sends a reponse-header Content-Type: application/xhtml+xml thus triggering a bug in Safari.With JSF 1.2 (also with Facelets) it was always Content-Type: text/html. The result is that Safari throws NO_MODIFICATION_ALLOWED_ERR on some DOM operations that are needed from the dojo side.

I added a Listener to set the Content-Type to text/html and - helas! - it works just fine.

public void beforePhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
ExternalContext extContext = context.getExternalContext();
Object response = extContext.getResponse();
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE) {
String contentType = "text/html; charset=UTF-8";
if (response instanceof ServletResponse) {
((ServletResponse) response).setContentType(contentType);
} else if (response instanceof RenderResponse) {
((RenderResponse) response).setContentType(contentType);
}
}
}

Tuesday, June 16, 2009

JSF 2.0 AJAX overview

Many AJAX JSF frameworks are on the market - but the moment you start combining them you may get random results due to incompatibilities. JSF 2.0 will help with this! Specifying the AJAX API will help assemble the different approaches under one roof. The spec (JSR-314) defines an f:ajax tag as well as a javscript API together with an AJAX enhanced JSF lifecycle.

I helped implement one of the numerous AJAX JSF approaches for years (the fry:ajax tag from J4Fry) and during the last months this approach was integrated into Apache MyFaces 2.0 while adapting it's interfaces to the new spec. The spec covers a lot of the basic features in a generic and flexible way. Btw.: MyFaces 2.0 is on its way, we're currently gluing everything together and I'm hoping for an alpha by end of august.

The most basic part of an AJAX implementation is replacing parts of the document. These are the features the JSF 2.0 API provides:
  • execute - The components that will be processed on the server in a blank separated list. Only the components named within this parameter get their decode, validate and updateModel methods called during phase 2-4. There is an @all keyword you can use to process the entire component tree.
  • render - The components that will be rendered and replaced within the HTML page in a blank separated list.
  • onevent - A JS callback that is triggered with three different events:
    • begin - occurs immediately before the request is sent
    • complete - occurs after the AJAX request has completed but before DOM manipulation has taken place
    • success - occurs after DOM manipulation has taken place (only for successfull request, else see onerror)
  • onerror - A JS callback that is triggered when the server signalizes that an error has occured.
  • params - An object that may include additional parameters to include in the request.
There have been discussions on both the MyFaces and Mojarra mailing lists on the nature of the ids in the execute and render parameters. Are they HTML ids or component ids? Here's the truth: The f:ajax tag can take either component ids that resolve relative to the nearest naming container or HTML ids. There is an algorithm that tries both. The procedural interface jsf.ajax.request(source, event, {execute: ..., render: ...}) requires HTML ids. The f:ajax tag will resolve the component and generate a behaviour that is in fact a call to jsf.ajax.request.

f:ajax provides three more attributes that offer JSF specific enhancements:
  • disabled - Indicates whether the AJAX behavior script should not be rendered.
  • listener - A method binding to execute when the AJAX request is processed on the server.
  • immediate - same as the attribute you know from the standard JSF action sources.
For Tomahawk 2.0 we are preparing a t:ajax tag that will include a bunch of extra options. Implementation will happen in J4Fry JSF 2.0 with a fry:ajax tag (targeted for end of juli) which will be repackaged for Tomahawk 2.0 when it is ready. This is the list of extra options we want to support:
  • timout - How long to wait for the HTTP response before aborting the request.
  • delay - How long to wait before issuing a request (helpfull with onkeyup or mouse move events to avoid tons of requests).
  • queuesize - Number of requests to queue (discard the oldest when the queue is full and a new one arrives).
  • partial submit - The current spec requires submission of the entire form though only the elements named in the execute parameter are being processed. Setting partial submit (or pps) to true could reduce the submit volume to the actually processed values.
  • disable - HTML id's of the components to disable while the request is running (can be implemented via onevent).
  • loadingbar - HTML id of an img tag to make visible while the request is running (can also be implemented via onevent).
  • errorhandling for errors that occur within the javascript - can be done with the onerror parameter, but the spec doesn't mention this use.
Just in case you've made it up to here (which would only happen if you are really deep into JSF and AJAX technology) you will be keen to know whether JSF 2.0 AJAX will do an auto eval on incoming scripts. If you rerender a portion of your markup that contains a script then auto eval will execute the newly arrived scripts. The spec doesn't mention this issue, Mojarra 2.0 (in it's current beta state) doesn't do auto eval but MyFaces 2.0 will.

Thursday, June 4, 2009

HowTo integrate Apache Axis and WebBeans

IMO WebBeans becomes a pretty cool dependency injection framework for Java. It works in a type-safe way (greetz to Spring ;-)) by using annotations. It provides Interceptors, Decorators and Event-Processing as well.
On the other hand Axis is a powerful framework to implement WebServices.

If you want to use the WebBeans benefits in your Axis Services you have to integrate both technologies. Axis provides two simple ways to do this:
  1. with a custom MessageReceiver
  2. with a ServiceObjectSupplier
So lets integrate WebBeans into Axis.
I'm running on Tomcat 6.0.18 with Apache Axis2 1.4.1 and WebBeans 1.0.0. Preview1.

Create a WebBeans integration class

package org.j4fry.webbeans;
import javax.inject.manager.Manager;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.jboss.webbeans.CurrentManager;

public abstract class WebBeansIntegration {
public static Object createInstance(AxisService axisService) throws AxisFault {
Parameter parameterServiceClass = axisService.getParameter(Constants.SERVICE_CLASS);
Class serviceClass = null;
try {
serviceClass = Class.forName(parameterServiceClass.getValue().toString());
} catch (ClassNotFoundException e) {
throw new AxisFault("There's not valid serviceClass specified", "serviceClass");
}
Manager manager = CurrentManager.rootManager();
return manager.getInstanceByType(serviceClass);
}
}

Possibility 1: Adjust Axis to use this integration class via a custom Message Receiver

package org.j4fry.webbeans;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;

public class CustomMessageReceiver extends org.apache.axis2.rpc.receivers.RPCMessageReceiver {
@Override
protected Object makeNewServiceObject(MessageContext msgCtx) throws AxisFault {
return WebBeansIntegration.createInstance(msgCtx.getAxisService());
}
}

Possibility 2: Adjust Axis to use this integration class via ServiceObjectSupplier

package org.j4fry.webbeans;
import org.apache.axis2.AxisFault;
import org.apache.axis2.ServiceObjectSupplier;
import org.apache.axis2.description.AxisService;

public class WebBeansObjectSupplier implements ServiceObjectSupplier {
public Object getServiceObject(AxisService axisService) throws AxisFault {
return WebBeansIntegration.createInstance(axisService);
}
}

Tomcat Configuration - web.xml
Tomcat's web.xml have to reference the WebBeans Manager (of course you have to include the AxisServlet and the mapping information as well)

<resource-env-ref>
<description>WebBeans Manager</description>
<resource-env-ref-name>app/Manager</resource-env-ref-name>
<resource-env-ref-type>javax.inject.manager.Manager</resource-env-ref-type>
</resource-env-ref>

Axis Service Configuration - services.xml
The services.xml from your Axis-Service archive (.aar file)
If you choose possibility 1 you have to include your custom Message Receiver with the following tag inside the service-element:

<messageReceivers>
<messageReceiver mep="http://www.w3.org/ns/wsdl/in-out" class="org.j4fry.webbeans.CustomMessageReceiver"/>
</messageReceivers>

If you choose possiblity 2 you have to add the "ServiceObjectSupplier" parameter to your service element like this

<parameter name="ServiceObjectSupplier">org.j4fry.webbeans.WebBeansObjectSupplier</parameter>

Use WebBeans Annotation inside your Service class
If you've finished the previous steps you can use the WebBeans Annotations to inject some resources in your service class.

Resources
WebBeans RI 1.0.0 Preview1 (thanks to JBoss): http://downloads.sourceforge.net/jboss/webbeans-1.0.0.PREVIEW1.zip
Apache Axis2 1.4.1: http://ws.apache.org/axis2/