SpringOne 2008 Day 2

The highlight of the day must surely have been Graeme “Grails” Rocher building a basic Twitter app onstage in 40 min. I missed the fun, chose to go to the “What’s new in Spring 3.0″ session by Juergen Hoeller instead.

I won’t repeat stuff verbatim as the slides would be released sometime, but will just jot down my personal impressions from Juergen’s session:

  • Starts with a revision of Spring 2.5 config using annotations. Pretty clear that they now recommend the annotation way (even @Autowired !) and minimize the XML
  • After yesterdays keynote preview I was wondering if EL for Spring would make sense but it does, I am convinced.
  • For example the Spring EL will simplify cases like injecting primitive values (think of a “cacheSize” to be set conditionally). I have a feeling that stuff I am currently doing using a FactoryBean can be avoided with the EL. I am yet to try JavaConfig though.
  • Spring will ship with a home grown EL processor, apparently inspired by the JSF “Unified” EL. So it uses #{} kind of syntax. But Spring EL will be more powerful, can even do method invocations. I have not been following the EL scene closely but I distinctly recall a certain other framework that has this feature implemented already. Who came up with this idea first? Hmm.
  • The EL support will be tightly integrated with Spring “scopes”. Think conversation, session, application – even exotic things like Spring Batch “step” scope. Sounds elegant.
  • Spring will move to an Ivy based custom build and release system in future. Juergen did not say this explicitly but it sounded like they are ditching Maven becuase they want better control over dependencies metadata etc. Juergen said that they would end up using stuff that was / is being tried out in the current Spring WebFlow build system. I had noticed when I tried one of the recent SWF beta-s or RC-s that the build was based on Ivy. If this is true, Maven guys won’t be pleased ;) Anyone care to comment?
  • REST support looks neat I could tell a lot of folks were impressed. @PathVariable ftw!
  • Juergen promises “conversation scope” is coming that solves the “concurrent windows in same browser” problem. Uh oh, sounds like I have heard that elsewhere as well. Do I smell another flame war on the ServerSide soon? *glee*. The slide says matter-of-factly that this feature is inspired by MyFaces “Orchestra”.
  • Next slide brings up “serializability” of session and conversation objects. Solution is proxies that reobtain references on deserialization. Now where have I seen this before? Hmm ;)
  • Spring “inheritance based” controllers will still exist but be marked as deprecated in 3.0 in favor of the annotations. I will miss you SimpleFormController and friends, you have served me well!!
  • But I won’t miss things like the wonderfully named JUnit 3.X support classes like “AbstractTransactionalDataSourceSpringContextTests”. I see myself using annotations for the Spring JUnit 4 support very soon. As someone that’s not particularly fond of annotations, now that’s saying something.
  • Juergen says that his view of Java EE 6 spec progress is that it is delayed, was supposed to be done by end 2008. Word is that they are shooting for JavaOne. Juergen feels that it likely won’t be done even then (June 2009). Hurray for standards. Yay. But some specs have come a long way e.g. JSF 2.0 and JPA 2.0, they may go into Spring 3.0, rest goes into 3.1, 3.2 etc when available.

After that I attended the LinkedIn case study. Interesting, they did a lot of work to customize finer details of how Spring does DI and life cycle stuff. I was not particularly convinced that they needed to go as far as they did – but the message was effectively conveyed that Spring is so easy to extend and bend around to do stuff that you want. For me personally, I had never ever ventured into creating custom Spring XML namespaces etc. and this session gave me some idea as to how to go about it.

After lunch came Jeremy Grelle’s Spring MVC and Spring JavaScript presentation. I had seen most of the slides already, downloaded from one of his talks elsewhere earlier but I did find the demos interesting. Personally I hate mixing JavaScript in your JSP but have to admit that Spring makes things easier than it would be otherwise, typical Spring. This stuff is for you if you are using JSP especially with Tiles – you can do partial refresh of fragments. But the Tiles config looks a little too complex for my liking. I guess I should blame Tiles, not Spring, heh. Jeremy appears to be great fan of Dojo, plugs the session by Dojo member(s) tomorrow. Spring Javascript is currently a wrapper over Dojo, they plan to add other implementations in the future like jQuery, YUI. Sounds a liitle ambitious to me. Spring JS 3.0 will have JSON support and “deep integration with dojo.data”, not sure what that means.

I attended the Morgan Stanley case study at the end which I felt was a “fair and balanced” look at real-life Spring adoption, even having a few slides on what the dev team perceived as Spring limitations – although most points seemed somewhat contrived. Having attended the LinkedIn session earlier it was good to see MS take a somewhat different approach to some of the stuff LI did. Very interesting to see that their architecture was all about message processing (CXF), no app servers, no Tomcat. Instead they bolt a custom TCP channel onto a Spring context. They invested in a Spring subscription and had very positive things to say about it, training, accessibility of SpringSource team etc. Overall I got some nice insights on how to pitch Spring to prospective clients especially those having a lot of legacy code. Very, very nice to see Morgan Stanley talk about killing their in-house frameworks and consolidate on stuff like Spring JDBC. They damn well got it right. Some of the clients (and pointy haired bosses) I have dealt with in the past (and wanted to knock some sense into) come to mind. Yeah if you are reading this blog, you know who you are!!

Here is my twitter feed if you are interested.

SpringOne 2008 Day 1

Now off to bed after the SpringOne kick-off and keynote. My, the venue is grand. Bag and goodies are nice but apparently no Rod Johnson bobblehead this time ;)

Quote as I remember it from Rod Johnson’s keynote: “No one uses Tomcat because they played golf with someone”. Hah! Take that all ye bloated app server vendors ;)

My personal (irreverent) thoughts from the keynote, just a few things I remember:

  • Theme this year: “Weapons for the War on Java Complexity”. On the swag T-shirt as well.
  • Yep, more stats and proof that Tomcat is the dominant app-server and even the other app-server deployments mostly run Spring apps. Spring world domination complete.
  • A lot on Spring WebFlow, looks that it plays a big role in the overall roadmap. Now did he actually say that he was not completely convinced that Spring WebFlow was simple enough and made complete sense until recently? Hmm. Yes, SWF syntax much simpler in 2.0 compared to 1.0. Rod Johnson stresses that SWF makes sense for guided page navigation, back button problem, opening multiple browser windows at the same time etc. Spring JavaScript
  • Talks about the Big Choice JSF vs non-JSF, compares this to Republicans vs Democrats, jokes about how ServerSide threads on JSF get hijacked by people who assert that JSF sucks. Rod does not say what he *really* feels about JSF. I will buy a beer for anyone who can tell ;)
  • Hardly any XML shown in the slides, mostly annotations. Guess I can’t avoid this stuff any more
  • In fact “admits” that the old Spring MVC was not really the “right way”. The inheritance based controllers will be deprecated in Spring 3.0. What the! Breaking news: Rod Johnson says that concrete inheritance “sucks”.
  • DM server, AMS, Oracle extensions. Lot’s of “SpringSource” stuff.
  • Aha, something new unveiled, SpringSource “tc” – Tomcat with management and enterprise features added
  • I can buy into this more than the OSGi stuff. Rod says that barrier to Tomcat usage in production is the management and enterprise / deployment features. Hmmm, probably. So you take your existing WAR and it should run on this. Not yet clear if this uses the DM server under the hood, think so.
  • Spring 3.0 will introduce REST support and some kind of an Expression Language. EL that you can embed in annotations and stuff huh!? Now that is interesting, reminds me of something I’ve seen elsewhere. Need to catch the first session tomorrow on Spring 3.0 by Juergen.

