Getting Started with Struts Shale

In JavaEE by timfanelliLeave a Comment

Struts Shale is a proposal for a next-generation web development framework. I’ve spent a couple days scouring the internet trying to find a simple getting started guide to build a new Shale application, but there just doesn’t seem to be one yet. Shale’s website promises that a future milestone release will include a blank template ready for customization, but in the meantime, we’re left to reading JavaDoc to figure out how to get going. This tutorial will walk you through building a very simple Hello / GoodBye world application using Shale and JavaServer Faces technology from scratch.

Creating a Directory Layout

The first thing we’ll do is create our project layout. I’m a fan of Maven, and like they’re standard directory layout templates, but for simplicities sake, we’ll ignore it for now (I’ll come back to Maven later regarding Shale). Instead, lets create the following directories:

helloworld/
   src/
   webapp/
      WEB-INF/
         lib/

This will be enough to get us started.

A Plethora of Dependencies

The next thing we’ll need to do is download the plethora of dependencies our simple project will have. First download our direct dependencies:

Then you’ll need to download the libraries that those project are dependent on:

*Phew*. Copy the library jars into your WEB-INF/lib directory that we created before. Here’s my directory listing for reference:

> ls
commons-beanutils-1.7.0.jar     commons-digester-1.7.jar        commons-logging-1.0.4.jar       myfaces-all-1.1.1.jar
commons-chain-1.0.jar           commons-el-1.0.jar              commons-validator-1.1.4.jar     oro-2.0.8.jar
commons-codec-1.3.jar           commons-fileupload-1.0.jar      jstl-1.1.2.jar                  shale-core.jar
commons-collections-3.1.jar     commons-lang-2.1.jar

Setting up web.xml

The next step is to create our helloworld/WEB-INF/web.xml descriptor file for our hello world web application. Copy the following into your web.xml. It sets up your web application to use the Shale Application Filter, the Commons Chain Listener, and the Shale Servlet mapping. All this amounts to is using Shale as your application’s controller.

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http:/java.sun.com/dtd/web-app_2_3.dtd">

	<display-name>Hello/Goodbye World!</display-name>

	<!-- Determines wether state is saved on the server or on the client. The 
	     tradeoff here is server memory versus network bandwidth. -->
	<context-param>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>server</param-value>
	</context-param>

	<!-- Sets up the shale application filter -->
	<filter>
		<filter-name>shale</filter-name>
		<filter-class>
			org.apache.shale.faces.ShaleApplicationFilter
		</filter-class>
	</filter>
    
	<filter-mapping>
		<filter-name>shale</filter-name>
		<url-pattern>*.faces</url-pattern>
	</filter-mapping>
		
	<!-- Set up the Commons Chain listener -->
	<listener>
		<listener-class>
			org.apache.commons.chain.web.ChainListener
		</listener-class>
    	</listener>

	<servlet>
		<servlet-name>faces</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    	</servlet>
    	<servlet-mapping>
		<servlet-name>faces</servlet-name>
		<url-pattern>*.faces</url-pattern>
    	</servlet-mapping>
</web-app>

Framework Config Files

Now that we have our dependencies in place and a webapp that is configured to use Shale, we’ll add some blank configuration files under helloworld/WEB-INF that Shale and JSF will need in order to properly initialize themselves.

chain-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<catalogs>
	<catalog name="shale">
      <!-- Disallow direct access to JSP and JSFP resources -->
      <command      className="org.apache.shale.application.ContextRelativePathFilter"
                     includes="\S*\.xml,\S*\.faces,\S*\.html,\S*\.gif,\S*\.jpg,/index\.jsp"
                     excludes="\S*\.jsp,\S*\.jspf"/>					 		
	</catalog>
</catalogs>

dialog-config.xml

<!DOCTYPE dialogs PUBLIC
  "-//Apache Software Foundation//DTD Shale Dialog Configuration 1.0//EN"
  "http://struts.apache.org/dtds/shale-dialog-config_1_0.dtd">

<dialogs>

</dialogs>

We only define one rule in our Chain’s shale catalog, and that’s to dissallow direct access to our JSP files. This is because we want to force our users to access the site through the JSF Servlet. The digest-config.xml file is required as of the 20051208 nightly build of Shale – the default application filter won’t initialize without it. I don’t know if this is a bug or not, but since dialog-config doens’t concern us in this example, we’ll just create an empty one. We’ll also need a faces-config.xml file, but we’ll revisit that in a bit.

Finally, the Web App

I know that seems like a lot of work to have gotten nowhere so far; if you ever worked with Struts from scratch I think you’d have thought the same thing about that. We’re getting there though, it’s finally time to write some code and make some JSPs.

First we’ll create a simple PersonBean class:

package com.timfanelli.jsfsample;

public class PersonBean {
	private String name;
	
	public void setName( final String name )
	{
		this.name = name;
	}
	
	public String getName()
	{
		return this.name;
	}
}

Then we’ll create some JSPs. One will prompt for your name, and populate the person bean with the value you enter. The others will say hello or goodbye, depending on which action the user chooses.

