Contents:
My What's New in Spring 3.1 Presentation
My first business trip of the year was to Dublin, CA this past week. Trish joined me because she wanted to take some pictures of San Francisco. She got some awesome shots as you can see below.
On Tuesday night, I attended Twitter's Open Source Summit with a co-worker and had a great time.
On Wednesday, I talked about What's New in Spring 3.1 at the Silicon Valley Spring User Group. I discussed the support for Java 7, Servlet 3, Hibernate 4 (and JPA 2 with Spring Data) and the new Cache Abstraction. I mentioned how spring-data-jpa-examples is a great sample project and showed a bunch of code from my Spring Kickstart project. I was surprised to find that no one in the audience (all Spring users) was using Java Config. Below are the slides from my presentation and you can also download the PDF.
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 teams 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 AppFuse.next, 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">
</div>
</div>
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>
</div>
</div>
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' : ''}">
</spring:bind>
<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"/>
</div>
</fieldset>
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.
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.
Upgrading AppFuse to Spring Security 3.1 and Spring 3.1
Before the holiday break, I spent some time upgrading AppFuse to use the latest releases of Spring and Spring Security. I started with Spring Security in early December and quickly discovered its 3.1 XSD required some changes. After changing to the 3.1 XSD in my security.xml, I had to change its <http> element to use security="none" instead of filters="none". With Spring Security 3.0.5, I had:
<http auto-config="true" lowercase-comparisons="false">
<intercept-url pattern="/images/**" filters="none"/>
<intercept-url pattern="/styles/**" filters="none"/>
<intercept-url pattern="/scripts/**" filters="none"/>
After upgrading to 3.1, I had to change this to:
<http pattern="/images/**" security="none"/>
<http pattern="/styles/**" security="none"/>
<http pattern="/scripts/**" security="none"/>
<http auto-config="true">
The next thing I had to change was UserSecurityAdvice.java. Instead of using Collection<GrantedAuthority> for Authentication's getAuthority() method, I had to change it to use Collection<? extends GrantedAuthority>.
Authentication auth = ctx.getAuthentication();
Collection<? extends GrantedAuthority> roles = auth.getAuthorities();
Lastly, I discovered that SPRING_SECURITY_CONTEXT_KEY moved to HttpSessionSecurityContextRepository. Click here to see the changelog for this upgrade in AppFuse's FishEye.
You can read more about what's new in Spring Security 3.1 on InfoQ. I'm especially pumped to see http-only cookie support for Servlet 3.0. I discovered Spring Security didn't support this when Pen-Testing with Zed Attack Proxy.
Upgrading to Spring Framework 3.1
Compared to the Spring Security upgrade, upgrading to Spring 3.1 was a breeze. The first thing I discovered after changing my pom.xml's version was that Spring Security required some additional exclusions in order to get the latest Spring versions. Of course, this was communicated to me through the following cryptic error.
-------------------------------------------------------------------------------
Test set: org.appfuse.dao.LookupDaoTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.004 sec <<< FAILURE!
testGetRoles(org.appfuse.dao.LookupDaoTest) Time elapsed: 0.001 sec <<< ERROR!
java.lang.NoSuchMethodError: org.springframework.context.support.GenericApplicationContext.getEnvironment()Lorg/springframework/core/env/ConfigurableEnvironment;
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:97)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
Without these additional exclusions, Spring Security pulled in Spring 3.0.6. I had to exclude spring-expression, spring-context and spring-web from spring-security-taglibs to get the 3.1.0.RELEASE version of Spring.
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
</exclusions>
</dependency>
I also had to exclude spring-context from spring-security-config and spring-context and spring-expression from spring-security-core. Isn't Maven wonderful?
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
After making these changes, I got a bit further, but ended up being blocked by a bug in Tapestry 5's Spring support. Basically, after upgrading to Spring 3.1, I started seeing the following error:
java.lang.RuntimeException: Service id 'environment' has already been defined by
org.apache.tapestry5.services.TapestryModule.buildEnvironment(PerthreadManager)
Luckily, I was able to easily fix this with advice I found on Tapestry's mailing list. Unfortunately, even though I submitted a fix on December 15th, it didn't make it into Tapestry's 5.3.1 release on December 21st. As soon as Tapestry 5.3.2 is released, I hope to get the AppFuse's build passing again (it's currently failing).
I hope this article helps you upgrade your AppFuse-started applications to the latest versions of Spring and Spring Security. Over the next few weeks, I'll be exploring many of Spring 3.1's new features and implementing them as I see fit. Right now, I'm thinking environments/profiles, Servlet 3 / Java 7 support and Hibernate 4 support. These seem to be the best new features to learn about for my talk in a few weeks.
What have I been working on at Taleo?
2011 has been a year of great clients for me. I started working with O.co and very much enjoyed my time there, especially on powder days in Utah. The people were great, the contract was great (no end date), but the work was not my forte. I was on a project to modularize the main shopping site's codebase, which involved mostly refactoring. By refactoring, I mean creating new Maven projects, modifying lots of pom.xml files and literally moving files from one directory to another. IntelliJ made this easy, the hard part was refactoring tests, moving from EasyMock to Mockito and splitting classes into interfaces and implementations where appropriate. As a developer who likes developing UIs and visually seeing my accomplishments, the project wasn't that exciting. However, I knew that it was strategically important to O.co, so I didn't complain much.
In mid-May, I received a LinkedIn message from the Director of Software Engineering at Taleo.
This is OB, I am the Director of Software Engineering at Taleo. We are the 2nd largest Software as a Service company. I am building a new specialist UI team that will take the product to the next level. I am looking for someone to lead this initiative. If you are interested to have a chat about it, please let me know.
At that time, I'd never heard of Taleo and quickly recommended they not hire me.
This probably isn't the best position for me. While I am a good leader, I'm not willing to relocate from Denver. I've found that leaders usually do best when face-to-face with their developers.
This conversation continued back-and-forth where I explained how I wasn't willing to go full-time and I didn't want to leave Overstock. In the end, OB was persistent and explained how the position would entail lots of UI work and wouldn't require me to travel much. Our negotiations trailed off in June and resumed in July after I returned from vacation in Montana. Shortly after, we met each other's expectations, agreed on a start date and I started working at Taleo in early September.
When I started, there were three features they wanted to add to to Taleo Business Edition: Profile Pictures, Talent Cards and Org Charts. They knew the schedule was tight (8 weeks), but I was confident I could make it happen. At first, I groaned at the fact that they were using Ant to build the project. Then I smiled when I learned they'd standardized on IntelliJ and set things up so you could do everything from the IDE. After using Maven for many years, this setup has actually become refreshing and I rarely have to restart or long for something like JRebel. Of course, a
Home