Wicket and GWT compared with code

I have been using Wicket for a while now and I’ve occasionally wondered if GWT provides any kind of advantage over Wicket. Recently I got a chance to do a comparison and instead of coding a simple “Hello World” kind of example, I decided to try something a little more complex. Hopefully this brings out the differences between Wicket and GWT more clearly.

Functionality

The target functionality is a one-page application that shows data in a single table. Item counts are displayed categorized under multiple “spaces” (workspaces). There is a summary row. The user can click on a space to expand the count of items grouped by status. The screenshots below show how the table looks when fully collapsed and then when one or more spaces are expanded.

It may look simple, but some of the tricky parts are:

  • The number and names of the possible status types can be different for different spaces. For example, the first space above has 3 status types and the second 2. This means that we can’t use different columns to group this data. Multiple rows are used instead to display the break-up when expanded.
  • Some of the table cells have to be merged to represent the grouping by space and then by status. In HTML terms, this requires some careful control of TD “colspan” and “rowspan” attributes.
  • In addition to the cell merging described above, the style / color of the different cells has to be controlled to differentiate the total count from that grouped by status. For example, the grand total on the last row is in bold. In HTML terms, this requires control over the CSS “class” attribute, coordinated with a style-sheet.

First, let us look at the Java code common to the GWT and Wicket implementations.

The “Space” Domain Object

The class above represents a “space” and it internally uses a Map to hold status names and corresponding counts. There is a method that calculates the total count, a getter for the space name and list of states, and helper methods to add and get status data.

DashrService.java

As the functionality is kind of a ‘dashboard’ view – and inspired by the “Cheesr” example that the Wicket In Action book uses, I decided to call this application “Dashr”. “DashrService.java” is a singleton that returns a list of spaces with dummy data. The relevant code is shown below:

So on to the comparison then. In the side-by-side layouts below, GWT is on the left and Wicket is on the right.

Project Structure

Although it is not really a domain class, “DashrService.java” has been kept in the “domain” package along with “Space.java” to keep things simple.

On the GWT side, the recommended package structure and naming conventions (“client”, “public”, etc.) are being used. Our example is a pure client-side application and server-side communication or RPC is not being used at all. All the client-side code and behavior is in “DashrEntryPoint.java” itself. “Dashr.html” simply serves as a placeholder for the rendered application.

It may first appear that Wicket requires more files than GWT but one difference is that the GWT code is not communicating with any server-side functionality at all. Wicket would feel more natural to Java web-app developers familiar with web.xml and the like, and integrating additional server side code or frameworks such as Spring or Hibernate would be much more straightforward.

Another thing is that the Wicket application has been modularized into multiple Java components and corresponding HTML files. It was not really possible to do something similar for the GWT application which has all the UI code in a single file. The reasons for this difference will become clear when we look at the code in detail.

Framework Configuration

GWT needs to be told where to find the Java classes that have to be converted into JavaScript. If this path is not explicitly set using an XML element called “source” it defaults to “client” – which is the GWT recommended convention. Our main module config file “Dashr.gwt.xml” does not have the source path declared. So this means that all the Java code in the directory “dashr/gwt/client” (and any sub-directories) will be processed by the GWT Java to JavaScript compiler.

Since “Space.java” and “DashrService.java” are dependencies for our GWT based UI code, we need to ensure that they are included in the Java to JavaScript conversion as well. So in addition to the “User” core framework module that all GWT apps must inherit, we have a reference to a custom module – “dashr.domain.DashrDomain”. “DashrDomain.gwt.xml” declares the source path to be an empty string which in relative-path terms works out to be the same folder the XML file is in – and this is how the “dashr/domain” directory is included for our example. Those who intend to use GWT to connect to server-side Java code would need to do something like this – i.e. include all dependencies needed by UI code, typically domain objects that happen to already exist – like in our example.

The UI class that acts as the “entry point” has to be configured for a GWT application. In our example we have only one UI class and this itself will be the entry point.

One more thing the main GWT config does is declare “Dashr.css” as the CSS file for our application. A GWT convention-over-configuration rule applies here as well which is that resources like CSS files and images are looked for in the “public” folder relative to the XML file by default.

For Wicket, there is no XML configuration but an “application” class that can hold configuration in Java code. The web.xml file is not really Wicket configuration but it is shown above for completeness and it names the Wicket “application” class used by the framework servlet / filter. In our example, “DashrApplication.java” is just pointing to the designated “home page”. Our home page is “DashrPage.java” for which the HTML markup is in “DashrPage.html”. The Wicket “home page” can be considered equivalent to the GWT “entry point”.

UI Implementation

Because of the differences between GWT and Wicket – the code below does not really line up side by side. To make it easier to see how the code compares – some key sections from the GWT side have been mapped to the Wicket side using blue arrows. I have not mapped every possible thing because then the picture would be out of control! You can click on the picture to view a bigger version

