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.

Comments

4 Comments so far. Comments are closed.
  1. Hi David, just getting around to implementing a few direct actions in my app. I did not need to do step 1 (setDefaultRequestHandler) at all to get DAs to work? That may be because my Application class subclasses ERXApplication from Project Wonder.

  2. david,

    I wasn’t clear on this. You do not need to set the defaultResquestHandler to get your Apps to see DAs. You only need to set it if the default request handler should be for direct actions.

    In other words, with the defaultRequestHandler set to “wa” (directAction) a call to your App that contains no request type in its URL (ie: the root URL for your app) will be handled by the defaultAction in your DirectAction class.

    And yes, you are correct. I looked at the source and ERXApplication sets the defaultRequestHandler to the directActionRequestHandler in its constructor.

  3. Laszlo,

    Hello.

    Some time ago I implemmented a similar mechanism, using a special form variables(authentification token) which is basically an encrypted string created from an combination of the random characters+password+timestamp.

    At the first page acccess The user is requested to enter the password, the servercode will authentificate the password and will create an unique access token then this access token will be used for further authentification
    At webpage access
    the servercode will decrypt the accesstoken and will verify password and timestamp. If ok the it will process the request. Otherwise will redirect to the login page.

    As the user closes the webpages the token is lost and it will be required again to authentificate

    As the token is expired due to the timestamp verification
    the user is requested to authentificate again.

    I call this authentification(security) modell as the ping-pong modell.

  4. Yolia,

    hello,I’m a beginner on WebObject.And I’m wondering if there is any convinient way to test the WO applications in IDE like Eclipse.I’ve tried to use WOUnitTest but the complex configurations really confuse me.Anyone who has a good idea please contact me.
    e_mail:moc.liamgnull@1588gnixnixuohz
    Thank you!