Suppressing the wosid in a DirectAction

Two common means of generating DirectAction URLs in WebObjects are by using the directActionName bindings available in WOHyperLink (and it’s brethren) and by using the WOContext method: directActionURLForActionNamed(String name, NSDictionary).

Kol. Panic offered a tip on suppressing the Session ID (wosid) in DirectAction urls generated from a WOHyperLink in the comments of this post.

It turns out that there is a similar method if you are generating the URL in your code from a WOContext:

  public String loginUrl() {
    NSDictionary dict = new NSDictionary(
        new Object[] {Boolean.FALSE},
        new String[] {"wosid"});
    return context().directActionURLForActionNamed("login", dict);
  }

Using WebObjects DirectActions – pt. 5

Calling a DirectAction with values from a WORedirect

WORedirect is useful when you need a regular Component action (i.e. non DA) to lead somewhere other than another WOComponent (i.e. If you need to perform some cleanup and return a company homepage when a logout link is clicked).

Luckily for us, a WORedirect can also easily allows us to redirect to a DirectAction, as the following code demonstrates:

String searchString; 		//assume exists
String category;		//assume exists
String pageOfResults = "0"
 
public WORedirect performSearch() {
    NSMutableDictionary dict = new NSMutableDictionary();
    dict.takeValueForKey(searchString, "searchString");
    dict.takeValueForKey(category, "category");
    dict.takeValueForKey(pageOfResults, "page");
    String url = context().directActionURLForActionNamed(
                 "search", dict ); 
    WORedirect redirect = new WORedirect(context());
    redirect.setUrl(url);
    return redirect;
}

This hypothetical action is bound to a WOSubmitButton in a WOForm on a WOComponant. It is important to note that its return type is WORedirect instead of the usual WOComponent.

It function is pretty clear, it creates a new NSMutableDictionary and populates it with the values and keys that we need to append to our DirectAction URL. The single line of code does most of the heavy lifting:

String url = context().directActionURLForActionNamed( 
                  "search", dict );

It creates the DirectAction url (in this case for the searchAction) for us and append the values from our NSMutableDictionary. Finally we set the url for the WORedirect and return it.

The directActionURLForActionNamed comes from WOContext and it’s API can be found here.

Well, I think this will be the last DirecAction specific post. I’ve covered pretty much everything I set out to, so I think I’ll take a break an look for a different topic to examine. If anyone has any suggestions, let me know.

Using WebObjects DirectActions – pt. 4

Calling a DirectAction with values from a WOHyperlink

In the last segment we looked at using a form to submit values into a DirectAction, this time we’ll look at binding values to a WOHyperlink.

According to Apple’s Dynamic Elements Reference, the bindings for a WOHyperlink are:

action, href, pageName, directActionName, actionClass, fragmentIdentifier, string, target, disabled, secure, queryDictionary

The bindings in bold are the ones we are interested in:

  1. directActionName – The name of the action minus "Action" (i.e. "helloWorld").
  2. actionClass – The name of the class containing the action (in our examples we’ve been using the default: "DirectAction").
  3. queryDictionary – A dictionary of key/value pairs to append to the URL.

Clear? OK, it’s time to get started. As always, we are going to extend the previous examples, so fire up your IDE and we’ll begin.

First, add a new WOHyperlink to the Main component (somewhere outside the form). Bind its directActionName to "hyper" and its actionClass to "DirectAction" (don’t forget the " "s).

Next, create the hyperAction that’s bound to our WOHyperlink. Add the following to the DirectAction class:

public WOActionResults hyperAction() {
    WOComponent page = pageWithName("Main");
    System.out.println("Hyperlink values: " + 
                       this.request().formValues());
    return page;
}

This is not complex code it just exposes what is happening when this action is called.

Build and run the application. When the Main page loads, click on the new hyperlink. The page should reload and you should see this in the console:

Hyperlink values: {}

Now, lets attach a value to the WOHyperlink. In WebObjects Builder select the WOHyperlink and invoke the inspector (cmd+1). Add a new binding (use the small [+] button in the upper right corner of the Inspector window, and select Add binding). Give it a binding of ?name and a value of "david". The Main.wod snippet for the WOHyperlink should look something like this:

Hyperlink1: WOHyperlink {
    ?name = "david";
    actionClass = "DirectAction";
    directActionName = "hyper";
}

Save the component and reload the page, click on the link again and you should see this in the console:

Hyperlink values: {name = ("david"); }

You can add additional key-value pairs to the WOHyperlink by repeating the Add binding step above or by directly editing the Main.wod. For instance, the following WOHyperlink .wod snippet:

Hyperlink1: WOHyperlink {
    ?age = "10";
    ?name = "david";
    actionClass = "DirectAction";
    directActionName = "hyper";
}

Results in this output:

Hyperlink values: {name = ("david"); age = ("10"); }

Alternately, we can add the values to the WOHyperlink all at once in by using the queryDictionary. Open the Main.java file and add the following method:

public NSDictionary hyperDictionary() {
    NSMutableDictionary dict = new NSMutableDictionary();
    dict.takeValueForKey("david", "name");
    dict.takeValueForKey("10", "age");
    return dict;
}

Delete the two bindings you added to the WOHyperlink in the last step, and bind the hyperDictionary method to the queryDictionary binding. The section of Main.wod for the WOHyperlink should look like this:

Hyperlink1: WOHyperlink {
    actionClass = "DirectAction";
    directActionName = "hyper";
    queryDictionary = hyperDictionary;
}

OK, were almost done, build and run the application once again. Click on the link and you should see the same entry in the console as above:

Hyperlink values: {name = ("david"); age = ("10"); }

At this point you should have pretty much everything you need to play with DirectActions. We’ve looked at how to configure your application, trigger an action, decipher a DirectAction URL, grab values from a form, pass values with your hyperlinks, and get the use of a session if you need one. Next time we’ll look at combining Component actions and DirectActions using a WORedirect.

Using WebObjects DirectActions – pt. 3

Calling a DirectAction with values from a form

This is the 3rd in a series, part 1 is here and part 2 is here. We’ve looked at the composition of a DirectAction URL, and how to retrive passed values. This time we’re going to look at how to call a DA with values from a form.

We are going to extend the examples we used last time so fire up your IDE (Eclipse I hope) and lets get started.

First we need to modify our Main component, edit the Main.html so it looks like this:

<html>
<head>
    <meta name="generator" content="WOLips Core">
    <title>New</title>
</head>
<body bgcolor=#FFFFFF>
    <webobject name=Form1>
        Usrename: <input type=text name=username>
        <br />
        Password: <input type=password name=password>
        <br />
        <input type=submit>
    </webobject>
</body>
</html>

Change the Main.wod so it looks like this:

Form1: WOForm {
    directActionName = "helloWorld";
    actionClass = "DirectAction";
}

Save and run the application. After the Main page loads, enter values in the two form fields and hit the submit button. You should see something like this in the console:

Form Values: {password = ("pass"); username = ("dave"); }

A couple of things to note: The only WO component on this page is the WOForm, it is bound to the helloWorld directActionName, and the DirectAction actionClass. All of the other form elements are just plain HTML.

You’ll also notice that the text field values are not retained – after you submit the form the text fields are blank. Lets look at how we might fix that:

  1. In WebObjectsBuilder convert the text fields to WOTextFields by clicking on the Make Dynamic button in their Inspector windows.
  2. Add a username and password variable of type String to your Main.java
  3. Bind the username variable to the username WOTextField, and the password variable to the password WOTextField
  4. Modify the helloWorldAction in the DirectActionclass so it looks like this:
public WOActionResults helloWorldAction() {
    NSDictionary dict = this.request().formValues();
    System.out.println("DA values: " + dict);
    WOComponent page = pageWithName("Main");
    String username =
        (String)this.request().formValueForKey("username");
    String password = 
        (String)this.request().formValueForKey("password");
    page.takeValueForKey(username, "username");
    page.takeValueForKey(password , "password");
    return page;
}

Now when we build, run, and submit the form, the form values should be retained. This little example shows how to grab the values from a form, and pass them to a page.

Before we go, lets try a little experiment, add a WOString to your Main component and bind it to session.sessionID (WOBuilder may complain that the This binding value is not defined – just click the Don’t Add button and move on).

When you are done, reload the Main page and submit the form a couple of times. What happens? If everything is working you should see something like the following appended to the URL:

wosid=e3ef6ofP1badQRlQtJdIew

Note: This will only work if you haven’t set setStoresIDsInCookies(true); and setStoresIDsInURLs(false); in your Session constructor.

wosid stands for WO Session ID and this demonstrates the mechanism that DirectActions use to track a Session. So, although you don’t need to trigger a Session from your DirectActions (you are free to manage state yourself) you can get one just by asking for it. This can be very helpful as we will see later.

Using WebObjects DirectActions – pt. 2

At the conclusion of part one of this mini-series we had successfully configured a WebObjects application to accept DirectActions, had written a simple DirectAction method, and created a WOHyperlink to trigger it. Now it’s time to look at some of the common additional requirements you might encounter. As I mentioned last time they are:

  1. Passing parameters to our action
  2. Accessing a database with our action
  3. Invoking or using a Session with our action

Each of these will take a little work to get through, so I’m going to tackle them in several separate posts. Today we will look at passing parameters to our actions. We are going to extend the examples we used last time so fire up your IDE (Eclipse I hope) and lets get started.

Passing parameters to a DirectAction

Being able to trigger an action based on the URL is fun and all, but often we will want to do more. More? what could we possibly want that is more? Well submitting a form to a direct action URL might be nice, or passing a value to the next page for display or to modify its behaviour would be cool too.

To get this to work we have a number of issues to cover:

  1. Handling parameters in our action
  2. Passing a single parameter to our action
  3. Passing multiple parameters to our action

1. Handling parameters in our action

The first thing we are going to tackle is to get our DirectAction to handle parameters attached to our URL. Our DirectAction class has access to a WORequest object through the request() method. The WORequest contains a bunch of information about the current request, including any form values – which is how we will be passing values into our DA’s. These can be accessed through the following methods:

  • formValues()
  • formValuesForKey(String aKey)
  • formValueForKey(String aKey)

I suggest you take a look at the documentation for WORequest for more information but here is a brief summary of what they do:

  • formValues – returns an NSDictionary with all of the form values. The names are represented as the NSDictionary keys each with an NSArray containing its value(s).
  • formValuesForKey – returns an NSArray of the form value(s) that match a given name (key).
  • formValueForKey – returns an Object that is one of the value(s) that matches a given name (key).

Note: formValues() and formValuesForKey(String aKey) will return NSArray’s of values. This is because multiple form values can be associated with any given name (key). The NSArrays returned are sorted in no particular order – be warned.

Similarly, the Object returned by formValueForKey(String aKey) will be arbitrarily chosen from the NSArray of returned values – only use this method if you can be assured that there is only one value for each key (or don’t care which value you receive).

Lets extend the helloWorld example from last time to see how this works. Open your project and modify the helloWorld method in the DirectAction.class so it looks like this:

public WOActionResults helloWorldAction() {
	// Using formValues()
	NSDictionary dict = this.request().formValues();
	System.out.println("Form Values for request: " + dict);
	WOComponent page = pageWithName("Main");
	page.takeValueForKey("Hello World", "myDisplayString");
	return page;
}

Granted, this is not awe inspiring code, but it will help us to explore the next section.

2. Passing a single parameter to our action

Build the application and run it. If you are working on the project we built last time your web browser should open a new page with a single link. Click on the link to get to the Hello World page. You should see something like this in your console:

Form Values for request: {}

Which is understandable, as we haven’t supplied any values. Let’s change that. Append the following to the current URL "?=thisIsATest" so it looks like this:

http://STD_WEBO_URL/Test.woa/wa/helloWorld?=thisIsATest

The STD_WEBO_URL will look something like: "localhost:55555/cgi-bin/WebObjects/" it’s abbreviated for brevity… and to make it shorter too.

Hit return to submit the modified URL and you should see this in the console:

Form Values for request: { = ("thisIsATest"); }

Because we did not append a key-value pair to the URL, our resulting dictionary is missing the key. This is fine if we don’t need to uniquely identify our values. If we are just passing one value, we can retrieve it using formValueForKey("").

3. Passing multiple parameters to our action

Having one value is rare, in my experience, so lets look at identifying our value with a key. Appending a key to the URL is easy, the resulting URL will look like this:

http://STD_WEBO_URL/Test.woa/wa/helloWorld?aKey=thisIsATest

Submitting this URL to our application should give us this in the console:

Form Values for request: {aKey = ("thisIsATest"); }

We can explicitly retrieve this value using formValueForKey("aKey").

Finally, lets look at sending multiple key-value pairs. Simply append additional pairs (key1=value1) separated by an & symbol:

http://STD_WEBO_URL/Test.woa/wa/helloWorld?key1=value1&key2=value2

This URL should give us the following in the console:

Form Values for request: {key1 = ("value1"); key2 = ("value2"); }

Again, using formValueForKey("keyN") will allow us to get each of these values from the request.

You should now have a pretty good idea of how a simple DirectAction works, and how values are encoded into the URL. However, it would be nice if we could get the URLs without having to enter them by hand. So, next time we’ll look at generating the DirectAction URLs by using the bindings on WebObjects WODynamicElements.