Observations:

  1. Wicket gives you complete control over the HTML. To render a table we use a “ListView” repeater control [DashrPage.java:18] which manipulates a <TR> section. In the case of GWT however, we have to use an abstraction over an HTML table either HTMLTable or FlexTable. Since we require control over the table “colspan” and “rowspan” attributes, we have to use the GWT “FlexTable” as the basic “HTMLTable” does not support this. What I experienced is that having to use the GWT API to output HTML limits you in certain ways, for example on the Wicket side I was able to freely include <TH> cells with <TD> cells but within the GWT table I could not mix <TH> cells. This may explain why the GWT “Dashr.css” file has an extra CSS class called “header” defined to compensate.
  2. Using Wicket’s built-in Ajax support, getting the expand / collapse functionality to work was very easy. It was a simple matter of replacing one (or more) rows of the HTML table over Ajax [RowCollapsedPanel.java:19, RowExpandedPanel:29]. Trying to do the same thing using GWT turned out to be quite a puzzle-solving exercise. To dynamically add or remove rows on a GWT table you have to know the row index and in our case the number of rows in the table changes dynamically. I ended up using a HashMap [DashrEntryPoint.java:21] to track the table row for each Space. This explains the mysterious code you see at lines 98 and 124 in DashrEntryPoint.java to update the Map when the table is changed.
  3. To dynamically set the contents of a table cell in GWT, you have to explicitly get a reference to the cell using the row-index and column-index. But in Wicket it is very easy to add or replace text as long as you know the wicket:id of the HTML element and it works fine for <TD> as well.
  4. One of the biggest problems I found with GWT is the poor separation of concerns. You can see a lot of code in DashrEntryPoint.java doing CSS styling on the HTML table and cells, for e.g. the calls to getRowFormatter() and getCellFormatter(). GWT does allow you to use a standard CSS file but you have to programmatically set the styles on your widgets in Java code. You can see for example how lines 42-43 in DashrEntryPoint.java map cleanly to markup and code on the Wicket side. The Wicket implementation does not have any CSS mixed in the Java code at all – it is all in the HTML where it belongs, and where web-designers can work freely. Most GWT widgets make use of pre-defined CSS names so this may not be a big problem for simple applications, but the web-designer would still need to know which CSS class names to use.
  5. This example only has a single widget on one page, but when you place multiple widgets on a screen, you have to think in terms of layout managers just like Swing. I have not gone into what GWT provides in detail but it looks suspiciously like the days of struggling with GridBagLayout :) I prefer the much simpler and effective Wicket approach of managing layout using standard HTML and I personally feel that web-designers need to be able to work directly with the HTML (and CSS) and have better control over things like cross-browser rendering quirks.
  6. On the GWT side Dashr.html is just a placeholder for all the JavaScript stuff that will happen at run-time. So when testing or debugging, if you do “view source” you see nothing, just the skeletal Dashr.html! This was a real pain when I was trying to tweak things like the CSS styling by trial and error. Especially when you are using hosted mode you can say goodbye to things like the web developer FireFox extension. When it comes to Wicket, you are dealing with a “normal” web-app and being able to look at the rendered HTML or DOM at any time is something you take for granted.
  7. One of Wicket’s strong points is that you can take chunks of HTML and model them as reusable panels. This makes the code modular and easier to read and it is obvious what the intent of “RowCollapsedPanel” and “RowExpandedPanel” is. Maybe with some more thinking and effort on the GWT side I could have had the inner classes ExpandClickListener and CollapseClickListener in separate files. But the code in the “onClick” event handlers is tightly coupled to the “table” and “spaceRowMap” properties of the enclosing class. I considered passing these as parameters in the constructor but decided it wasn’t worth the extra complexity and that the readability of the GWT code would reduce even more.
  8. The big difference between GWT and Wicket is of course that at run-time, all the GWT code becomes JavaScript and executes on the client browser. This may require the developer to think a little more about the implications of certain design choices. For example on lines 51 and 83 of DashrEntryPoint.java, a new instance of a ClickListener is being instantiated for each Space. On the server side, I wouldn’t think twice about dynamically instantiating many objects to render a page but in GWT I would have to start thinking about the impact this would have especially when everything ultimately becomes client-side JavaScript. The GWT tutorial also has some recommendations regarding this.
  9. The GWT host HTML page Dashr.html contains a hidden IFRAME to support use of the browser back-button. To be able to use this feature properly requires some extra effort as detailed in this page of the GWT documentation. I did not spend time trying to understand this and I simply used null for the “state token” on lines 50 and 82 of DashrEntryPoint.java. The Wicket application transparently supports the browser back-button. If you really need bookmarkable URLs, you then need to do some extra work in Wicket just like you have to do in GWT.
  10. The conversion to JavaScript takes more time than normal Java compilation. I found a mention of a real-life project experiencing GWT compile times of up to 18 minutes.
  11. On a more positive note, I used the latest GWT 1.5 and whatever little Java 5 features I used (generics, enhanced for loop) worked fine. You still need to be aware of some gotchas though.
  12. The GWT code does not communicate with the server at all which can indeed be considered one of the advantages of GWT because of performance. But it depends. What if I really wanted the data to come from the server? Then I would need to understand how to make server calls and perhaps even GWT serialization. The “Dashr” requirement is not something I cooked up and I am using something similar in an actual project. In the real-life requirement when a Space is expanded, the data has to come from the server (over Ajax) because it is an expensive “count (*)” kind of query in the database. In other words, the expanded data for all spaces cannot be loaded upfront in one go. Handling this kind of stuff in Wicket comes naturally, you *are* on the server all the time. And if you use Hibernate you have to be aware of certain issues with GWT. I hope to expand this example with RPC into another blog post soon and also explain why I think concepts like SOFEA have drawbacks that need to be taken into consideration.
  13. A few other points worth noting that are not addressed in the example, I personally find GWT’s approach to JavaScript integration, unit testing and especially internationalization more complicated than Wicket.

Overall, a perception of GWT I couldn’t get rid of while working with it is that it feels like a hack – but of course, a very well engineered hack. Maybe if you really have a lot of stuff you want to do on only the client side, it is fine. From the perspective of someone used to Java server-side programming, there are too many things about the unique approach that leak through – not being able to do “view-source” and the added complexity of RPC being some of them. And for example here below is a screen-shot of what I get when I “compile” the GWT application into JavaScript:

It is quite weird to see a one-page application result in a bunch of files like this. There is one JavaScript file but even the HTML files contain almost nothing but JavaScript. All the JavaScript is mini-fied and heavily obfuscated. I guess one can get used to it :P

You can’t do this using Adobe Flex!

I initially had an ambitious plan to include Adobe Flex and make this a three-way comparison. But as far as I can tell, there is simply no way to get the exact table grid behavior we require using Flex! Simple things like “rowspan” are simply out of the question. Some more recent Flex widgets like the Advanced Data Grid support grouping of data and expanding grouped items etc. – but come nowhere close to the requirement outlined at the beginning of this post.

I may have missed something, so do let me know in the comments.

Related previous blog post: A Wicket User Tries JSF – comparison of Wicket and JSF using a simpler example.

An alternative Maven plugin for Ant and NetBeans

A while back I wrote a custom Maven plugin to “escape” from Maven because I personally prefer Ant for build scripting. I now generally use Maven only for JAR file dependency management and my plugin acts as a bridge between the Maven and Ant worlds. The plugin can automatically generate an Ant build.xml file from the Maven pom.xml file and it supports web-application (WAR) projects. A few people aware of the existence of this ‘underground’ plugin have been asking me for more details, and since I got a chance to tweak things recently, I’m putting down some information in this blog post on how to get the plugin and try it out. Maybe you will find it useful.

Some of the features the plugin provides are:

  • Generated build file takes care of WAR packaging and deploying to Tomcat
  • Once generated, Ant build is independent of Maven and offline
  • Build file is IDE-independent, portable and includes targets for running JUnit tests as well

NetBeans users may find some of the advanced features interesting:

  • Generation of the following different types of NetBeans projects:
    • Java Free Form Project
    • NetBeans ‘native’ Java SE Project
    • NetBeans ‘native’ Java EE (web) project
  • The Ant build (for Free Form project mode) is simple, human-readable and easily customizable instead of the horribly complex “build-impl.xml” that NetBeans users are familiar with
  • In addition to the standard clean, compile, run actions etc., the generated Free Form project supports the following NetBeans-specific IDE-integration when a file is selected in the project explorer window:
    • run single file
    • debug single file
    • run JUnit test for single file
    • run JUnit test in debug mode for single file
    • debug web application
    • Hot Deploy single file into debug session

You just need the light-weight Java SE version of NetBeans in order to start and stop Tomcat, debug and even hot-deploy classes for your web-app. No extra plugins are required for e.g. Maven or Tomcat support. You can try this out for yourself by following the instructions below.

