Monday, October 13, 2008

Anything goes alternative Olympic Games


I've been toying with the idea of an alternative Olympics where anything goes as long as it is human powered. The rules are simple, (if you're stupid enough) you can use any kind of dope but more interestingly you can use any kind of technology, just as long as it is human powered. I want to see Phelps with one of these things! Maybe he can wear a fin on his back to go with it.

Saturday, October 11, 2008

Hibernate Interceptors, Events and JPA Entity Listeners

Hibernate became is an implementation of the JPA specification. The JPA specification is part of the EJB3 specification (JSR-220). See, SUNs FAQ on that if you want to know more about that.

Hibernate Interceptors
In a recent project I wanted to intercept Create, Update and Delete events. From the Hibernate Reference Documentation it was pretty straightforward to find out how to create an Interceptor class. I extended my AuditInterceptor class from the EmptyInterceptor interface and implemented the onSave, onFlushDirty and onDelete methods but then was a bit puzzled how to activate the interceptor. Chapter 2 talks about specific hibernate configuration properties, but how to use those when you're using a JPA persistence.xml? It turns out the answer is very simple. Pretty much any vendor specific property can be set in the persistence.xml using a properties block. In this case a property with name hibernate.ejb.interceptor needs to be set to the full name of my AuditInterceptor class.

Some advantages are that
  • you don't to change any of your existing code, just add your interceptor and update the persistence.xml
  • the onFlushDirty gives you a nice detailed information on what changed
but on the flipside
  • the interceptor fires for every entity bean, and chances are you're only interested in a subset. I ended up doing the filtering in my AudutInterceptor.
  • if your primary key is set by the database, the id is still undefined when onSave fires.
Hibernate Events
The capabilities of Hibernate Events API goes beyond those of the Interceptors. It gives you very fine-grained control over where to hook into the event stream. Check out the org.hibernate.event package for all the different interfaces you can implement.

Some advantages
  • fine-grained control over where to hook into the persistence process (lots of Pre- and Post-event interfaces)
  • The event objects are contain a wealth of information, including previous and current state of the entity.
but on the flipside
  • hooking up your EventListener is either done programmatically or using the Hibernate session-factory configuration block. I guess I could use a hibernate.cfg.xml file and reference that in my persistence.xml, but it started to feel convoluted to me.
JPA EntityListeners
FInally there are non vendor specific JPA EntityListeners. To use an EntityListener you simply add a '@EntityListener (class=)' annotation. Then in your listener class you can use other annotations (like @PrePersist, @PreRemove, @PostPersist, @PostRemove, @PreUpdate, @PostUpdate and @PostLoad) to decorate your listener methods.

Some advantages are
  • fine-grained control as to which entities you want to listen to (annotation on the entity, referencing your listener class)
  • pretty good control on where you want to hook in your listener (annotation on a method on the listeners class)
but on flipside
  • the API only gives you the current state of the entity, and does not provide information as to what changed in case of an update.
Conclusion
In my case I ended up with a hybrid solution using a HibernateInterceptor for the Update and Delete, and using EntityListeners for the Create event, listening to the PostInsert events so that the id field on my entities are defined.

Saturday, September 27, 2008

Transformation using Smooks, part 1: XML2XML

Part 1 is sort of the Hello World on Smooks, and how it is better then using plain XSLT.

Smooks is fragment based data transformation framework. It can handle many different data formats and is the default transformation engine of three open source ESBs: (JBossESB, Synapse and Mule ESB). In this case I needed an XML2XML transformation. I'm used to using XSLT for that, but I had some date formatting to do, so I figured I would use Smooks. Currently the latest release is v1.0.1, so this is what I used. Note that some of the documentation on the Smooks website already referring the v1.1.x version (you can tell by the xsd reference, smooks-1.1.xsd), so watch out for that since that will not work using 1.0.x. However you can still use v1.0.x notation in v1.1. x

So how to go get started?

1. First you will need to download the Smooks Libraries, but if you're like me and use JBossESB, then you can skip this step. Note that Smooks is very modular, so if you don't need all the features you'll only need a subset of the jars provided by Smooks.

2. Create a transformation unittest, like the one below to test your transformation. I based this one on the one given in the Smook User Guide, the one at the very end of the document).