welcome.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<html>
	<head>
		<title>Hello/GoodBye World!</title>
	</head>
	<body>
		<f:view>
			<h1><h:outputText value="Welcome!"/></h1>
			<h:form id="helloform">
				<h:outputText value="Please enter your name:"/>
				<h:inputText value="#{personBean.name}"/>
				<h:commandButton action="sayhello" value="Say Hello"/>
				<h:commandButton action="saybyebye" value="Say Goodbye"/>
			</h:form>
		</f:view>
	</body>
</html>

hello.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<html>
	<head>
		<title>Hello/Goodbye World!</title>
	</head>
	<body>
		<f:view>
			<h3>Hello, <h:outputText value="#{personBean.name}"/></h3>
		</f:view>
	</body>
</html>

byebye.jsp

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<html>
	<head>
		<title>Hello/Goodbye World!</title>
	</head>
	<body>
		<f:view>
			<h3>GoodBye, <h:outputText value="#{personBean.name}"/></h3>
		</f:view>
	</body>
</html>

If you’re not familiar with JSF already, you’re probably wondering how all of this is going to tie together… How does personBean get into my JSP’s and how do the input buttons on welcome.jsp get me to hello.jsp or byebye.jsp? That’s where we come back to the faces-config.xml file.

Setting up faces-config.xml

Create a file called helloworld/WEB-INF/faces-config.xml and copy the following into it:

<?xml version="1.0"?>

<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">

<faces-config>
	<navigation-rule>
		<from-view-id>/welcome.jsp</from-view-id>
		<navigation-case>
			<from-outcome>sayhello</from-outcome>
			<to-view-i>d>/hello.jsp</to-view-id>
		</navigation-case>
		<navigation-case>
			<from-outcome>saybyebye</from-outcome>
			<to-view-id>/byebye.jsp</to-view-id>
		</navigation-case>
	</navigation-rule>
 
	<managed-bean>
		<managed-bean-name>personBean</managed-bean-name>
		<managed-bean-class>com.timfanelli.jsfsample.PersonBean</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>

</faces-config>

faces-config sets up our navigation rules. In particular, if we’re coming from /welcome.jsp and the “outcome” is “sayhello”, go to the hello.jsp view; if the “outcome” is “saybyebye”, go to the byebye.jsp view. The “outcome” is determined by the action property of the commandButton elements your “from-view”, welcome.jsp.

Additionally, you can see we’ve created a managed-bean called personBean that is an instance of our com.timfanelli.jsfsample.PersonBean class. personBean has request scope, and is therefore available throughout processing of the entire request. Its properties can be accessed and set using the #{beanname.propertyname} convention, as shown in all three JSPs.

Build, Package, Deploy

With all this in place, you should now be able to compile, build, deploy and run your web application. I’m going to assume that you’re comfortable enough on this process to bang out a quick ant script (or maven pom) to do the job for you.

Once you can access your webapp, please keep reading! (I’m writing this based off the sample project I just completed, so if you find that I missed a step in my writeup, please post comments!)

You can access your sample app by browsing to your context-root /welcome.faces. That will trigger the JSF servlet to find and load a view named “welcome”, which corresponds to your “welcome.jsp”

WARNING: No ViewController for viewId

If you’re like me, you watched your logs carefully while running your little sample app, and you’d have noticed several warnings telling you there’s new view controller for view id found under name . This is where we get to start (not) using Shale’s features. Shale provides a 1:1 relationship between views (your jsps) and backing beans (think controller). It’s not an error for there to be no backing bean, but the relationship is one-to-one, not one-to-atmost-one. So we’ll create a couple quick empty controller classes and tie them in. For brevity, I’ll only show you one. You should be able to handle the other two on your own then.

First, create a new class that extends AbstractViewController:

package com.timfanelli.shalesample.viewcontrollers;

import org.apache.shale.view.AbstractViewController;

public class WelcomeViewController extends AbstractViewController {
	public WelcomeViewController() {
		super();
	}
	
	public void init() {
		// Obtain generic resources here - that is, resource that you need regardless
		// of the context of the request you're going to process.
	}
	
	public void preprocess() {
		if ( ! isPostBack() ) 
			return;
			
		// Obtain resources you'll need to process the postback - for instance, database 
		// connections.
	}
	
	public void prerender() {
		// Use this method to acquire resources (such as database connections, 
		// or performing queries) that you will need if this view is the one to 
		// be rendered.
	}
	
	public void destroy() {
		// Clean up any resources you obtained in previous event handlers.
	}
}

Then add a managed-bean to your faces config:

...
	<managed-bean>
		<managed-bean-name>welcome</managed-bean-name>
		<managed-bean-class>com.timfanelli.shalesample.viewcontrollers.WelcomeViewController</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>
...

And that’s it! The magic is in the naming convention. We have a view called “welcome.jsp”. Shale will try to find a backing-bean for your view named “welcome”. Note that there’s no actual requirement for your backing bean to implement the ViewController interface (AbstractViewController is a convenience base class) – but Shale guarantees that if it does, you’ll get extra “freebies” from the framework. For more information on using ViewController, See Here

Add similar empty view controllers to your “hello” and “byebye” views to make the rest of your warnings go away.

Conclusion

While we used virtually none of Shales features, this should be more than enough to get you on your way to using the newest (and potentially hottest) web development framework out there.

Resource Roundup

I found the following resource helpful to get myself started using JSF and Shale:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.