I’ll use the Wicket “quickstart” Maven Archetype as an example of how you can quickly get up and running using Ant on a Maven web-project. You need Maven 2 installed as a pre-requisite. The Wicket “quickstart” can be found here:

http://wicket.apache.org/quickstart.html

Open a command prompt, cut and paste the magic command and you get a simple web-application project along with a Maven POM definition, ideal for testing out the plugin features. This is the command I used for this example:

mvn archetype:create -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.3.4 -DgroupId=com.mycompany -DartifactId=myproject

This will create a directory called “myproject” which contains a “pom.xml” file as well as some source code. We need to add a few lines to the pom.xml in order to use the custom plugin. First declare the repository for the plugin as follows by adding this snippet just above the <dependencies> section:

<pluginRepositories>
    <pluginRepository>
        <id>jtrac.info</id>
        <url>http://j-trac.sourceforge.net/repository</url>
    </pluginRepository>
</pluginRepositories>

And within the <plugins> section, just add these four lines:

<plugin>
    <groupId>info.jtrac</groupId>
    <artifactId>maven-antprops-plugin</artifactId>
</plugin>

That’s all that needs to be added to the POM, just 10 lines that don’t get in the way of any other Maven stuff you may want to do. To generate the Ant script, change to the newly created project folder and run the following command:

mvn antprops:generate

This will create a build.xml file and a “build-deps.properties” file. The properties file is a Plain Old Java Properties file that contains classpath information extracted from Maven as well as a list of dependencies with “runtime” scope which is used to create the “WEB-INF/lib” part of your WAR.

If you have Tomcat and Ant available on your system you can start Tomcat and deploy the WAR right away from the command line. But first you will need to point the build-file to where Tomcat is installed and this is a simple one-time matter of creating a “build.properties” file with a single line on it. Something like this:

tomcat.home=C:/peter/opt/apache-tomcat-6.0.14

From the command prompt, change to the “myproject” root directory (which should contain build.xml and build.properties by now) and type the following command:

ant tomcat-start-debug

Once Tomcat starts you should be able to verify that the app was successfully deployed by pointing your browser to: http://localhost:8080/myproject/

Eclipse users can use the “mvn eclipse:eclipse” command to open the project in Eclipse and start working with the Ant targets.

The command to create a NetBeans free-form project from the Maven POM is as follows:

mvn antprops:nbfreeform

This will create the “nbproject” folder and the NetBeans project file as well as an extra Ant script for NetBeans integration targets. Now you can open “myproject” as a NetBeans free-form project.

The “tomcat-start-debug” target is conveniently mapped to the NetBeans “run” IDE action, so just clicking on the big green “play” button should deploy the web-app running on Tomcat. If you right click on the project root “myproject” node, a “Stop Tomcat” context menu item should helpfully appear as well.

You can try the clean, compile, and war Ant targets etc. – which should work. The Wicket archetype includes a sample JUnit test also in “TestHomePage.java”. After clicking on this file to select it within the NetBeans project explorer window – go to the Run –> Run File –> Test “TestHomePage.java” toolbar menu (or hit CTRL + F6) and you should be able to run only the selected test. But it will fail now with a “java.lang.NoClassDefFoundError: javax/servlet/ServletException”.

This problem actually gives us a good example for demonstrating how the “build-deps.properties” file can be updated when dependencies change or are added to the POM. Now add the missing Servlet API dependency to the “pom.xml” file by adding this snippet within the <dependencies> section:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.4</version>
    <scope>provided</scope>
</dependency>

Then re-run the command to generate build-deps.properties. Note that this command is designed so that if a “build.xml” file already exists, it will not be over-written.

mvn antprops:generate

Now run the test case again from NetBeans and it should pass. Unit testing a UI component is easy with Wicket!

One of the neat things about the Wicket archetype is that it embeds a Jetty web-app server using a small Java class called “Start.java” lying in the “test” source structure. The POM is already set with the right dependencies for Jetty and so you can simply right-click on this Java file within the NetBeans project explorer and choose “Run”. This will start a Jetty instance and deploy the WAR as well. You will be able to see the app running at http://localhost:8080/. Look ma, no Tomcat!

One more thing you can try is right-click on “Start.java” and do “Debug” instead of run. This will kick off a proper NetBeans debug session bringing up some sub-windows for viewing breakpoints, call stack etc. You can now try hot-deploying a single class without re-starting the app-server (Jetty). Try changing the text of the Label in HomePage.java to something else and saving the file. With the file selected in the NetBeans project window, look for the “Apply Code Changes” menu option – one place to find it is within the “Run” toolbar menu. A message should appear in the log saying that a class was reloaded. Refresh the browser and you should see the change in the text displayed.

Hot deploy should also work with Tomcat after initiating a debug-session (Attach Debugger) and then using the “Apply Code Changes” menu option.

The plugin is still experimental so if you find problems, do let me know in the comments. The commands for creating “native” NetBeans projects are “mvn antprops:nbjavase” and “mvn antprops:nbjavaee”. You need NetBeans with Java EE support to try the second option.

The plugin also should make it possible to package a project along with dependencies and hand-off to someone without Maven or internet access – but I haven’t completed this part yet.

Migrating to Apache Wicket – GIDS presentation slides

The ‘Migrating to Apache Wicket’ presentation I made at the Great Indian Developer Summit last week went off well. It was great to see the interest in Wicket, the room was full and there were quite a few questions even during the course of the session before I got to the end.

Here are the slides for your viewing pleasure. Apologies if some of the slides look cluttered because the animations I used to talk through some of the slides have been lost after converting to PDF.

Here below is one of the images I used to illustrate how a project that starts out using an action-oriented MVC framework with JSP can end up with a ‘Franken-stack’ over time. It starts innocently enough, you decide to use something extra say to enforce a common layout, then you realize you need some third party tag-libs, then security, and of course Ajax and before you know it…

What if a framework exists that can do all of this in Just Java and Just HTML? Find out more.

Hope you find the slides useful. I look forward to your feedback and suggestions on how the content can be improved. Please do comment!

How to record RTMP flash video streams using Red5

Update 2009-04-04: I’ve released an open source project that you can use to download RTMP video streams in a much simpler way. You can find it here: http://flazr.com

Red5 is an open source Flash server written in Java. It does not include a standalone client yet but I was able to write a Java program that uses Red5 to connect to an RTMP video stream and record / save it to a file. Code is provided below and also some tips on how to get the details required to download flash videos that you come across on the internet.

Here’s the code of “MyRtmpClient.java”, you are free to use and modify this in any way you want.

import java.io.File;

