Using WebObjects DirectActions pt. 1

Someone asked where they could go to find a tutorial on using WebObjects DirectActions , I went looking and, horrors of horrors, found the Internet wanting! Really, I should write a letter. Sigh… why do I have to do everything around here?

There are two ways of invoking actions in a WebObjects application. Component Actions and Direct Actions (Actions are methods triggered by a request – ie: clicking a link triggers an action to return the next page, or clicking a button triggers an action to log a user in with form values). Component actions are used by default and are covered extensively by the Apple tutorials (binding to the action binding of a WO Dynamic Element – WOActiveImage, WOHyperlink, WOSubmitButton, etc – generates a component action). The resulting URLs are dynamic (based on the context id, session id, and component id) and cannot be bookmarked.

Component actions are well suited for many types of applications (wizards, order checkout, admin utilities, etc). But because they have a dynamic URL they may not be suitable if you need to allow visitors to bookmark their pages (a catalog or reference site for instance). As well, each visitor will receive a relatively heavyweight Session object, so they may not be appropriate if you expect a lot of visitors and/or you do not need to track their state. Direct Action are designed for these situtations.

Direct Actions (DAs) are a WebObjects mechanism for performing actions with a static URL. Direct Actions don’t automatically invoke a Session (if you don’t need one) so they can be lighter weight. However they require a little more effort to get to work, and because they are not inherently stateful, you need to think a little more to ensure that state is captured.

We’re going to look at a simple example of the steps needed to setup and trigger a DirectAction.

There are three steps to setting up and using a DirectAction:

  1. Configure the Application Request Handler
  2. Create the action in the DirectAction class
  3. Create a link or redirect to access the new directAction

1. Configuring the Application Request Handler

By default a new WebObjects application will have a component action request handler (identified by the /wo/ portion of the URL). This is a sample component action URL:

http://localhost/cgi-bin/WebObjects/
            this.woa/wo/E5gVcEa7GA0bT714xOYsUg/0.0.3.1

As an aside: The string E5gVcEa7GA0bT714xOYsUg is the Session ID and identifies the current user session, you can remove it from the URL by storing it in a browser cookie instead if you wish (warning: this will break your app if the browser is configured refuses cookies – so check first):

// In your Session constructor
setStoresIDsInCookies(true);
setStoresIDsInURLs(false);

To use DirectActions we need to change the Application’s defaultRequestHandler to the directActionRequestHandler. This code in your Application constructor will do the job:

// In your Application constructor
String directActionRequestHandlerKey = 
	this.directActionRequestHandlerKey();
WORequestHandler directActionRequestHandler = 
	this.requestHandlerForKey(directActionRequestHandlerKey);
this.setDefaultRequestHandler(directActionRequestHandler);

2. Create the action in the DirectAction class

Your custom code can go in either your own java class, or in the default DirectAction.java created with each project. To keep things simple we will extend the DirectAction.java class.

If you take a look at the DirectAction.java class of a new project, you will see that it has one action: defaultAction that looks like this:

public WOActionResults defaultAction() {
	return pageWithName("Main");
}

This action is pretty straight forward. It follows the naming convention for DirectActions (namely: actionNameAction) and it returns the WOComponent with the name "Main". An application that has a directActionResponseHandler as it’s defaultResponseHandler will process any request that doesn’t specify an action (and/or class) by the defaultAction in the DirectAction class. You can see this for yourself by changing the defaultAction to this:

public WOActionResults defaultAction() {
	System.out.println("Using the default action");
	return pageWithName("Main");
}

If you build and run your application and you should see Using the default action in the console when the Main page loads.

That’s all very exciting, but what we really want to do is create our own custom action that gets triggered by a specific URL. So lets create our own action. In the DirectAction.java class add the following:

public WOActionResults helloWorldAction() {
	WOComponent page = pageWithName("Main");
	page.takeValueForKey("Hello World", "myDisplayString");
	return page;
}

To make this work we need to modify our Main WOComponent. Add a String called myDisplayString to Main.java (make sure to give it accessor methods) and in the Main.wo add a WOString component and bind its value to myDisplayString.

Build and run the application. It should open and empty browser window. Use this URL to trigger your new helloWorldAction:

http://localhost:55555/cgi-bin/WebObjects/Test.woa/wa/helloWorld

Replace the 55555 in the URL above with the actual port for your application instance – also notice that we’ve replaced the /wo/ with /wa/ indicating that this is a DirectAction URL. When the page reloads you should see this:

Result of HelloWorld DirectAction example

So, by using DirectActions we can easily call arbitrary methods by specifying them in our URL.

3. Create a link or redirect to access the new directAction

To access our DirectActions we could hard code the URL as an href in a link, or ask our users to manually enter them – like we just did, but neither of those are really practical. Thankfully many of the WO Dynamic Elements – such as the WOHyperlink we are about to use – have built in support for DirectActions.

Add a WOHyperLink to your Main WOComponent and set its bindings so they look like this:

HelloWorld Direct Action Exampl WOHyperLink bindings

Build and run your application, when the Main page loads, it should have your new hyperlink. Clicking on it should reload the page with the helloWorld URL.

This little tutorial gives a basic overview of how DirectActions are used. But there is a lot more that we can do. Some of the things we will still need to tackle are:

  • Passing parameters to our action
  • Accessing a database with our action
  • Invoking or using a Session with our action

I’ll try to get to some of that next time.

When bad RAM happens to good PowerBooks…

I’ve just spent a couple of very frustrating days rebuilding my PowerBook. It started with a constantly crashing Finder:

  • open Finder window
  • crash
  • write crash log
  • launch
  • crash
  • write crash log
  • launch
  • crash

Once I’d thought I’d resolved that (be restoring from my backup) the iChat daemon started quitting. I re-installed iChat and … the Finder started crashing again. So, burn some Panther install CD’s – Archive and Install (and all of the upgrades that entails – Xcode 1.2, WebObjects 5.2, Java 1.4.2, WebObjects 5.2.2, WebObjects 5.2.3…). Tried to install MySQL, and the installer quits. OK, just going to restart and … the Finders starts crashing again. Deep breath – AARGH!

I finally pulled a third party 512MB stick of RAM – which had successfully passed memtest – and sanity is once again restored. Between my TiBook, and my 17inch AlBook that makes 4 – FOUR! 512MB dimms I’ve had fail.

I know everyone offers lifetime warranties but this just sucks. RAM – can’t live with it, can’t shoot it.

WordPress

Yup! There’s a new blog engine in town boys!

I was getting tired of cleaning up comment spam (aren’t we all) and was looking around for a replacement writeback plugin for Blosoxom that had spam blocking. Well one thing led to another (as the internet is want to do) and I ended up reading a bunch of really nice things about WordPress.

So, I took the plunge and after a little futzing with the templates and css I’m back in business. The comments didn’t make it through (I think they might have fallen down a crevasse), but well, most of them were spam anyway :-). (Q: Should punctuation go before or after a smiley?) If you’d posted any, and were really attached to them, let me know. I’ll go all St. Bernard on them and haul them up.

So without further ado, I’d like to introduce the new reBeLog, now with added blogging power, searching, a calendar, and a fresh new minty taste!