package com.sermo.services.foley.transform;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.BeforeClass;
import org.junit.Test;
import org.milyn.Smooks;
import org.milyn.container.ExecutionContext;
import org.milyn.event.report.HtmlReportGenerator;
import org.milyn.payload.JavaSource;
import org.xml.sax.SAXException;

/**
* Unit test for Smooks transformation.
*
* Smooks configuration file is located in src/main/resources/smooks-config.xml
* Input file for transformation is located in src/test/resouces/input.xml
* Expected file from trasformation is located in src/test/resouces/expected.xml
* Smooks execution report will be created in target/smooks-report.html
*/
public class SmooksTest {

public static Smooks smooks = null;

@BeforeClass
public static void setupSmooks() throws SAXException, IOException
{
smooks = new Smooks( "smooks-res.xml");
}
@Test
public void testTransformation()
throws FileNotFoundException, IOException, SAXException
{
InputStream in = this.getClass().getResourceAsStream("/input.xml");
System.out.println(new InputStreamReader(in).toString());
StreamSource source = new StreamSource(this.getClass().getResourceAsStream("/input.xml"));
ExecutionContext executionContext = smooks.createExecutionContext();
//create smooks report
Writer reportWriter = new FileWriter( "smooks-report.html" );
executionContext.setEventListener( new HtmlReportGenerator( reportWriter ) );
StreamResult result = new StreamResult( new StringWriter() );
smooks.filter( source, result, executionContext );
System.out.println("Smooks output:" + result.getWriter().toString());
InputStream is = this.getClass().getResourceAsStream("/expected.xml");
//compare the expected xml (src/test/resources/expected.xml) with the transformation result.
XMLUnit.setIgnoreWhitespace( true );
XMLAssert.assertXMLEqual(new InputStreamReader(is), new StringReader(result.getWriter().toString()));
}
}

In this case it transforms the XML in the input.xml file into a format that should correspond to the XML in the expected.xml file. The actual transformation happens at line 55 (smooks.filter), and the result can be accessed using a StreamResult called result. XMLAssert is used to check that the output corresponds to our expectation.

3. Smooks has one configuration file, the smooks-res.xml file, in which you define the smooks-resource-list, and any entry in this list is a resource-config entry. This file contains the definition of the transformation:

<?xml version='1.0' encoding='UTF-8'?>
<smooks-resource-list xmlns="http://www.milyn.org/xsd/smooks-1.0.xsd" >

<resource-config selector="global-parameters">
<param name="default.serialization.on">false</param>
<param name="stream.filter.type">SAX</param>
</resource-config>

<!-- Date Parser used by all the bean populators -->
<resource-config selector="decoder:UTCDateTime">
<resource>org.milyn.javabean.decoders.DateDecoder</resource>
<param name="format">yyyy-MM-dd HH:mm:ss</param>
</resource-config>

<resource-config selector="hibernate-event">
<resource>org.milyn.javabean.BeanPopulator</resource>
<param name="beanId">eventType</param>
<param name="beanClass">java.util.HashMap</param>
<param name="bindings">
<binding property="type" selector="hibernate-event/@eventType" />
</param>
</resource-config>

<resource-config selector="category">
<resource>org.milyn.javabean.BeanPopulator</resource>
<param name="beanId">category</param>
<param name="beanClass">java.util.HashMap</param>
<param name="bindings">
<binding property="name" selector="category/name" />
<binding property="type" selector="category/type" />
<binding property="id" selector="category/id" />
<binding property="createDate" selector="category/createDate" type="UTCDateTime" />
</param>
</resource-config>

<resource-config selector="category">
<resource type="ftl">
<![CDATA[<caffeine-event type="${eventType.type}">
<category>
<cat-name>${category.name}</cat-name>
<cat-type>${category.type}</cat-type>
<id type="integer">${category.id}</id>
<utc-date><#if category.createDate?exists>${category.createDate?string("yyyy-MM-dd'T'HH:mm:ss'Z'")}</#if></utc-date>
</category>
</caffeine-event>]]>
</resource>
</resource-config>

</smooks-resource-list>