import org.apache.mina.common.ByteBuffer;
import org.red5.io.IStreamableFile;
import org.red5.io.ITag;
import org.red5.io.ITagWriter;
import org.red5.io.flv.impl.FLVService;
import org.red5.io.flv.impl.Tag;
import org.red5.io.utils.ObjectMap;
import org.red5.server.api.event.IEvent;
import org.red5.server.api.event.IEventDispatcher;
import org.red5.server.api.service.IPendingServiceCall;
import org.red5.server.api.service.IPendingServiceCallback;
import org.red5.server.net.rtmp.Channel;
import org.red5.server.net.rtmp.RTMPClient;
import org.red5.server.net.rtmp.RTMPConnection;
import org.red5.server.net.rtmp.codec.RTMP;
import org.red5.server.net.rtmp.event.AudioData;
import org.red5.server.net.rtmp.event.IRTMPEvent;
import org.red5.server.net.rtmp.event.Notify;
import org.red5.server.net.rtmp.event.VideoData;
import org.red5.server.net.rtmp.message.Header;
import org.red5.server.net.rtmp.status.StatusCodes;
import org.red5.server.stream.AbstractClientStream;
import org.red5.server.stream.IStreamData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyRtmpClient extends RTMPClient {

	private static final Logger logger = LoggerFactory.getLogger(MyRtmpClient.class);

	private String saveAsFileName = "test.flv";

	public static void main(String[] args) {

		String host = "localhost";
		String app = "oflaDemo";
		final String name = "IronMan.flv";
		int port = 1935;
		final int duration = 10000; // milliseconds, -2 means until end of stream

		final MyRtmpClient client = new MyRtmpClient();
		logger.debug("connecting, host: " + host + ", app: " + app + ", port: " + port);
		
		IPendingServiceCallback callback = new IPendingServiceCallback() {							
			public void resultReceived(IPendingServiceCall call) {
				logger.debug("service call result: " + call);
				if ("connect".equals(call.getServiceMethodName())) {					
					client.createStream(this);
				} else if ("createStream".equals(call.getServiceMethodName())) {													
					Integer streamId = (Integer) call.getResult();
					logger.debug("createStream result stream id: " + streamId);
					logger.debug("playing video by name: " + name);						
					client.play(streamId, name, 0, duration);
				}								
			}						
		};
		
		client.connect(host, port, app, callback);

	}

	private RTMPConnection conn;	
	private ITagWriter writer;

	private int videoTs;
	private int audioTs;

	@Override
	public void connectionOpened(RTMPConnection conn, RTMP state) {
		logger.debug("connection opened");
		super.connectionOpened(conn, state);
		this.conn = conn;
		init();
	}

	@Override
	public void connectionClosed(RTMPConnection conn, RTMP state) {
		logger.debug("connection closed");
		super.connectionClosed(conn, state);
		if (writer != null) {
			writer.close();
			writer = null;
		}
		System.exit(0);
	}

	@Override
	public void createStream(IPendingServiceCallback callback) {
		logger.debug("create stream");
		IPendingServiceCallback wrapper = new CreateStreamCallBack(callback);
		invoke("createStream", null, wrapper);
	}

	@Override
	protected void onInvoke(RTMPConnection conn, Channel channel, Header header, Notify notify, RTMP rtmp) {
		super.onInvoke(conn, channel, header, notify, rtmp);		
		ObjectMap<String, String> map = (ObjectMap) notify.getCall().getArguments()[0];
		String code = map.get("code");
		if (StatusCodes.NS_PLAY_STOP.equals(code)) {
			logger.debug("onInvoke, code == NetStream.Play.Stop, disconnecting");
			disconnect();
		}
	}	

	private void init() {
		File file = new File(saveAsFileName);
		FLVService flvService = new FLVService();
		flvService.setGenerateMetadata(true);
		try {
			IStreamableFile flv = flvService.getStreamableFile(file);
			writer = flv.getWriter();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private class CreateStreamCallBack implements IPendingServiceCallback {

		private IPendingServiceCallback wrapped;

		public CreateStreamCallBack(IPendingServiceCallback wrapped) {
			this.wrapped = wrapped;
		}

		public void resultReceived(IPendingServiceCall call) {
			Integer streamIdInt = (Integer) call.getResult();
			if (conn != null && streamIdInt != null) {
				MyNetStream stream = new MyNetStream();
				stream.setConnection(conn);
				stream.setStreamId(streamIdInt.intValue());
				conn.addClientStream(stream);
			}
			wrapped.resultReceived(call);
		}

	}

	private class MyNetStream extends AbstractClientStream implements IEventDispatcher {

		public void close() { }

		public void start() { }

		public void stop() { }

		public void dispatchEvent(IEvent event) {
			if (!(event instanceof IRTMPEvent)) {
				logger.debug("skipping non rtmp event: " + event);
				return;
			}
			IRTMPEvent rtmpEvent = (IRTMPEvent) event;
			if (logger.isDebugEnabled()) {
				logger.debug("rtmp event: " + rtmpEvent.getHeader() + ", "
						+ rtmpEvent.getClass().getSimpleName());
			}
			if (!(rtmpEvent instanceof IStreamData)) {
				logger.debug("skipping non stream data");
				return;
			}
			if (rtmpEvent.getHeader().getSize() == 0) {
				logger.debug("skipping event where size == 0");
				return;
			}
			ITag tag = new Tag();
			tag.setDataType(rtmpEvent.getDataType());
			if (rtmpEvent instanceof VideoData) {				
				videoTs += rtmpEvent.getTimestamp();
				tag.setTimestamp(videoTs);
			} else if (rtmpEvent instanceof AudioData) {
				audioTs += rtmpEvent.getTimestamp();
				tag.setTimestamp(audioTs);
			}
			ByteBuffer data = ((IStreamData) rtmpEvent).getData().asReadOnlyBuffer();
			tag.setBodySize(data.limit());
			tag.setBody(data);
			try {
				writer.writeTag(tag);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

}

To compile and run the code you need the following libraries:

commons-collections-3.2.jar
jcl104-over-slf4j-1.4.3.jar
logback-classic-0.9.8.jar
logback-core-0.9.8.jar
mina-core-1.1.6.jar
red5.jar
slf4j-api-1.4.3.jar
spring-beans-2.0.8.jar
spring-context-2.0.8.jar
spring-core-2.0.8.jar

We need the latest Red5 JAR built from version control (not the latest official release) and I have uploaded these files here: red5-rtmp-client-libszip.pdf – just rename the file to end with “.zip” after downloading.

The code shown is hard-coded to connect to “localhost”, app name “oflaDemo” and stream name “IronMan.flv” which can be tested on the official Red5 server distribution which you can download and run. When it comes to downloading flash streams from the internet, WireShark can be used to sniff out the values you need.

Let’s take this site for example: http://videolectures.net/ Start a WireShark capture session before clicking on a video on the site to play it. Let WireShark grab all the information exchanged between your PC and the remote flash server and you can stop the capture once the video begins to play, we are only interested in what goes on during the connection handshake. I will use this video as an example: http://videolectures.net/ff06_chomsky_szmp/ [update Jun-2008: looks like they changed this particular video to Windows media instead of Flash, so try other videos or other sites]

In WireShark you can filter for protocol “rtmpt” and the first few entries would be handshake or “invoke” operations. Examining the “Handshake part 3″ we can easily get the value of the required “app” property. Below we can see it is “video/2006/other/ff06/chomsky_noam”:

For the host name, the IP address should do fine for most sites, but we can easily figure out the host name of the stream server from what appears after “rtmp://”. Note that WireShark allows you to search the text contents of captured packets. Here below we can see that the host name is “velblod.videolectures.net”:

And finally when the “play” command is issued – we need the value of the stream name. Below we see it is “chomsky_noam_01″:

So with the right values of hostname, app and stream name set – you can run the program and download the stream to your local drive for offline viewing. To download the whole stream – just change the duration to ‘-2′ as hinted in the source code comment. There are many free Flash players available you can use to play downloaded content such as FLV Player.

Do let me know if this works for you and if you find any additional parameters that need to be passed for other sites.

Never install NetBeans again! (just use the ZIP)

Okay that title was just to grab your attention :) What I mean is that I’m going to show you how to use the NetBeans ZIP distribution on Windows so that you never need to use the installer executable again. If you are like me and would like total control over the folders that NetBeans uses, or if you hate installing things onto Windows because of all that stuff that gets added to the programs menu and your user profile folders and maybe your registry – you will probably like this approach. Now that NetBeans 6.1 release candidate
is out, this is a good way for you to try it out in an un-intrusive manner especially if you have an older version of NetBeans already installed.

Although most people use the platform specific installers, NetBeans can also be downloaded as a platform-independent ZIP file. You can get the various flavors here for 6.1 RC: http://dlc.sun.com.edgesuite.net/netbeans/6.1/rc/zip/

I am going to use the “javase” version which is just 50MB. I can’t help mentioning that two years back, one of the main reasons I switched to NetBeans was because I felt that Eclipse was getting too bloated for comfort. Never regretted it, and especially now that Apache Wicket is my web-framework of choice – the NetBeans “javase” version is just perfect because Wicket only needs HTML and Java editing support.

After downloading the file, in this case called “netbeans-6.1rc1-200804100130-javase.zip” extract it to any folder of your choice. Create a batch file (you can call it “netbeans.bat”) and place it in the top level “netbeans” folder itself with the following contents:

set NETBEANS_HOME=%~dp0
set NETBEANS_HOME=%NETBEANS_HOME:~0,-1%

set JAVA_HOME=C:\peter\app\jdk1.6.0_02
set NETBEANS_USER_DIR=C:\peter\workspaces\netbeans

start /b %NETBEANS_HOME%\bin\netbeans.exe --jdkhome %JAVA_HOME% --userdir %NETBEANS_USER_DIR%

The first two lines are DOS hacks to obtain the path of the current directory (without a trailing slash) where you un-zipped NetBeans. You should point the JAVA_HOME to the JDK you wish to use. And finally, you can customize the folder where NetBeans saves your settings (which by default goes somewhere into your “Documents and Settings” folder). The “start /b” part is a way to make the console window “disappear” after NetBeans launches otherwise you may terminate it later and kill NetBeans by mistake.

That’s it! Now just double-click on the batch file and NetBeans will start and even create the “userdir” if it does not exist. I actually use NetBeans like this on a daily basis. It should be easy to evaluate NetBeans this way – you don’t have to go through any un-install step (in the unlikely event that you don’t like NetBeans :)

This is a nice way to control which JDK NetBeans uses, which is useful in case you have multiple JDKs installed. I use this approach for conducting training workshops where I provide a ZIP that includes NetBeans, a custom bundled JDK and a sample project – the batch file uses relative paths, just unzip and you are good to go.

If you have a NetBeans tip to share – enter the NetBeans blogging contest here: http://www.netbeans.org/competition/blog-contest.html?cid=923686

Fibonacci spiral fun with Java3D

Recently I became fascinated with the Fibonacci series and the Golden Ratio, especially with how they turn up in nature. I had been meaning to explore the Java3D API for a while, so I thought it would be a good idea to try and generate some Fibonacci spirals and get to know Java3D that way. Here is one example of what I could come up with.

fibo_java3d_1

I was able to tweak the code to highlight interesting patterns. I actually thought for a moment that I had “discovered” a few things like for instance how if you number the “dots” by the order in which they are introduced into the simulation, the spirals that visually strike you are formed by joining the dots where the number difference is a fibonacci number.

Of course all this is common knowledge in the mathematics community. But I think I was able to create much prettier visualizations :) Here is a snapshot showing how the two most obvious spirals are where the dot-number difference is equal to 13 and 21 (successive Fibonacci numbers). Dot number 1 is on the far right.

fibo_java3d_2

And here is this interesting effect when the dots are numbered in reverse order, the dots corresponding to the Fibonacci sequence (1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144) line up along the x-axis.

fibo_java3d_3

Well, this is animation after all – so here is my first ever YouTube video :) If you are interested, here is the source code (not much documentation I’m afraid).

I found the fantastic sunflower photo on Flickr. The photo description has a good explanation of why the fibonacci spirals happen and the maths behind it. If you want to explore more, have a look at this Science News Online article.

Update 2008-12-13: Found this link to some nice mathematical analysis of number spirals (not Fibonacci): http://www.numberspiral.com/

Wicket Impressions, moving from Spring MVC / WebFlow

[update 2008-05-27: A detailed presentation that summarizes this blog post along with visuals and code snippets is now available]

For quite a while, I was trying to ignore the increasing buzz about Wicket, convincing myself that I don’t need yet another MVC framework (there are too many of them anyway), but somewhere between the Javalobby articles, the InfoQ article and the O’ReillyNet article – my resolve cracked and I took a closer look.

It looked interesting and so I decided to try and migrate a selected few JSP screens of an existing Spring MVC + Spring WebFlow application to Wicket. This went much better than I expected and two months later (not full time) – I completed migrating the entire app to Wicket and it is now ready for a new release as a 100% JSP free application. I’m now trying to convince my colleagues to try Wicket and they give me strange looks because I was an outspoken Spring MVC / WebFlow fan not so long ago : )

So is Wicket the one true MVC framework that a lot of us have been hunting for? At the moment, I tend to think so. Of course I have not tried GWT, Tapestry, RIFE, Stripes, JSF, Seam, Echo2 and the other usual suspects. And how is Wicket better than Spring MVC and Spring WebFlow? Having used both, I will attempt to elaborate below.

[update1: I tried JSF, and you can read my comparison of Wicket with JSF]

[update2: I also tried GWT and here is my comparison of Wicket vs GWT]

[update3: Detailed performance & memory usage comparison of Wicket with Seam / JSF]

Lots of information is already available on Wicket and how it compares with other frameworks in general, so here I will try to focus on what I experienced when I moved from JSP + SMVC + SWF to Wicket. The way I had to throw some of my pre-conceived notions about Java web-app development out of the window may be of interest to you. This is not a very structured list, but I’ve been meaning to put down these first-hand Wicket impressions for a while, so here goes:

Pure Java
If you like Java you will really like Wicket. Over the last two months, I was surprised to learn a few Java-isms that I was not aware of – such as some subtleties when using anonymous inner classes etc. To be really productive with Wicket I think that your Java fundamentals do need to be sound. But that is a good thing.

Great component model
The application that I migrated is a reasonably complex one, with a few CRUD screens, forms, search results etc – and Wicket offered almost everything I needed – and more. I was able to easily create a couple of custom components like:

  • a date picker (Wicket has one but I really wanted to write my own)
  • a variant of a multi-select check box where if there are pre-selected values, they “float” to the top of the list. It was very easy to create this by extending the Wicket multi-select checkbox.

Once you get used to components (even a web page is a component) as opposed to URL mappings and MVC actions, you can develop at a very fast clip. After experiencing the elegance of this kind programming model where you can show or hide components and control all this in pure Java code as opposed to hacking in JSP or JSTL, you really won’t feel like going back.

I used to hold the opinion that people new to Java who need to learn how to create web-applications could probably skip most of the Swing sections in the typical introductory course material and get straight on to Servlets and JSPs. Now I have completely reversed this thinking. Swing-style coding is the future for web-applications, I can feel it :)

