Thursday, November 23, 2006
AJUG Stripes Presentation
I think that the presentation was well received and hopefully it will make people take another look at Stripes. We have researched many Java Web frameworks and this is probably the best one out there as far as simplicity while allowing the developer to focus on application development. Stripes uses convention over configuration for resolving URLs to action classes, has excellent databinding, and integrated well with other POJO based frameworks.
Please contact me at meagle@gmail.com if you want a copy of the slides.
Friday, April 28, 2006
Stripes: I think we have a winner!
The Stripes project recently released version 1.3 of their web framework. This framework relies heavily on Java 5 capabilities to deliver a much simpler web framework. The configuration is done up front in the web.xml file where a filter and a Servlet dispatcher is configured. The only thing that you need to be aware of is to configure the root package of your Stripes action classes. This allows Stripes to inspect your action classes when your servlet container starts up. Stripes uses a convention based approach to determine which classes in this defined package will be Stripes actions. Therefore, action classes do not have to be configured in an XML file. That's right - no more struts-config, xwork.xml, JSF config nonsense, etc.
From this point on you are ready to code. The action classes that you build contain concise annotations that handle interception, validation, Spring integration, and more. With your classes annotated you do not have to flip back and forth between external files and your action classes. This saves you a ton of time and reduces lines of code. In fact we migrated our WebWork code to Stripes equivalents and experienced another 20%+ reduction in the lines of code (and removing configuration files) while maintaining full functionality. Not too bad. The migration only took about 2 days to complete for about 8 complex actions and 12 JSPs. As you can see will be using this on all of our projects.
The only con I can think of for Stripes is that you have to use JSP and the Stripes taglibs. However, the taglib is pretty good and very close to HTML in regards to the naming used. I am hoping that a Velocity view resolver is on the horizon in the not too distant future. However, I did not experience too many problems with JSTL and the Stripes taglib.
If this sounds good take a look at the Stripes Quick Start Guide to quickly get up and running. Stripes is a great step forward for Java web development. It offers Java developers an simple way to program Java web applications with minimal configuration, high productivity, and a fun development framework that is addictive. This might be as close to the Ruby on Rails Action Pack for MVC development as we will see in a while from the Java community.
Tuesday, March 28, 2006
Comparing Web Frameworks: WebWork
To save time I copied some of the components from other people's implementations that were not framework specific.This included the domain objects
Blog
, BlogEntry
, and BlogService
. Theseare straightforward and I could have generated them in IntelliJ in about 2 minutes so no big deal. I also copied the stylesheet and image that was used to pretty up the blog look and feel. Again, no big deal and not really relevant to the framework comparison. So let me take a moment to preface some of my gripes with this little project. First, I do not consider someof the methods I used to code this application to be ideal. Since this is a read only blog application I did not use a persistence mechanism for the blog entries. Nevertheless, I coded the application to the specifications required using only the WebWork web tier components no more. The main WebWork component that needed to be designed was the action class. This is fairly lean and should be
easy to interpret. Here is the code:
public class BlogAction implements Preparable {
private Blog blog;
private BlogEntry blogEntry;
private String blogEntryId;
private BlogService blogService;
public void prepare() throws Exception {
blog = getBlogService().getBlog();
}
public String execute() {
// simply display the default page -- the data was setup in prepare()
return "success";
}
public String viewBlogEntry() {
this.blogEntry = blog.getBlogEntry(this.blogEntryId);
return "entry";
}
public void setBlogEntryId(String blogEntryId) {
this.blogEntryId = blogEntryId;
}
public Blog getBlog() { return blog; }
public BlogEntry getBlogEntry() { return blogEntry; }
protected BlogService getBlogService() {
if (blogService == null) {
blogService = new BlogService();
}
return blogService;
}
public void setBlogService(BlogService blogService) {
this.blogService = blogService;
}
}
This is about 40 lines of code and most of that is comments, fields, and accessors. Really there are only about 5 lines of code of any logic. The
prepare
method is called before the action executes to setup the action. This gets called because the action implements the Preparable
interface. The Prepare interceptor is invoked as one of the interceptors in the default interceptor stack. The service should really be injected into the action by an IoC container such as Spring (WebWork has good integration support with Spring). Also notice that other than implementing the Preparable
interface this action is just a POJO.Here is the action configuration in the xwork.xml file:
<action name="Blog" class="com.meagle.wwblog.web.webwork.actions.BlogAction">As for the views there were two files. The first one shows the blog and associated entries. I used SiteMesh todecorate the common elements and JSP as the view resolver to display the stack elements. WebWork can also use Freemarker, Velocity, and other view resolvers as well. Here is what the Sitemesh decorator looks like:
<result name="success">/pages/index.vm</result>
<result name="blogentry">/pages/entry.vm</result>
</action>
<%@ page pageEncoding="UTF-8"%>
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>
<%@ taglib prefix="ww" uri="/webwork" %>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title><decorator:title default="Welcome!" /></title>
<meta http-equiv="Content-Style-Type" content="text/css">
<link rel="stylesheet" href="/css/screen.css" type="text/css"/>
</head>
<body>
<div id="container">
<h1><decorator:title default="Welcome!" /></h1>
<h2><ww:property value="%{blog.description}"/></h2>
<decorator:body />
</div>
</body>
</html>
So this takes care of the blog title, name, and description that appears on each page. This also leaves a placeholder for the content of each page. Here is what was required to display the entries in the blog:
<%@ page pageEncoding="UTF-8"%>
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib uri="/webwork" prefix="ww" %>
<html>
<head>
<title><ww:property value="%{blog.name}"/></title>
</head>
<body>
<table>
<ww:iterator value="blog.blogEntries" id="blogEntry">
<tr>
<td>
<div class="blogEntry">
<h3><ww:property value="title"/></h3>
<div>
<ww:if test="excerpt != null">
<ww:property value="excerpt" escape="false"/>
</ww:if>
<ww:else>
<ww:property value="body" escape="false"/>
</ww:else>
</div>
<p>
<ww:if test="excerpt != null">
<ww:url id="readMoreUrl" action="Blog!viewBlogEntry">
<ww:param name="blogEntryId" value="id"/>
</ww:url>
<a href="<ww:property value="readMoreUrl" escape="false"/>">Read More</a>
</ww:if>
</p>
<p>
Posted on <ww:date name="%{date}" format="dd MMMM yyyy hh:mm:ss z"/>
</p>
</div>
</td>
</tr>
</ww:iterator>
</table>
</body>
</html>
Again, this is straightforward and captures the requirements of the application. The only interesting lines here that allows the user to conditionally view more of a blog entry is this:
<ww:url id="readMoreUrl" action="Blog!viewBlogEntry">These lines create a link that calls the
<ww:param name="blogEntryId" value="id"/>
</ww:url>
<a href="<ww:property value="readMoreUrl" escape="false"/>">Read More</a>
viewBlogEntry
method of the Blog action by using a WebWorkconvention. The blog entry ID is appended as a parameter so that we can display the correct blog entry. You may notice the "action" in the <%@ page pageEncoding="UTF-8"%>
<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="ww" uri="/webwork" %>
<html>
<body>
<ww:if test="blogEntry != null">
<div class="blogEntry">
<h3><ww:property value="blogEntry.title" escape="false"/></h3>
<div><ww:property value="blogEntry.body" escape="false"/></div>
<p>
Posted on <ww:date name="%{blogEntry.date}" format="dd MMMM yyyy hh:mm:ss z"/>
</p>
</div>
</ww:if>
<ww:else>
<div class="blogEntry">
<h3>Sorry we could not locate that blog entry...</h3>
</div>
</ww:else>
<div><a href="JavaScript:void(0)" onclick="history.go(-1)">Back</a></div>
</body>
</html>
That is really all there was to coding the requirements of the application. The rest of the components were skeleton elements from a base WebWork configuration.
Conclusion
While this is a very simplistic web application with little functionality it does show how little coding is required by WebWork to make it happen. There is so much more that I would have like to have shown such as some of the data binding capabilities inside WebWork when submitting form information with complex object graph information. This trivial application really does not show WebWork's full capabilities. If you think there is value in this example then you should give WebWork a try on more complex applications.
WebWork makes coding web development with Java simple and very productive with the framework's capabilities and ease of use.
Tuesday, October 25, 2005
Java Web Framework Changes...
Wednesday, August 17, 2005
Is Java Dead?
I have already been exposed to Ruby on Rails and I am currently reading the new Pragmatic Programmers book - 'Agile Web Development with Rails'. I am finding that this book is a good read that walks a developer through the process. It is hard to ignore technologies that are as productive as Rails when compared to what I consider a 'lightweight' Java stack to build equivalent Web applications. I consider Struts, Velocity, Spring, and Hibernate a lightweight and productive Java stack for building an end-to-end Web application. However, Web development Ruby on Rails is much faster and elegant compared to any Java stack today.
What is even more frustrating is when I read about technologies JSF. Let's see - we will build a framework (and by the way make it a standard) which is *way* fatter than something like Struts and tell developers that feeding a framework is a good thing. Rails is so much more simple and elegant that JSF from a presentation/MVC perspective. I think that Sun is making a big mistake with this framework. They finally figured out that EJB was bloated and POJOs were good. Now they are going to learn another lesson on the front end. Well, I am not following the piper this time... More than likely I will stick with my lightweight Java stack - Struts, Velocity, Spring, and Hibernate. If I need to do component development in my presentation layer I will choose Tapestry 4.
Finally, towards the end of Bruce's presentation he discussed how 2/3 of his development in mid-2006 will be non-Java. If that is not enough to make you take notice of what is going on around you then I do not know what it would take. How much more can we stretch the Java language before we turn to dynamic languages? Is Java dead or dying a slow death?