Note that the first sections sets up some global parameters like which parser it should be using under the hood (SAX in this case). Next I defined a date parser called 'decoder:UTCDateTime' which can parse the date format in the input.xml, so that it can be transformed into another date format later. The next two sections set up two Java beans (using a HashMap actually), so we can add name, value pairs. The first bean selects data on the 'hibernate-event' tag, setting the type, by selecting the value of eventType attribute. The second section populates another HashMap by looking at the data in the category element. This is what Smooks means with being fragment based. You can use different types of technologies to parse your incoming message (XML in this case). Finally in the last section it builds the output message. Here I chose to use FreeMarker (ftl), which is very nice templating language.

4. input.xml

<hibernate-event eventType="create">
<category>
<name>Sumatra</name>
<type>Coffee Bean</type>
<id type="integer">5000</id>
<createDate>2009-02-09 21:00:01</createDate>
</category>
</hibernate-event>

This is the incoming XML message.

5. expected.xml

<caffeine-event type="create">
<category>
<cat-name>Sumatra</cat-name>
<cat-type>Coffee Bean</cat-type>
<id type="integer">5000</id>
<utc-date>2009-02-09T21:00:01Z</utc-date>
</category>
</caffeine-event>

This is the XML we want to transform the input.xml to. So this file is the expected output, so we can use XMLUnit to assert that we got what we were expecting.

6. Smooks Execution Report

When you are in the middle of building your smooks-res.xml, the Smooks Execution Report can come in very handy for debugging purposes. The lines

//create smooks report
Writer reportWriter = new FileWriter( "smooks-report.html" );
executionContext.setEventListener( new HtmlReportGenerator( reportWriter ) );

create an HTML based report called 'smooks-report.html', which you can simply open in your favorite browser.


Conclusion

Fragment based transformation rocks, have you ever tried to do any date manipulation or working on a highly normalized XML in XSLT? By the way you can still use XSLT instead of a BeanPopulator; mix and match. I also like having a real templating language to create my outgoing message. By picking the tool for the task you can expect high transformation performance. There was nice thread on theServerSide on that here.

Part 2, will be about how a Java2XML transformation and how you'd deploy the transformation as a service to JBossESB.

Friday, August 15, 2008

Javadoc

I've been writing Java for more then a decade now and the funny thing is that I never actually read how to write Javadoc. Don't get me wrong I write it alright, but when I came across this document, it was kinda fun to discover the true intentions.

Wednesday, August 6, 2008

MySQL Profiling and Performance tools

I'm working with a MySQL database that has been growing, and has reached about 2 Gb these days. So needless to say we're getting more interested in profiling the database. I started a search for some tools and this is the list thus far, in no particular order.

1. MyTop
The first tool I came across was mytop, which is a little tool inspired by 'top'. I also found this quick tutorial tutorial on how to interpret the screens. It does require depend on some Perl libraries, which you can install using MCPAN:
sudo perl -MCPAN -e shell

then at the cpan prompt:
install DBI
install DBD::mysql
install Term::ReadKey
install Term::ANSIColor
install Time::HiRes

In the directory where you extracted mytop execute:
perl Makefile.PL
make
make test
sudo make install


2. Maatkit
MySQL toolkit is now called Maatkit. Maatkit can be found on sourceforge and more recently on code.google. It looks like it can come in very handy with running replicated databases. Peter Zeitsev has nice blog entries on what it can do, or you can just read the docs.

3. MySQL Query Profiling
Recently MySQL added a profiling tool in the server itself called MySQL Query Profiler. This tool provides very detailed information on where the time is spend for a query.

4. MyProfi
MyProfi is a log analyzer and profiler. Extracts the most popular queries grouping them by their normalized form and shows the statistics for each group. Helps you recognize the most frequently run queries to be able to optimize overall db performance.

Wednesday, July 30, 2008

Where did my class get loaded from?

In Java is it not always easy to figure out from where a certain class is loaded. Particularly when the same class is packaged up in more then one archive. So if you want to figure out from which archive the class got loaded from, this little piece of code may come in handy

Monday, July 21, 2008

JBoss IDE Timeout waiting for server to come up

"Did not start in 50s". That's a pretty annoying message to receive when you're trying to fire up JBoss from within eclipse using the JBoss IDE plugin. It turns out that there is a setting called "Server timeout delay" where: Unlimited (-1), Longer (1) - Shortest (9)

Open the file

/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.wst.server.core.prefs

and add

machine-speed=1