In the old app I had written a custom JSP tag for the special multi-select checkbox list and was quite pleased with the result. I used to think that JSP tags were more than sufficient to create re-usable components and using Prototype directly was enough do fancy Ajax things etc. Now I have revised that opinion as well.

*Real* separation of concerns
Because the application I was developing had zero JSP scriptlets and strictly used JSTL, I was under the impression that I had reached nirvana in terms of separation-of-concerns.

Of course I was wrong again. In Wicket, all layout is controlled in good old HTML files. And Wicket has some neat-o ways to do markup-y things in the Java code itself – like for instance how you can color alternate rows when rendering an HTML table.

If you have a separate team doing the presentation look and feel work, they can truly work in isolation and their output can be used as-is. Although I don’t care about this at the moment (in my case, the UI designer and Java developer is the same guy), I’m sure that this is a big deal for most development shops. I am aware that Tapestry promises the same thing.

So this is a key difference from Swing where you have the concept of layout managers. As far as I know this is where frameworks like GWT and Echo2 are different from Wicket because they also have layout controlled in Java code. IMHO the Wicket approach is the right one because you get the separation of concerns advantage. And I personally like complete control of the markup. I mean, with all those silly cross-browser incompatibilities and the need to finely adjust spacing, padding, coloring and the like, this seems to be a good thing.

