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.
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 divorcebecoming an awesome dad.
Below is a timeline of how the project evolved over its first 4 years.
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.
This week, my lovely fiancé and I traveled to the City of Light. Our journey was designed around some speaking engagements at Devoxx France. Devoxx is one of my favorite conference franchises and Devoxx France has been special to me ever since the Devoxx (Belgium) I spoke at in 2011.
2011 was the year I spoke about my experience with Play, Scala, CoffeeScript and Jade. I wrote the presentation on my flight over, composed the demo video the night before and made it all happen in the nick of time. Of course, this was after 120 hours of research and preparation, so the presentation composition process had all the data I needed. You can imagine my sense of relief after pulling off that talk and getting an enthusiastic applause from the audience for my efforts.
One of the first audience questions I received was from Nicolas Martignole, asking if I'd speak at Devoxx France the following year. I whole-heartedly agreed to do it and was excited for the opportunity. It was with great disappointment that I later found out I couldn't attend Devoxx France in 2012. My client didn't like me taking so much time off and I agreed to scale my two week vacation back to 1 week. This year, I was determined to go, so I submitted some of my favorite talks: Comparing JVM Web Frameworks and The Play vs. Grails Smackdown with James Ward. I was extremely pleased when they both got accepted.
Side Story: I met Martin Odersky shortly when he sat down next to me for the Java Posse presentation in Belgium in 2011. After shaking his hand and introducing myself, I had to politely ask him to leave because it was Trish's seat. Talk about awkward; but Martin was very gracious and promptly found a new seat close by.
Comparing JVM Web Frameworks
I took out the parts of the presentation that've pissed people off in the past - particular the JSF bashing by James Gosling, the Rails gushing from Craig McClanahan and the Pros and Cons sections of each framework. I added the history of web frameworks and research from InfoQ and devrates.com.
The best part of the JVM Web Frameworks talk was the audience's reaction and enthusiasm. Devoxx always seems to attract passionate developers and Devoxx France was no different. Developers packing the room, clapping after your intro, laughing at your jokes, signifying that they agree with you about JSF. As a speaker, it's an unbelievable experience.
You can view my Comparing JVM Web Frameworks presentation below or on Slideshare.net.
Play Frameworks vs. Grails Smackdown
To prepare for James Ward and my Play vs. Grails Smackdown, we had a number of goals. First of all, we wanted to update our apps to use the latest versions of each framework. I documented what it took for Grails, James just checked in his code to GitHub. It was interesting to see that Grails 2.0.3 -> 2.2.1 caused a number of issues with testing, while Play 2.0.3 -> Play 2.1.0 required API changes, but nothing for tests. Secondly, we updated all the stats for our pretty graphs and ran load tests again.
This is where the fun started. On Tuesday evening, I decided to challenge the notion that Play was twice as fast as Grails. James had proven this with Apache Bench tests. With Play 2.0 and Grails 2.0 (last summer), we clocked Play at 251/requests per second and 198 for Grails. After upgrading each app to the latest releases, we found the numbers to be 233/second for Play and 118 for Grails.
Now he was smoking Grails, so I added a CDN and caching as well. However, the best I could do was just over 1000/requests per second, while he was around 2200/second. When he ran live tests during our talk, Play was around 2800/sec and Grails was around 900.
It was great to see how much better performance we could get with caching and a CDN. The best part is this should be available to most applications, not just these frameworks. By adding a CDN (we used Amazon CloudFront) and caching, we were both able to 10x the performance of our apps. You can find out presentation online at http://ubertracks.com/preso or view it below.
This was a very enjoyable conference to attend as a speaker. First of all, it was in one of the most beautiful cities in the world, but it's also a very special place for Trish and I. We got engaged just outside of Paris in Versailles after the last Devoxx conference I spoke at. Trish has some amazing photos from that trip. Secondly, the Devoxx conference attracts a special kind of developer - one that is passionate about and eager for knowledge. Lastly, speaking with my good friend James, in an exotic city about something we love - that was special. Asking for beers and having them brought to us at the start of our Smackdown. That was magical (thanks Nicolas!).
To all the Devoxx organizers and crew - well done on a great show!
Fixing the source The first issue I ran into was Spock and Groovy 2 incompatibilities.
| Resolving plugin JAR dependencies
| Error WARNING: Dependencies cannot be resolved for plugin [mail] due to error: startup failed:
Could not instantiate global transform class org.spockframework.compiler.SpockTransform specified at jar:file:/Users/mraible/.grails/ivy-cache/org.spockframework/spock-core/jars/spock-core-0.7-groovy-1.8.jar!/META-INF/services/org.codehaus.groovy.transform.ASTTransformation because of exception org.spockframework.util.IncompatibleGroovyVersionException: The Spock compiler plugin cannot execute because Spock 0.7.0-groovy-1.8 is not compatible with Groovy 2.0.7. For more information, see http://versioninfo.spockframework.org
At this point, I also moved all my plugin dependencies from application.properties to BuildConfig.groovy.
The next problem I ran into was a unit test and functional tests failing. The unit testing issue was caused by my Direction model not being in the tests @Mock annotation. After I added it, validation kicked and I recognized my test was invalid. I added @Ignore and continued.
The functional test seemed to be seemed to be caused by Geb and it trying to use the Chrome Driver. One of my tests didn't work with the default HtmlUnitDriver, so I used the ChromeDriver for the one test.
| Running 11 spock tests... 6 of 11
| Failure: signup as a new user(happytrails.AuthenticatedUserSpec)
| org.openqa.selenium.WebDriverException: Unable to either launch or connect to Chrome. Please check that ChromeDriver is up-to-date. Using Chrome binary at: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 45.66 seconds
Build info: version: '2.27.0', revision: '18259', time: '2012-12-05 11:30:53'
System info: os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.8.2', java.version: '1.7.0_04'
Driver info: org.openqa.selenium.chrome.ChromeDriver
at happytrails.AuthenticatedUserSpec.signup as a new user(AuthenticatedUserSpec.groovy:25)
Even when running "grails -Dgeb.env=chrome test-app", this still happened. This was caused by the fact that I had GebConfig.groovy in test/functional/happytrails. Move it to test/functional solved the problem. I also discovered that I know longer needed Chrome to get this test to pass. Apparently, the HtmlUnitDriver has issues with Grails 2.2, but it seems to work for me.
After getting the Geb configuration fixed, I ran into a functional test failure:
| Running 11 spock tests... 5 of 11
| Failure: click signup link(happytrails.AuthenticatedUserSpec)
| org.openqa.selenium.ElementNotVisibleException: Element must be displayed to click (WARNING: The server did not provide any stacktrace information)
Even though I could see the "signup" link when I ran "grails run-app", I could see that it didn't show up when running tests in Chrome. This turned out to be caused by an extraneous <div class="nav-collapse"> I had in my main.gsp. Removing it solved the problem. It's strange that this never showed up with Grails 2.0. My only guess is that Geb someone didn't look at the visibility of the element.
The last testing-related issue I ran into was a InvalidElementStateException:
| Running 11 spock tests... 7 of 11
| Failure: add new route to region(happytrails.AuthenticatedUserSpec)
| org.openqa.selenium.InvalidElementStateException: Element must be user-editable in order to clear it. (WARNING: The server did not provide any stacktrace information)
I was able to fix this by changing AddRoutePage.groovy from:
And then referencing name, distance and location accordingly (form.name, etc.) in AuthenticatedUserSpec.groovy.
After I had everything working locally, I logged into Jenkins on CloudBees. Since I hadn't used it in a while, I had to wait a bit while my Jenkins server was re-commissioned. Once it was up, I tried to select Grails 2.2.1 to build with, but found it wasn't available. After a tweeting this, I learned about Grails Wrapper, found that the latest Grails Jenkins plugin supported it and got everything working. I later discovered that CloudBees does support Grails 2.2.1, I just needed to setup another Grails installation to automatically download and install 2.2.1.
The last two issues I ran into were with Heroku. Since I was upgrading everything, I wanted Grails to build/run under Java 7 and use Servlet 3. I changed the appropriate properties in BuildConfig.groovy, configured Heroku and deployed. No dice.
Sidenote: I tried building with Java 8 on CloudBees, but discovered the searchable plugin doesn't support it.
Compile error during compilation with javac.
/scratch/jenkins/workspace/Happy Trails - Grails 2/work/plugins/searchable-0.6.4/src/java/grails/plugin/searchable/internal/compass/index/DefaultUnindexMethod.java:94: error: reference to delete is ambiguous
both method delete(CompassQuery) in CompassOperations and method delete(CompassQuery) in CompassIndexSession match
As far as Servlet 3, it was pretty obvious that the Jetty version Heroku uses for Grails doesn't support it. Therefore, I reverted back to Servlet 2.5.
I sent the Java 7 issue to Heroku Support a few days ago but haven't heard back yet.
While upgrading Grails from 2.0 to 2.2 wasn't as easy as expected, it is understandable. After all, Grails 2.2 ships with Groovy 2.0, which has a bunch of new features itself. All the issues I ran into were fairly easy to solve, except for Java 7 on Heroku. But hey, what do you expect from a free hosting service?
If you're at Devoxx France next week, I look forward to sharing our research on Grails 2.2.1 vs. Play 2.1.0.
David Díaz Clavijo sent me an email a couple weeks ago asking me about comparing web frameworks.
David is a computer engineering student at the University of Las Palmas de Gran Canaria (ULPGC) in the Canary Islands, Spain. His FYP (Final Year Project) is a web frameworks comparison focused on high productivity frameworks. He's started a blog to help facilitate his work and has been writing some interesting posts.
Four frameworks will be compared. The comparison test is composed by four fixed time tasks for each framework:
Learning the programming language: 5 hours
Making exercises in the programming language: 15 hours
Learning the framework: 25 hours
Developing the website: 50 hours
After all process is done, it can be seen which framework presented a higher productivity and smaller learning curve.
We have decided a cross-language set of frameworks which are: Ruby on Rails, Grails, Django and Code Igniter.
Sorry it took me so long to respond. I think your approach as far as learning the language, making exercises, learning the framework and developing the website is good. As you know, the last one you develop with will likely do well because you're repeated the steps so much with the other ones.
However, there's one thing I think you're doing wrong. In the real world, I don't believe that an architect would look at *all* the available web frameworks and choose one. I believe most of them already have a language bias or there's a target platform (e.g. LAMP, JVM, etc.).
I believe the majority of development happens today where a platform is already in place. Even moreso, the backend may already be in place and the company is simply trying to find a more productive front-end framework. In the first instance, where the platform is already chosen, the chooser's options are immediately limited. For example, if it's the JVM, Django might be eliminated because JPython isn't that up-to-snuff or widely used (this could be changing). However, it could be said that all the frameworks you've chosen (including Code Igniter) can run on the JVM.
I just don't see people identifying web frameworks across such a wide variety of languages. I think folks generally choose a platform, then a language, then a framework. It's possible that startups will do it differently by choosing a language first. However, I imagine most startups have a technical founder that already has some preference towards a particular language.
Now it's your turn, dear readers. Have you ever been in a situation where you've been able to pick a web framework across all languages? Did any of your biases enter into the equation?
How would you recommend David go about choosing web framework candidates?
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 Evite.com 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.
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.
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?
Last night, I had the pleasure of delivering two talks at the Denver Java User Group. The first talk, The Modern Java Web Developer, was inspired by the book titled The Well-Grounded Java Developer. Ben Evans and Martijn Verburg mention in the beginning of the book that they wrote it as a training guide to get new Java developers up to speed. For my talk, I wanted to do something similar, but for Java Web Developers.
I mentioned that the first thing you have to do to become modern is to change your title from a Java Web Developer to a JVM Web Developer. After doing that, you have a whole slew of new and wonderful technologies at your disposal. From there, I believe the Modern JVM Web Developer:
The second talk was on Java Web Application Security and was largely an updated version of the talk I gave a couple years ago, starting with an appearance at the Utah JUG. It was mostly a live demo session using my Ajax Login application. To prepare the project for this talk, I created branches for each step. This means you can checkout the "baseline" branch and use Git to compare it with the "javaee" branch. You can also compare the "spring-security" branch vs. the "apache-shiro" branch. Finally, you could see what I needed to do to fix many of the vulnerabilities found by Zed Attack Proxy.
... 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.
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:
java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
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.
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.
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.
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.
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:
I've been comparing web frameworks ever since 2004. It was the first time I'd ever proposed a talk for a conference. ApacheCon was in Vegas that year and my buddy Bruce suggested I speak at it. I submitted the talk, got accepted and went to work learning the frameworks I was talking about. At the time, I had a lot of Struts experience and I'd made a good living learning it, consulting on it and blogging about it. However, there was a new kid on the block (Spring MVC) that was garnishing attention and some other frameworks (WebWork and Tapestry) that had a lot of high praise from developers. I was inspired to learn why so many people hated Struts.
Fast forward 8 years and I'm still comparing web frameworks. Why? Because there still seems to be a large audience that's interested in the topic. Witness InfoQ's Top 20 JVM Web Frameworks, which was one of their most-read articles for two months in a row. One of the beauties of the Java Community is that it's very diverse. There's tons of folks that are part of this community and, like it or not, several folks that are former Java Developers. However, these developers still seem to maintain an interest in the community and it's still one of the largest pools of talent out there. Java is still quite viable and only seems to be getting better with age.
So the topic of web frameworks on the JVM is still hot, and I still like to write about it. For those of you still enthusiastic about the topic, you're in luck. The two best websites for the Java Community, InfoQ and DZone (formerly Javalobby) are still very interested in the topic too!
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.