Rainy days and Java always get me down


I've Moved My Blog

It's currently located at http://www.urlinone.com/blog

I should say "I'm moving my blog." It's a pretty painful process.

Pebble has blown up on me, and it's been many months since I've been able to blog reliably. I've lost posts. And now I've got to figure out how to migrate my past blog posts from Pebble to my new destination without all the URLs changing, lest external links become 404 Not Founds.

Why does everything in the 21st century have to be a three-day project???

Maybe it was the fact that I had just come off of nitrous oxide..., uh, because I had just had, uh, dental work, yeah, that's it, I had just had dental work, yeah, dental work! That's the ticket! Anyway, I would swear that Weird Al Yankovich came to the Atlanta Java Users Group meeting last week to talk about Tapestry. But that's probably just the nitrous talking.

In my susceptible state, Howard Lewis Ship convinced me that Tapestry was a very powerful web layer and superior alternative to Struts (not hard to convince me of that!), WebWork, Spring MVC, and all the other MVC frameworks now competing for our attention. I have to say, I think I agree. Tapestry takes a different approach from all the other MVC frameworks, and you end up with clean, succinct, and nice-looking code and web pages. I think I've found my presentation layer of choice -- at least until I start hunting for just the right RIA platform with which to drive myself nuts. Quick, where's that nitrous?!

Anyway, I was able to integrate Tapestry 3.0 into AppFuse 1.5, effectively tripling my version number to 4.5, which was quite a coup. Here's how I did it...

The first step is to add the tapestry jar to the classpath. To do this, you must copy the jar and edit two files.

1. Create directory Tapestry-3.0 under the lib directory.

2. Copy tapestry-3.0.jar into lib/Tapestry-3.0.

3. Edit lib/lib.properties, adding the following at the very bottom of the file:

#
# Tapestry - http://jakarta.apache.org/tapestry
#
tapestry.version = 3.0
tapestry.dir=${lib.dir}/Tapestry-${tapestry.version}

4. Edit properties.xml. Locate the line that says

<path id="web.compile.classpath">

5. Go down about 17 lines, and just before the line that says

</path>

add the following line:

    <fileset dir="${tapestry.dir}" includes="*.jar"/>

Now, all jar files in lib/Tapestry-3.0 will be part of the classpath when compiling the web module.

Next, we have to change the deployment descriptors to allow Tapestry's servlet to run and for certain URLs to reach it.

1. Add the following to the bottom of metadata/web/servlets.xml:

    <!-- Tapestry Servlet Configuration -->
    <servlet>
        <servlet-name>tapestry</servlet-name>
        <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

2. Add the following to the bottom of metadata/web/servlet-mappings.xml:

    <!-- Tapestry Servlet Mapping -->
    <servlet-mapping>
        <servlet-name>tapestry</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>

3. Add the following to the top of metadata/web/web-security.xml:

    <!-- Grant access to public areas -->
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>TapestryPages</web-resource-name>
            <description>Tapestry Pages</description>
	    <url-pattern>*.htm</url-pattern>              
            <http-method>POST</http-method>
            <http-method>GET</http-method>
        </web-resource-collection>
    
        <user-data-constraint>
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

We've now added the Tapestry servlet, mapped all URLs with an .htm extension to it, and granted free access to these pages without having to be logged in via AppFuse's security model. Enabling security is outside the scope of this document.

Next, we'll add a simple Tapestry page to the application:

1. Create a file called Home.java in src/web/org/appfuse/webapp:

package org.appfuse.webapp;

import java.util.Date;
import org.apache.tapestry.html.BasePage;

public class Home extends BasePage {
	public Date getCurrentDate() {
		return new Date();
	}
}

2. Create a file called Home.html in web/WEB-INF:

<html>
<head>
<title>Simple</title>
</head>
<body>
<p>
   This application demonstrates some dynamic 
   behavior using Tapestry components.
<p>
   The current date and time is: 
   <b><span jwcid="insertDate">This Text Will Be Replaced</span></b>
<p>
   Click <a jwcid="refresh">here</a> to refresh.
</body>
</html>

3. Create a file called Home.page in web/WEB-INF:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE page-specification
      PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN"
      "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">

<page-specification 
	class="org.appfuse.webapp.Home">
    <description>Simple Home Page</description>

	<component id="insertDate" type="Insert">
		<binding name="value" expression="currentDate"/>
	</component>
	<component id="refresh" type="PageLink">
		<static-binding name="page">Home</static-binding>
	</component>
</page-specification>

If you read one of the many Tapestry tutorials, you will not have a difficult time understanding this exceedingly simple Tapestry page. I highly, highly recommend this free sample chapter from Tapestry in Action.

One note about Tapestry and accompanying jars:

I had to manually retrieve a couple of jars that I would have thought Tapestry would include automatically. Namely, I had to download and copy the jars for OGNL and Javassist, since Tapestry referred to them, but they were not included in the Tapestry install. Maybe it's a licensing thing? Anyway, I put all the jars in my $CATALINA_HOME/common/lib directory, rather than putting them into my AppFuse lib area. I guess either way will work, but who needs the monster war every time you build? But you do need the tapestry-3.0.jar in the web.compile.classpath to resolve external references.

Now, all you have to do is ant deploy start.tomcat, and your AppFuse project should be unchanged, other than the addition of the Tapestry page at http://localhost:8080/appfuse/Home.htm. You should be able to add a link to this URL within your Struts pages in AppFuse and jump back and forth, although I am sure that there are all kinds of ugly issues with session state once you start doing anything meaningful.

That's as far as I've gone with this, so there are probably plenty of issues to deal with in this mutant, hybrid environment. Matt Raible plans on adding a Tapestry version of AppFuse some time in late 2004, but this allows you to at least play with Tapestry today. Have fun, and feel free to post problems, suggestions, and enhancements!