No JSPs
This is very nice because:

  • You can do things much more easily and efficiently in pure Java than in JSP and the limited syntax of JSTL. Ever had that nagging feeling that your JSPs were getting un-maintainable? Try Wicket!
  • You can refactor confidently and catch problems at compile time which are not possible with JSP. For example if in JSTL you were referring to a non-existent Javabean property, you may not know until the page renders.
  • Pages are no longer slow the first time you access them because there is no more JSP compilation step
  • in my case, the app embeds Jetty and now I don’t need the JSP jar dependencies any more. This cuts the Jetty footprint from about 7 MB (including Ant and the Eclipse Java compiler) to about 1.3 MB. I had tried JSP pre-compilation earlier but gave up because of differences in how Tomcat / Jasper does things vs the Glassfish JSP engine. Jetty + the web-app requires only a JRE to run if there are no JSPs.
  • A nice side-effect of using wicket is that your pages are guaranteed to be XHTML compliant

The downside is of course that you have to recompile a little more often than if you were using JSPs. Wicket does allow you to change the markup on the fly and refresh in debug mode. Also, Wicket provides out of the box, a very detailed error page with some nice syntax coloring telling you exactly where the problem lies in your markup or otherwise – which is very, very cool.

Re-usability
Ah, again, *really*. Re-usability in the JSP world is a custom tag or a hack-y include file.

I already mentioned how easy it is to extend (yes, extend as in the Java keyword) a Wicket component to customize how it behaves. And once you get the hang of the Wicket way of doing things and how to use anonymous inner classes to your advantage, life is good :)

So compared to doing things in JSP, it is far less work in Wicket to create a component that is truly re-usable, say across all the pages of your application. And unlike JSP tags, you get the full benefit of the Java OO features. Did I mention that the design of the whole Component class hierarchy in Wicket feels very nicely done?

Wicket also has a Panel concept where you can group custom markup + components and re-use the group as a single unit to your hearts content. IMHO you really don’t need any “tiles” kind of framework anymore, just create panels and instantiate them at will.

Templates for web pages
Something I really missed in the JSP world was the ability to have all pages have a consistent header and footer and I really hated having to add includes to all JSPs to achieve this. Not any more. Wicket has a brilliant markup inheritance concept that simply works.

Ajax
I’m guessing that this is the killer feature of Wicket. Control freak that I am, I was at first concerned that Wicket comes along with its own basic Ajax implementation, or in other words it provides a replacement for say Prototype or Dojo out of the box. I initially tried to use Prototype from Wicket and was pleasantly surprised when that proved really easy. Adding on Scriptaculous effects was no problem either.

But after trying the Ajax support in Wicket I was really impressed and soon decided to do away with all those *.js files lying around in my web-app. The very useful Ajax debug popup that automagically appears on your web pages in debug mode is one good reason to rely upon Wicket’s built in Ajax. Now I feel confident that I can implement any kind of fancy Ajax on my screens, so bring it on! One example that I tried and can mention here: it was very, very easy to create a page that runs a long running process in a separate thread and updates a progress indicator through Ajax every few seconds or so.

So using Ajax is as simple as telling Wicket that instead of showing or hiding a component using a full-page refresh, do that using Ajax partial-updates to a page. And it just works on any kind of component. And when you use Wicket’s Ajax features you typically never need to write a single line of Javascript.

I came across this quote that Ajax in Wicket is possibly better and much easier when compared to how you do it in Ruby on Rails, and I wouldn’t be surprised if this is true.

Form Binding and Validation
Spring MVC is extremely good at binding HTML forms to POJOs, (a far cry from Struts 1.X) -so can Wicket be any better? I really think so. Just like Spring MVC, as long as you have POJOs and you bind in terms of OGNL, you are fine. I was able to bind almost all of the POJOs that I was using in the earlier Spring MVC app to Wicket forms without any problem. Some things felt really cleaner – like how to have multiple submit buttons on a form.

When it comes to Form validation and displaying validation errors, there are so many options and great possibilities. By default, you can display errors in a section (feedback panel) at the top of the form. I was also able to create a Wicket “behavior” that would highlight the offending widget on the screen by applying a red CSS border around it. Lurking on the Wicket mailing list, I can see folks trying all kinds of cool things such as Ajax-ified feedback messages etc. The Wicket mailing list is a friendly source of help btw, and I got quick responses to all my newbie questions.

Other Neat Stuff
Wicket has some goodies and some of the ones that I ran into (there must be many more) were these:

  • File upload: After using Spring MVC where you have to choose say commons-fileupload and manually include the JAR, I was pleasantly surprised to see that Wicket supports multipart forms / file uploading out of the box.
  • File download: Wicket has a special “Link” class specifically for the purpose of downloading files. Wicket takes care of all the low-level details such as setting the right content-type for the browser – so you end up doing the Right Thing. You don’t need to deal directly with the HttpServletRequest or Response objects at all.
  • Buffered Image: I use JFreeChart and in the old app I had to hack around a bit to get a server-side created chart streamed into an IMG tag. Wicket has an Image component that works with a buffered image. Perfect!
  • URL Mounting: You can get those bookmarkable “friendly URLs” you want with this feature. I liked the support for “REST-ful” URLs out of the box: e.g: /foo/bar/param1/param2 – and how easy it was to use.

Security (Acegi) and Wicket
The old application was using the Acegi security framework. I started out retaining Acegi for authentication and co-existing with Wicket, which was easy. I soon realized that Wicket has a very simple authorization strategy and I was able to plug in custom code to check if a user is not logged in, redirect to a login a page etc. I was also able to easily handle an auto-login using a “remember-me” cookie.

An interesting thing from the security point of view is that the URLs that Wicket generates are inherently secure. In other words it is near-impossible to predict them as they are tightly tied to a user’s session. I came to the conclusion that simply programmatically hiding / unhiding links to secure pages based on the currently logged in user’s role would be sufficient for role-based access-control kind of security.

Acegi is very useful in a URL to MVC-action mapping situation because you can restrict URL patterns to roles – e.g. you can enforce URL wildcard rules like “/admin/**” can be viewed only by ROLE_ADMIN. I will probably continue to use Acegi for a planned remote REST/POX API to the app and for the LDAP and CAS support that it comes with etc. But I’m almost convinced that Acegi is overkill for a basic Wicket app. I am still going back and forth on this – so do let me know what you think.

Integration with Spring
This was easy. I was able to manage without the recommended wicket-spring integration JARs and went with a relatively simpler (and arguably less-elegant) approach – plucking the Spring context out of the ServletContext. In case you were wondering – I have so far used only the core wicket JAR and have not even used wicket-extensions. But I’m sure I’ll start using wicket-extensions soon, I can’t wait to try modal popup windows, the file-upload progress-indicator and the other cool stuff :)

Another example of how well thought out Wicket’s design comes across is that it took only a few lines of code to delegate to the Spring MessageSource instead of using Wicket’s default i18n. So I was able to use my existing resource bundles unchanged.

Integration with Hibernate
I use Spring on top of Hibernate and staying clear of the dreaded LazyInitializationException was as simple as adding the excellent Spring OpenSessionInViewFilter. Regarding GWT, from what I can make out, getting it to work with Hibernate may not be as easy because of the way it works. I would appreciate some comments confirming this, because this could be another key point to consider when you choose an MVC framework.

No Annotations Required
Yep, I’m one of those stubborn types who firmly believes that the only annotation that you should use is @Override. And as mentioned above I did not use the annotations based Spring integration. I bring this point up because from what I have heard – some of the other competing MVC frameworks rely a lot on annotations such as Tapestry, Stripes, RIFE, Seam etc. So if this really matters to you or if your environment is pre-JDK5.0, it could be another differentiating factor. Wicket already is famous for not needing any XML configuration at all. If the Wicket guys are reading this – I really appreciate that you have not forced users to use annotations and I sure hope Wicket stays that way!

WebFlow or Wicket
In the old app, I was using Spring WebFlow and was quite happy with it. So when I started out with Wicket, I was trying to figure out how I could integrate it with WebFlow. But as I understood Wicket more and more and things started to click in my mind, I realized that there is no way you can have them both – you have to choose one or the other.

I found WebFlow great because it allowed me to re-use subflows. So as an example if I had a use-case like “assign task to user” and the user did not exist, I could easily call the “create user” flow and then resume the original calling flow at the point where I branched out, you know – all that continuations stuff. But now my conclusion is that you can easily do all that – and more – with Wicket.

In Spring WebFlow, each view state in a flow is typically a JSP page. Which brings me to now think that it was not really designed to reuse anything more fine-grained than a JSP view – when interacting with a user. I already mentioned that Wicket allows you to reuse sections of HTML and group bunches of components into panels. So when you start trying to build more dynamic pages – I think Wicket wins. Navigating back and forth in Wicket really is child’s play, you just call or instantiate another page at will. You can even do tricks like holding a reference to a previous page, (a page is nothing but a good old Java component) so you can build any kind of complex kind of back-and-forth or wizard kind of navigation easily. I am aware that Wicket has a breadcrumb component and a wizard component but I have not tried them yet.

When it comes to Ajax, I really think Wicket is better than Spring WebFlow. Spring WebFlow is unquestionably a well designed framework, continuations and all, but sometimes I felt that certain things were constraining – for example you have to jump through a few hoops to access flow-scoped variables from outside a web-flow. When you use Ajax, you do need to do that kind of stuff a lot. In addition, in the Ajax world – you are invariably dealing with a section of a page – rather than the page in its entirety – and that is where IMHO the “page centric” nature of Spring WebFlow is a limitation.

A couple of other points, I did not use browser back-button support at all yet, but just from looking at the documentation, Wicket’s back-button support appears to be just as good, if not better. And nit-picking here – I don’t particularly like the huge UUID kind of URLs that SWF generates by default eg: /like?_flowExecutionKey=_c815540C2-03F1-39F8-19E9-D56FC0E377B7_k14D5E331-7B59-EA45-CF06-672C33FA2097
But Wicket is quite the opposite, with a “URL compressor” turned on by default.

End Note
Are there any points I have missed? Please feel free to comment and help me straighten out my thoughts on comparing some of these MVC frameworks. The migration was done on an open source app, so if you want me to pull out some “before and after” code samples, do let me know!

Afterthoughts [update 2007-03-03]
Triggered by the comments and also a few additional things that popped into my mind:

  • Unit Testability: I have not used this yet, but if this means a lot to you – Wicket has that covered. And before you look down on my lack of best practice :p let me hastily add that I use Watij, but not as much as I should have.
  • Custom Session: You can create a typesafe custom Session class and you never need to deal with the HttpSession at all.
  • Refactoring: It is worth repeating that because of no JSPs, no templating (like for e.g. Velocity) and no XML – refactoring of the Java code is simple within your plain old IDE and no special tooling is required. I can vouch for that, I am using NetBeans and have no extra modules (plugins) installed. Debugging, setting break-points and stepping-through plain old Java code is far more easier than trying to do the same thing with e.g. JSPs.
  • Simplified Stack: In my case I replaced [HTML + JS + Prototype + JSP/EL + JSTL + Spring MVC + Spring WebFlow] with [HTML + Wicket]. Also note that whether Acegi needs to be there or not is debatable.
  • Clean separation from Service Layer: This is somewhat specific to Seam and let me elaborate a little. I attended one of Gavin King’s Seam sessions recently and was a little taken aback (so were quite a few others) by the suggestion that the notion of a re-usable middle tier (service layer) is grossly over-rated, i.e. a) you normally never find yourself swapping out a layer, and b) a change in one layer always impacts the other, no matter how loosely coupled they are. Conclusion: so why bother, and you are better off merging all the layers into one. You know the feeling – like wtf, is this back to the monolithic JSP-directly-accessing-DB days!? Anyway – now I can stand up and testify that I was able to cleanly take out Spring MVC and replace with Wicket with only minimal changes to the service interface (mostly feature adds and minor refactoring). This is worth thinking over, and I also feel that a well defined Service Layer is easier to expose as an XML remote API, which I plan to do soon. Just my 2c, do comment!
Follow

Get every new post delivered to your Inbox.

Join 29 other followers