Monday, April 14, 2008

Using Metawidget with Seam, Facelets, JPA and Hibernate Validator

This is a short tutorial on using Metawidget with JBoss Seam, Facelets, JPA and Hibernate Validator. It should take about 10 minutes.

Seam - the fusion of the best

Metawidget is a great fit for Seam, because both Metawidget and Seam are all about leveraging and integrating existing technologies. For this tutorial, we will use Seam 2.0.1.GA and JBoss 4.2.2.GA, so you'll need to download those first. Next, build the Seam Booking example using:

cd \jboss-seam-2.0.1.GA\examples\booking
ant

...and then...

cd \jboss-4.2.2.GA
copy \Applications\jboss-4.2.2.GA\server\default\deploy
   server\default\deploy
bin\run

...and finally open a Web browser to http://localhost:8080/seam-booking and check it's all running okay. We'll assume you're familiar with the standard Seam Booking app (if not, it's covered in detail in the Seam documentation).

Seam, meet Metawidget

Metawidget ships with an updated Seam Booking example. To build it...

cd \metawidget-0.43\examples\faces\seam-booking
ant

...then stop JBoss if it's still running and, as before...

cd \jboss-4.2.2.GA
copy \Applications\jboss-4.2.2.GA\server\default\deploy
   server\default\deploy
bin\run

Open a Web browser to http://localhost:8080/seam-booking and check it's running okay. The app should look remarkably similar, but the Metawidget version uses less code, is less error-prone, and is more 'proper'. What do we mean by that?

Less code

The Metawidget version of the Seam Booking app replaces book.xhtml, confirm.xhtml and hotelview.xhtml. In each case, most of the code has been replaced by a single tag. So instead of...

<s:decorate id="checkinDateDecorate" template="edit.xhtml">
  <ui:define name="label">Check In Date:</ui:define>
  <rich:calendar id="checkinDate"
   value="#{booking.checkinDate}"
   required="true"
   datePattern="MM/dd/yyyy"
   event="onblur"
   reRender="checkinDateDecorate"
   style="width: auto;"/>

   ...some 60 lines of code...

</s:decorate>

...we simply have...

<m:metawidget value="#{booking}" rendererType="div">
  <f:param name="divStyleClasses"
   value="entry,label,required,input,error errors"/>
</m:metawidget>

Less error-prone

Ironically, the Seam Booking example actually contains the exact sort of bug Metawidget is designed to avoid! In the original hotelview.xhtml, we see...

<ui:define name="label">Nightly rate:</ui:define>
<h:outputText value="#{hotel.name}">

...clearly this is wrong - nightly rate should display #{hotel.price}, not #{hotel.name}. It's a simple cut-and-paste, 'my UI has gotten out of sync with my business object' sort of bug.

Metawidget gets it right, because Metawidget outputs the code for you.

More 'proper'

Often, there's a bunch of business object metadata that really should be mapped to the UI, but it's too laborious to do. For example, Booking.java uses Hibernate Validator's @Length annotation. Ideally, we would put...

<input type="text" length="16">

...on every such occurance, but who has time to do that?

Metawidget gets it right, because Metawidget inspects the back-end, discovers the annotation, and outputs the laborious code for you.

Conclusion

That concludes this short tutorial. As we have seen, combining Metawidget with Seam saves you code and bugs, whilst making your UI more 'proper'. To learn more about Metawidget, the best place to start is the Reference Documentation.

0 comments: