AppFuse 3.0 Released!

The AppFuse Team is pleased to announce the release of AppFuse 3.0. This release is AppFuse's first release as a 10-year old and includes a whole slew of improvements.

  • Java 7 and Maven 3 are now minimal requirements
  • Replaced MyFaces and Tomahawk with PrimeFaces for JSF
    • Removed SiteMesh in favor of JSF's built-in layout support
  • Added Wicket support
  • Migrated from jMock to Mockito for tests
  • Integrated wro4j and WebJars
  • Migrated to Bootstrap 3 and defaulted to Bootswatch's Spacelab theme

In addition, this release includes upgrades to all dependencies to bring them up-to-date with their latest releases. Most notable are Spring 4, Spring Security 3.2 and Bootstrap 3. For more details on specific changes see the release notes.

What is AppFuse?
AppFuse is a full-stack framework for building web applications on the JVM. It was originally developed to eliminate the ramp-up time when building new web applications. Over the years, it has matured into a very testable and secure system for creating Java-based webapps.

Demos for this release can be viewed at Please see the QuickStart Guide to get started with this release.

If you have questions about AppFuse, please read the FAQ or join the user mailing list. If you find any issues, please report them on the users mailing list. You can also post them to Stack Overflow with the "appfuse" tag.

Thanks to everyone for their help contributing patches, writing documentation and participating on the mailing lists.

We greatly appreciate the help from our sponsors, particularly Atlassian, Contegix, and JetBrains. Atlassian and Contegix are especially awesome: Atlassian has donated licenses to all its products and Contegix has donated an entire server to the AppFuse project.

Posted in Java at Dec 23 2013, 02:31:15 PM MST 1 Comment

Happy 10 Year AppFuse!

10 years ago yesterday, I released the first version of AppFuse. It started with XDoclet generating ActionForms from POJOs and became very popular for Struts developers that wanted to use Hibernate. The project's popularity peaked in 2006, as you can see from the mailing list traffic below.

AppFuse Mailing List Traffic

It's possible the decrease in traffic is because we re-wrote everything to be based on Maven. It's also possible it was because of more attractive full-stack frameworks like Grails and Rails. However, the real reason is likely that I stopped working on it all the time due to getting a divorce becoming an awesome dad.

Below is a timeline of how the project evolved over its first 4 years.

AppFuse History: 2003 - 2007

AppFuse has been a great project for me to work on and it's been a large source of my knowledge about Java, Web Frameworks, Spring, Hibernate - as well as build systems like Ant and Maven. We started with CVS, moved to SVN and now we're on GitHub. We've experienced migrating from Tapestry 4 to Tapestry 5 (thanks Serge Eby!), upgrading to JSF 2 and enjoyed the backwards compatibility of Spring and Struts 2 throughout the years. We've also added REST support, a Web Services archetype and kept up with the latest Spring and Hibernate releases.

AppFuse History: 2007 - 2013

Last year, we added Bootstrap and jQuery as foundational front-end frameworks. For our next release, we're switching to PrimeFaces, adding Wicket and changing from jMock to Mockito. Most of these changes are already in source control, we just need to polish them up a bit and add AMP support. I hope to release 3.0 before the bus is done. ;)

Thanks to all the enthusiastic users of and contributors to AppFuse over the years. It's been a great ride!

Posted in Java at Apr 05 2013, 08:56:45 AM MDT 3 Comments

Integrating GWT into AppFuse

I've been interested in integrating GWT into AppFuse ever since I blogged about it 4 years ago. A few months after that post, I wrote about Enhancing with GWT and Grails. After Evite, I had a gig near Boston where I developed with GXT for the remainder of the year. When all was said and done, I ended up spending a year with GWT and really enjoyed my experience. I haven't used it much since.

GWT is scheduled to be integrated into AppFuse in version 4.0. That's quite a ways off. The good news is you might not have to wait that long, thanks to Iván García Sainz-Aja. Iván let us know about his work a couple weeks ago in an email to the appfuse-dev mailing list.

It's still work in progress but it has already most of AppFuse functionality..

If you want to give it a try

the quickest way to have a go would be

web/gwt> mvn -P gwtDebug -Dgwt.inplace=true gwt:compile jetty:run  

at the moment it still requires this fork of gwt-bootstrap to be compiled first

It needs a lot of testing yet but it's getting quite there

As you can imagine, I was very excited to hear about Iván's work. So I cloned his repo, built gwt-bootstrap locally and checked it out. Functionality wise, it was great! However, when I dug into the source code, I found a whole lotta code.

To see how the GWT flavor compared to the other implementations in AppFuse, I created a cloc report on the various web frameworks in AppFuse. I'm sure these reports could be adjusted to be more accurate, but I believe they give a good general overview. I posted some graphs that displays my findings in visual form.

Lines of Java Number of Files

When I sent this to the mailing list, Ivan responded that it was a lot of code and estimated 12 new files would be needed to CRUD an entity. This sure seems like a lot to me, but he defended this yesterday and noted that his implementation follows many of GWT's latest best practices: MVP pattern, Activities and Places, EventBus, Gin and Guice. He also shared a wiki page with explanations and diagrams of how things work.

The reason I'm writing this post is to get more feedback on this implementation. First of all, does GWT really require this much code? Secondly, are there other GWT implementations that reduce a lot of the boilerplate? SmartGWT, Vaadin* and Errai come to mind.

If you were starting a new GWT project and using AppFuse, how would you want it implemented?

* Vaadin 7 claims it can be used as a drop-in replacement for GWT. I tried replacing the gwt-servlet and gwt-user dependencies with Vaadin's, but it didn't work.

Posted in Java at Mar 07 2013, 06:49:28 PM MST 7 Comments

Switching AppFuse from MyFaces to PrimeFaces

When describing my bias against JSF back in November, I wrote:

... there's a lot of folks praising JSF 2 (and PrimeFaces moreso). That's why I'll be integrating it (or merging your pull request) into the 2.3 release of AppFuse. Since PrimeFaces contains a Bootstrap theme, I hope this is a pleasant experience and my overall opinion of JSF improves.

Shortly after the AppFuse 2.2.1 release in December, Gilberto Andrade contributed a sample project that used Mojarra (the JSF RI) and PrimeFaces instead of MyFaces and its Tomahawk components. Last week, I spent a few hours integrating Gilberto's changes into AppFuse's master branch. You can see all the changes I made (which include a Jetty plugin upgrade and some cleanup) in this Crucible review. Feel free to leave comments on ask questions in the review itself.

The first thing I noticed when integrating PrimeFaces is you have to add a custom repository in order to get its artifacts via Maven.

        <name>Prime Repo</name>

This is unfortunate since all of AppFuse's other dependencies can be found in Maven Central. It means that if you're using a JSF archetype, the PrimeFaces repo will be checked for artifacts first, causing an unnecessary slowdown in artifact resolution. I hope the PrimeFaces developers fix this soon.

While integrating these two frameworks, I ran into a number of issues.

An IllegalStateException on startup when using "mvn jetty:run"
The first issue I encountered was that I was unable to run the app in Jetty. It worked fine in Tomcat but I got the following error in Jetty:

2013-01-31 22:28:07.683:WARN:/:unavailable
java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
at javax.faces.FactoryFinder$FactoryManager.getFactory(
at javax.faces.FactoryFinder.getFactory(
at javax.faces.webapp.FacesServlet.init(
at org.eclipse.jetty.servlet.ServletHolder.initServlet(
at org.eclipse.jetty.servlet.ServletHolder.doStart(

I found the fix for this on Stack Overflow and added the following listener to my web.xml to solve it.


Conditionally rendering a button disables its click-ability
The next thing I noticed was the Delete button didn't work when editing a user. It was hidden correctly when adding a user, but clicking on it to delete a user simply refreshes the page. Below is the code I used successfully with MyFaces. For some reason, this doesn't work with PrimeFaces.

<c:if test="${not empty}">
<h:commandButton value="#{text['button.delete']}" action="#{userForm.delete}"
    styleClass="btn" onclick="return confirmMessage(msgDelConfirm)"/>

I also tried the following, but no dice. This is currently an open issue.

<h:commandButton rendered="${not empty}" value="#{text['button.delete']}" 
    action="#{userForm.delete}" styleClass="btn" onclick="return confirmMessage(msgDelConfirm)"/>

The PrimeFaces Bootstrap theme 404s on some images
After integrating PrimeFaces' Bootstrap theme, the following error shows up in server logs.

[INFO] [talledLocalContainer] Feb 02, 2013 10:40:25 PM com.sun.faces.application.resource.ResourceHandlerImpl logMissingResource
[WARNING] [talledLocalContainer] WARNING: JSF1064: Unable to find or serve resource, images/ui-bg_highlight-hard_70_000000_1x100.png, from library, primefaces-bootstrap.

This seems to have happened before in previous releases and is currently an open issue.

Canoo WebTest doesn't work with fileUpload nor to set checkbox values
We use Canoo WebTest to run integration tests on the UI in AppFuse. For some reason, performing file uploads and setting checkbox values works fine with MyFaces/Tomahawk, but not with Mojarra/PrimeFaces. I'm not sure if this is caused by the JSF core or the component library, but it remains an open issue. For now, I've just commented out the parts of tests that used to do this.

On a related note, getting the real path of a resource from the ServletContext worked fine before the switch, but results in a null value now.

String uploadDir = getServletContext().getRealPath("/resources") + "/" + request.getRemoteUser() + "/";

PrimeFaces resources served up at /javax.faces.resource/* not found
While I didn't have problems with this in AppFuse, I did encounter it in AppFuse Light. I don't know why there was a difference between the two, but it turned out to be caused by the UrlRewriteFilter and my desire for extensionless URLs. The outbound-rule to strip .xhtml from URLs was the culprit. Adding a condition to it solved the problem. Yeah, the condition seems backwards, but it works.

<outbound-rule match-type="regex">
    <condition type="query-string" operator="equal">ln=primefaces</condition>
    <to last="false">$1$2</to>

The initial switch to Mojarra/PrimeFaces was pretty easy thanks to Gilberto's sample project. However, the small issues encountered after that turned out to be quite frustrating and you can see that several are still not fixed. I guess it just goes to show that not all web frameworks are perfect. Hopefully we'll get these minor issues fixed before the next release. In the meantime, you can checkout the updated demos for AppFuse JSF and AppFuse Light JSF.

Posted in Java at Feb 06 2013, 12:19:34 PM MST Add a Comment

AppFuse Light 2.2.1 Released!

In December, the AppFuse Team released 2.2.1. Right before that release, I decided to wait on enhancing its "light" modules, a.k.a. AppFuse Light. I'm glad I did, because it took some effort to get jQuery and Bootstrap integrated, as well as to make it more secure.

The good news is AppFuse Light 2.2.1 is released and it's sitting out on the Central Repository. This release is a refactoring of all archetypes to be up-to-date with the AppFuse 2.2.1 release. This means Java 7 compatibility, Servlet 3, Bootstrap/jQuery integration, Tapestry 5.3.6 upgrade and security improvements. I integrated Bootstrap and jQuery using WebJars Servlet 3 support since it was simple and straightforward.

You can create projects using AppFuse's light archetypes using a command such as the following:

mvn archetype:generate -B -DarchetypeGroupId=org.appfuse.archetypes 
  -DarchetypeArtifactId=appfuse-light-spring-freemarker-archetype -DarchetypeVersion=2.2.1 
  -DgroupId=com.mycompany -DartifactId=myproject 

The list of archetypes is as follows:

  • appfuse-light-jsf-archetype
  • appfuse-light-spring-archetype
  • appfuse-light-spring-freemarker-archetype
  • appfuse-light-spring-security-archetype
  • appfuse-light-stripes-archetype
  • appfuse-light-struts-archetype
  • appfuse-light-tapestry-archetype
  • appfuse-light-wicket-archetype

The QuickStart Guide will help you get setup and demos are available at the following links:

If you have questions about AppFuse, we invite you to ask them on the users mailing list or tweet using #appfuse.

For those enjoying Bootstrap in your apps, I encourage you to check out {wrap}bootstrap and Bootswatch.

Posted in Java at Jan 24 2013, 07:43:20 PM MST Add a Comment

AppFuse 2.2.1 Released!

The AppFuse Team is pleased to announce the release of AppFuse 2.2.1. This release includes upgrades to all dependencies to bring them up-to-date with their latest releases. Most notable are Hibernate 4, Struts 2.3.7, Apache CXF 2.7.0 and Spring Security 3.1.3. In addition, we've integrated HTML5, Twitter Bootstrap, jQuery and replaced Compass with Hibernate Search. Last but not least, we've added full support for Java 7 and integrated many security improvements. For more details on specific changes see the release notes.

What is AppFuse?
AppFuse is a full-stack framework for building web applications on the JVM. It was originally developed to eliminate the ramp-up time when building new web applications. Over the years, it has matured into a very testable and secure system for creating Java-based webapps.

Demos for this release can be viewed at Please see the QuickStart Guide to get started with this release.

A number of blog posts were written about features that went into this release while it was being developed:

If you have questions about AppFuse, please read the FAQ or join the mailing list. If you find any issues, please report them on the users mailing list.

Thanks to everyone for their help contributing patches, writing documentation and participating on the mailing lists.

We greatly appreciate the help from our sponsors, particularly Atlassian, Contegix and JetBrains. We highly recommend using the new IntelliJ IDEA 12 for developing web applications.

Posted in Java at Dec 11 2012, 03:21:44 PM MST 5 Comments

Improving AppFuse's PageSpeed with Apache

One of the most important things when developing webapps is to make them fast. With AppFuse, we've tried to incorporate many of the 14 rules for faster-loading websites. We had a gzip filter before it was cool (2003) and replaced it with the one from EhCache. However, users experienced issues with both of these, both with XFire/CXF and WebWork/Struts 2 and JSPs. Because of these issues, we disabled gzipping a few releases ago.

This article is designed to show you how you can make your AppFuse webapp faster, without modifying any code. The good news is this applies to any webapp that you can deploy behind Apache.

Last Friday, I sent an email to the good folks at Contegix to see if they could install mod_pagespeed on the Apache server that sits in front of * My goal was to improve the YSlow and PageSpeed scores of the apps hosted on I discovered they were getting a dismal score of 24 and figured we could do a lot better. mod_pagespeed speeds up your site and reduces page load time by automatically applying web performance best practices. It seemed like an easy solution.

Unfortunately, we were unable to use mod_pagespeed. From the guys at Contegix:

Attempting to install mod_pagespeed as you requested, we find that it requires Apache httpd 2.2 and libstdc++ 4.1.2, both of which are unsupported in RHEL4. To get mod_pagespeed to work on your present operating system basically means re-rolling the core components, which would make them unsupported. I'm afraid mod_pagespeed is simply not an option on your present configuration.

Since I still wanted to improve performance, I opted for another route instead: using mod_deflate (for gzipping) and mod_expires (for expires headers). I also turned on KeepAlive as recommended by PageSpeed Insights.

mod_deflate was already installed in Apache (version 2.0.52), so all I had to do was configure it. On RHEL4, Apache is installed at /etc/httpd and there's a conf.d directory that contains all the configuration files. I created a file at /etc/httpd/conf.d/deflate.conf and populated it with the following:

# mod_deflate configuration
<IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    AddOutputFilterByType DEFLATE text/plain text/html text/xml text/css application/xml application/xhtml+xml application/rss+xml application/javascript application/x-javascript
    DeflateCompressionLevel 9
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
    DeflateFilterNote Input instream
    DeflateFilterNote Output outstream
    DeflateFilterNote Ratio ratio
    LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate

At first, I had separate lines for all the different content types (as recommended by this article). The Contegix support crew figured out the solution (everything needed to be on one line) in 14 minutes, updated the config and verified it worked using an http compression testing page.

mod_expires was already installed, so I added a config file at /etc/httpd/conf.d/expires.conf. I used this howto and asked Contegix for help when it didn't work. Their response took quite a bit longer this time (49 minutes), but they once again figured it out:

It appears that FilesMatch does not like to play will JkMount. It does work using content type.

My final config for expires.conf:

<IfModule mod_expires.c>
    ExpiresActive On
    <FilesMatch "\.(jpe?g|png|gif|js|css)$">
        ExpiresDefault "access plus 1 week"
    ExpiresByType image/jpeg "access plus 1 week"
    ExpiresByType image/png "access plus 1 week"
    ExpiresByType image/gif "access plus 1 week"
    ExpiresByType text/css "access plus 1 week"
    ExpiresByType application/javascript "access plus 1 week"
    ExpiresByType application/x-javascript "access plus 1 week"

I used "1 week" because we're changing things quite a bit right now and we haven't integrated resource fingerprinting yet.

The last thing I did to improve performance was to turn on KeepAlive by editing /etc/httpd/conf/httpd.conf and changing Off to On.

# KeepAlive: Whether or not to allow persistent connections (more than
# one request per connection). Set to "Off" to deactivate.
KeepAlive On

As a result of these changes, our PageSpeed score went from 24 to 96 and YSlow went from a 90 to a 98. When I started this experiment, I was only trying to fix However, it also improved the speed of all the other * sites, including Confluence, Bamboo, JIRA and FishEye. Thanks for all the help Contegix! There's a good chance you've given me back a few minutes in each day.

Originally posted on the AppFuse Blog.

Posted in Java at Dec 04 2012, 09:25:05 AM MST 7 Comments

AppFuse News: Liquibase and wro4j Tutorials from J. García

New committer J. García has been doing a lot of work to improve i18n in AppFuse 2.2, as well as our Struts 2 support. In addition, he's written a couple articles that show you how to integrate Liquibase and wro4j in your AppFuse applications. Thanks for the great documentation J!

The 2.2 release is coming along, and we're down to 16 open issues. I've updated the Hibernate, JPA, Services and Web Services tutorials and hope to finish the web tutorials in the next week. You can try the latest code using the QuickStart Guide or check it out on the demo site:

Please see this thread on the mailing list if you have any questions or suggestions.

In related news, Roger Hughes has a good article titled Ten Things You Can Do With Spring Security. Since AppFuse uses Spring Security extensively, hopefully you can use some of Roger's tips to improve the security of your app.

Posted in Java at Nov 30 2012, 02:32:47 PM MST Add a Comment

AppFuse News: GitHub, Hibernate Search and The Future

It's been a while since I've written anything about AppFuse, but since the project has had quite a bit of activity lately, now seems like a good time.

First of all, we moved the source code from to GitHub way back in June. Thanks to Serge for helping with this process and making it quick and painless. For some reason, shortly after moving, we started having quite a few build issues with Bamboo. I was able to diagnose the problem as not enough memory on our server. Thankfully, Contegix was able to add another 2GB of RAM to our box and get everything back up-to-snuff.

New Committer: J. Garcia
J. Garcia has been a regular voice on the users and developers mailing list for several months. He's recently started contributing a lot of patches in JIRA and seems genuinely interested in the success of AppFuse. That's why we voted and added him as a committer. To prove this was a smart move, he recently replaced Compass with Hibernate Search and upgraded to Hibernate 4. As part of this work, he removed iBATIS support, which brings me to my next point.

The Future
In mid-August, I sent an email to the community, asking them "Anyone using iBATIS?"

I'm thinking of replacing AppFuse's Data Tier with Spring Data, especially because it has NoSQL and REST support. There's a good intro on InfoQ today:

Does anyone see an issue with this? The lack of iBATIS support could be an issue, but I doubt it since if we wanted to continue supporting it, we should move to MyBATIS.

Everyone agreed this was a good idea and it seemed like a logical time to remove iBATIS support. In addition, I posted a roadmap I jotted down in early May. Since we've missed all the dates so far, I've removed them from the listing below. We hope to get 1-2 releases done by the end of this year, with 2.2 in the next 2-3 weeks.

Hibernate 4
Hibernate Search

AMP for all light modules

JSR 303 (might require removing or developing client-side support)
Mockito instead of jMock/EasyMock

AMP one-to-many
Spring Data
MyBatis (if there's interest in adding it back in)

wro4j for concatenation and minimizing JS and CSS
pjax -

Scala example
Gradle example
Article about examples


Maven Central Statistics
To prove there's still a fair amount of folks using AppFuse, here's some statistic from Sonatype's OSS Repository Hosting Service.

AppFuse Downloads

From this screenshot, you can see that AppFuse artifacts are downloaded around 7,000 times per month. The following graph is even more interesting. Apparently, around 3,000 new projects are created with AppFuse archetypes each month.

AppFuse Archetype Downloads

The AppFuse Name
Finally, I recently discovered that ShoreTel decided to name a new product AppFuse. I guess this signifies two things: 1) it's a good name for a product and 2) someone didn't do their research before naming it. At this point, I'm not too concerned, but it is an interesting development.

Posted in Java at Sep 25 2012, 10:42:14 AM MDT 5 Comments

Refreshing AppFuse's UI with Twitter Bootstrap

The last time AppFuse had an update done to its look and feel was in way back in 2006. I've done a lot of consulting since then, which has included a fair bit of page speed optimization, HTML5 development and integrating smarter CSS. It was way back in '05 when we first started looking at adding a CSS Framework to AppFuse. It was Mike Stenhouse's CSS Framework that provided the inspiration and my CSS Framework Design Contest that provided its current themes (puzzlewithstyle, andreas01 and simplicity).

Since then, a lot of CSS Frameworks have been invented, including Blueprint in 2007 and Compass in 2008. However, neither has taken the world by storm like Twitter Bootstrap. From Building Twitter Bootstrap:

A year-and-a-half ago, a small group of Twitter employees set out to improve our team’s internal analytical and administrative tools. After some early meetings around this one product, we set out with a higher ambition to create a toolkit for anyone to use within Twitter, and beyond. Thus, we set out to build a system that would help folks like us build new projects on top of it, and Bootstrap was conceived.
Today, it has grown to include dozens of components and has become the most popular project on GitHub with more than 13,000 watchers and 2,000 forks.

The fact that Bootstrap has become the most popular project on GitHub says a lot. For, I'd like to integrate a lot of my learnings over the past few years, as well as support HTML5 and modern browsers as best we can. This means page speed optimizations, getting rid of Prototype and Scriptaculous in favor of jQuery, adding wro4j for resource optimization and integrating HTML5 Boilerplate. I've used Twitter Bootstrap for my Play More! app, as well as some recent client projects. Its excellent documentation has made it easy to use and I love the way you can simply add classes to elements to make them transform into something beautiful.

Last week, I spent a couple late nights integrating Twitter Bootstrap 2.0 into the Struts 2 and Spring MVC versions of AppFuse. The layout was pretty straightforward thanks to Scaffolding. Creating the Struts Menu Velocity template to produce dropdowns wasn't too difficult. I added class="table table-condensed" to the list screen tables, class="well form-horizontal" to forms and class="btn primary" to buttons.

I also added validation errors with the "help-inline" class. This is also where things got tricky with Struts and Spring MVC. For the form elements in Bootstrap, they recommend you use a "control-group" element that contains your label and a "controls" element. The control contains the input/select/textarea and also the error message if there is one. Here's a sample element waiting for data:

<div class="control-group">
    <label for="name" class="control-label">Name</label>
    <div class="controls">
        <input type="text" id="name" name="name">

Below is what that element should look like to display a validation error:

<div class="control-group error">
    <label for="name" class="control-label">Name</label>
    <div class="controls">
        <input type="text" id="name" name="name" value="">
        <span class="help-inline">Please enter your name.</span>

You can see this markup is pretty easy, you just need to add an "error" class to control-group and span to show the error message. With Struts 2, this was pretty easy thanks to its customizable templates for its tags. All I had to do was create a "template/css_xhtml" directory in src/main/webapp and modify checkbox.ftl, controlfooter.ftl, controlheader-core.ftl and controlheader.ftl to match Bootstrap's conventions.

Spring MVC was a bit trickier. Since its tags don't have the concept of writing an entire control (label and field), I had to do a bit of finagling to get things to work. In the current implementation, Struts 2 forms have a single line for a control-group and its control-label and controls.

<s:textfield key="user.firstName" required="true"/>

With Spring MVC, it's a bit more complex:

<spring:bind path="user.firstName">
<fieldset class="control-group${(not empty status.errorMessage) ? ' error' : ''}">
    <appfuse:label styleClass="control-label" key="user.firstName"/>
    <div class="controls">
        <form:input path="firstName" id="firstName" maxlength="50"/>
        <form:errors path="firstName" cssClass="help-inline"/>

You could probably overcome this verbosity with Tag Files.

Figuring out if a control-group needed an error class before the input tag was rendered was probably the hardest part of this exercise. This was mostly due to Bootstrap's great documentation and useful examples (viewed by inspecting the markup). Below are some screenshots of the old screens and new ones.

Old UI - Login Old UI - Users Old UI - Edit Profile

New UI - Login New UI - Users New UI - Edit Profile

Check out the full set on Flickr if you'd like a closer look.

Even though I like the look of the old UI, I can't help but think a lot of the themes are designed for blogs and content sites, not webapps. The old Wufoo forms were a lot better looking though. And if you're going to develop kick-ass webapps, you need to make them look good. Bootstrap goes a long way in doing this, but it certainly doesn't replace a good UX Designer. Bootstap simply helps you get into HTML5-land, start using CSS3 and it takes the pain out of making things work cross-browser. Its fluid layouts and responsive web design seems to work great for business applications, which I'm guessing AppFuse is used for the most.

I can't thank the Bootstrap developers enough for helping me make this all look good. With Bootstrap 2 dropping this week, I can see myself using this more and more on projects. In the near future, I'll be helping integrate Bootstrap into AppFuse's Tapestry 5 and JSF versions.

What do you think of this CSS change? Do you change your CSS and layout a fair bit when starting with AppFuse archetypes? What can we do to make AppFuse apps look better out-of-the-box?

Update: I updated AppFuse to the final Bootstrap 2.0 release. Also, Johannes Geppert wrote a Struts 2 Bootstrap Plugin. I hope to integrate this into AppFuse in the near future.

Posted in Java at Jan 31 2012, 05:12:17 PM MST 10 Comments