Tuesday, December 5, 2006

Autocompleting with Stripes and Scriptaculous

I recently had to implement autocompletion AJAX functionality with script.aculous.us and Stripes. Once again this AJAX functionality was simple to integrate with Stripes. This code will return a list of users to select from after the user types more than two characters.

Here is an example Stripes action that will be responsible for looking up the users and returning a partial page with the unorder list of users. In this example code the autoCompleteText will capture the text that will be autocompleted. A Spring bean will be used to call out to service which will use a Hibernate DAO to query for the user list.

 public class UserLookupAction implements ActionBean {

String autoCompleteText;

UserService userService;
private List users;

public Resolution findUsers(){
this.users = userService.findUsersByAutocompletion(autoCompleteText);
return new ForwardResolution("/pages/useradmin/FindUsers.jsp");
}

@SpringBean
public void setUserService(UserService userService) {
this.userService = userService;
}

public String getAutoCompleteText() {return autoCompleteText;}

public void setAutoCompleteText(String autoCompleteText) {
this.autoCompleteText = autoCompleteText;
}

public List getUsers() {
return users;
}

public void setActionBeanContext(ActionBeanContext actionBeanContext);
public ActionBeanContext getActionBeanContext() {return this.actionBeanContext;}
}

This JSP is responsible for making the AJAX calls to the Stripes action above. The AJAX.Autocompleter code from Scriptaculous does the work when more than two characters are present in the text field named autocomplete. If there are results they are returned in a partial page as an unordered list (more later). An animated gif indicator is used to signal the user that the AJAX call is being made and searching for results. Also, there is a callback method called getSelectionId that is called afterUpdateElement. This will be used to set the selected user id in a hidden field named autocompleteUserId. This will be used when editing the user through another Stripes action (UserEditAction).

 <style type="text/css">
div.autocomplete {
position:absolute;
background-color:white;
border:1px solid #888;
margin:0px;
padding:0px;
}

div.autocomplete ul {
list-style-type:none;
margin:0px;
padding:0px;
}

div.autocomplete ul li.selected { background-color: #ffb;}

div.autocomplete ul li {
list-style-type:none;
display:block;
margin:0;
padding:5px;
cursor:pointer;
border-bottom: 1px solid #cbcbcb;
}
</style>


<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %>

<stripes:form beanclass="com.meagle.web.stripes.action.useradmin.UserEditAction">
User Name:
<stripes:text size="30" id="autocomplete" name="autoCompleteText"/>

<div id="autocomplete_choices" class="autocomplete"></div>
<script type="text/javascript">

new Ajax.Autocompleter ("autocomplete",
"autocomplete_choices",
"${pageContext.request.contextPath}/useradmin/UserLookup.action?findUsers=",
{minChars: 2, afterUpdateElement : getSelectionId, indicator: 'indicator1'});

function getSelectionId(text, li) {
$('autocompleteUserId').value = li.id;
}
</script>

<stripes:hidden name="userId" id="autocompleteUserId"/>
<stripes:submit name="editUser" class=class="code-quote">"textBox" value="Edit"/>

<span id="indicator1" style="display: none">
<img width=
"14" height="14"
src="${pageContext.request.contextPath}/images/indicator_circle_ball.gif"
alt="Working..." />

</stripes:form>
Finally, this is the partial page that is returned by the UserLookupAction when results are returned. This simply iterates over the User objects from the Stripes action and creates an unorder list that is stylized with the CSS above.

 <%@ taglib prefix="c" uri=<http://java.sun.com/jsp/jstl/core> %>

<ul>
<c:forEach var="user" items="${ actionBean.users}">
<li id="${user.id}">${user.firstName} ${user.lastName}</li>
</c:forEach>

</ul>

Thursday, November 23, 2006

AJUG Stripes Presentation

Phil Barnes and I presented the Stripes framework at AJUG last night. We wanted to spread the word about Stripes and how it simplifies Java Web development. Most of the people who attended the presentation were using Struts as their presentation framework (no surprise here). We came prepared with many examples about how Stripes compared to Struts.

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!

For some time now I have been evaluating Java web frameworks. This was mostly driven by my frustration with existing frameworks I have been using. The amount of effort it takes to feed these frameworks to produce anything meaningful is usually painful and not fun to maintain. My baseline framework for Java Web development has been Struts. Struts is just outdated and requires way too many configuration files, extra classes outside the controller/action, and a separate ActionForm class that requires crude object binding. Enough said. From Struts I investigated a slew of frameworks such as Tapestry, Wicket, Spring MVC, and some JSF. These frameworks were definitely better than Struts (not too hard to achieve) but never felt much more productive and varied in learning curves. Then I started to investigate WebWork. This was definitely a step in the right direction. WebWork is an action based framework that is the basis for the Struts Action 2.0 Framework. WebWork does offer simpler actions, less configuration, some AJAX support, different view resolvers, interceptor stacks, and much more. We even decided to use WebWork for our new project after we felt that it addressed most of our concerns and there was nothing better to work with. We did experience more than a 40%+ reduction in the number lines of code and configuration files we had to write. This was great until...

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

Lately there have been Java Web framework comparisons on theServerSide.com. These comparisons revolve around requirements on Simon Brown's Blog. I am not sure that the application is very relevant and has limited functionality. However, I decided I would try this with WebWork. I have been using WebWork for about 5 months now and have been very productive with the framework's capabilities and ease of use. I took the requirements for the read only blog and reproduced it with WebWork. There is really very little that needed to be coded to make this happen and I did this on a plane trip from Atlanta to Las Vegas where I am attending TSSS with only one battery in my notebook.

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">
<result name="success">/pages/index.vm</result>
<result name="blogentry">/pages/entry.vm</result>
</action>
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:
     <%@ 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">
<ww:param name="blogEntryId" value="id"/>
</ww:url>
<a href="<ww:property value="readMoreUrl" escape="false"/>">Read More</a>

These lines create a link that calls the 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 tag references our Action class method viewBlogEntry(); it's in this method that we pull the specific entry and expose it (via a class variable) so that the view layer can render the entry. Here is the code for the view for displaying the entry.

     <%@ 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.