oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Using WebObjects: More Practical Tips and Tricks

by Josh Paul

Editor's note: This is the third installment in our ongoing series covering WebObjects (WO). In the first article, "An Introduction to WebObjects," Josh Paul showed you how WO consists of a set of frameworks that allow you to write cross-platform, server-distributed applications. Then, in the second tutorial, "Using WebObjects "Direct to Web" Technology," Josh shows you how to create a full-blown web application in just a few simple steps. This week, he picks up where he left off and shows you more tips and techniques for setting up Direct to Web (D2W) applications.

Special Price: Reduced $49,391

Hey, hey! Welcome back. If you're just joining us, we're working with Apple's WebObjects software. That'd be WO for short, which is what you should be saying at some point, if you haven't already. For reference, I located Steve Jobs' WWDC announcement on the $49,301 price drop. That's right, WO once was affordable only for large enterprise operations, such as the Apple Store. But now it's within the reach of anyone who wants to install and implement it.

In the last article, you stepped through a simple Direct to Web application. I'd like to continue on that path, and since I'm writing this before you read it, you have no choice. So I'm going to start walking ...

Login Page

Yup, I'm back to the Login Page thing. Since I left you hanging out to dry in the last article, I figured I'd integrate a little code. Open your old project, or create a new one, following the steps from the previous article. In the next few steps you are going to implement a better login process.

Locate your file within your project. You're going to add a method to see if the client has entered a valid username and password. It'll be painless, I promise.


By using the exceptionally useful EnterpriseObjects Frameworks (EOF), you'll be able to compare the client-provided information with the information in your database. You'll be using the specific classes of EOUtilities and EOEditingContext. The EOEditingContext, to quote Apple, " manages a graph of enterprise objects in an application; this object graph represents an internally consistent view of one or more external stores (most often a database)." For now, you can consider it a playground for your data, where you can invite objects in to play and to be played with.

Since the EO-based classes are not always expected in a WO component, you'll need to import them.

	import com.webobjects.eocontrol.*;
	import com.webobjects.eoaccess.EOUtilities;
	import com.webobjects.eoaccess.EOObjectNotAvailableException;

Client Feedback

In order to provide usable feedback to the client, you should also add a String variable. I called mine feedback.

	public String feedback;

Do the Deed

You can then add your new method.

public EOEnterpriseObject userForCredentials() {
     EOEnterpriseObject aUser;
  // the magical EOEditingContext..
     EOEditingContext ec;
  // use with EOUtilities to query the database
     NSDictionary bindings;
  // used to determine which columns to query
     Object[] keys = {"username", "password"};
     Object[] values = {username, password}; // used to query the database rows

     if ((username == null) || (username.length() == 0) ||
     (password == null) || (password.length() == 0)) {
         feedback = "You must provide both a username and a password.";
         return null;
     aUser = null;
     ec = session().defaultEditingContext();
     bindings = new NSDictionary(values, keys);

     try {
         aUser = EOUtilities.objectMatchingValues(ec, "User", bindings);
     catch (EOUtilities.MoreThanOneException e1) {
         System.err.println("ERROR:  More than one User with username '" + username +
         "' and password '" + password + "'.");
         feedback = "Please contact a System Administrator.";
     catch (EOObjectNotAvailableException e2) {
         feedback = "Your Login information was incorrect.";
     return aUser;
Obviously, unless you call your new method somehow, it's useless. Locate your defaultPage method and make some magic.

  public WOComponent defaultPage() {
      if (isAssistantCheckboxVisible()) {
      if (userForCredentials() != null)
    return D2W.factory().defaultPage(session());
      return null;

The Page

If you're curious how the heck defaultPage gets called, open your Main.wo file. (If you didn't just open the Main.wo file, please do so now.) The WebObjects Builder application should launch and present the component to you.

Within the Login Form, there is a WOActiveImage displaying the Login button. If you select the Login button, you'll notice in the Inspector window a binding called action, which is bound to your defaultPage method. When a client clicks the button, the defaultPage method is called. Therefore, you can safely assume your userForCredentials method will now be called as well.

While you have the Main.wo file open, you should add a WOString and bind it to your feedback variable. This will allow you to provide your clients with information, such as "Your login information was incorrect." When you've added the WOString and bound it, your Login Form should look something like this:

If you'd like, you can change the format of your feedback. I will usually either italicize or bold, as well as add some color (like red).

You should now be able to build and run your application. Should you run into problems, or if you're curious what EOF is doing, you can enable some simple logging by adding the following to your Properties file: EOAdaptorDebugEnabled=true. Upon doing so and running your application, you'll be able to see what SQL is being used, in addition to what JDBC driver is being used.

Okay. Now on to some more interesting topics.

Brew Some Java

From within your project, open your EOModel file. It will most likely be listed under the Resources Group. Opening the EOModel should launch the EOModeler application.

In your Toolbar, you will find a button to generate Java class files for your Entities. If you've been following along with the past articles, you should only have one Entity named User. It should be configured similar to this:

If you wanted to present a User's first and last name, there are a number of ways you could accomplish it. You could create a calculated column in your database, use WebObjects Builder to create a component with two WOStrings, use EOModeler's derived attribute ability, or choose any number of other options. In the next few paragraphs, you're going to create a User class and add a convenience method for nameFull.

Let EOModeler Do Some Work

Select your User Entity and click the Generate Java button located in the Toolbar. You will (most likely) be presented with an Alert informing you about your User class needing a class name. You can safely click the default button, Use User. However, do not save the file yet!

When your are presented with the Save Dialog box, rename your file something like "" or "," as you will be implementing the Generation Gap pattern. I chose Following this pattern may take a few extra steps, but has been well worth the effort, in my experience. Upon saving, you will be asked if you want to insert the file in your project. You do.

Back to the Project

When you return to using ProjectBuilder/Xcode, you'll discover that your file has been placed into your project, most likely under the Classes group. Select the file and edit it to remove the wrench you've thrown into the system by matching the class name with the file name.

public class _User extends EOGenericRecord {

    public _User() {

Implement the Gap

Next, you should create a new file. When presented with the Assistant, select the WebObjects Java class option. You should name your new class "" and select the Application Server as the Target.

In order to implement the pattern, you'll simply inherit from _User.

import com.webobjects.eocontrol.*;
import java.math.BigDecimal;
import java.util.*;

public class User extends _User {
    public User() {

Feel free to browse the code EOModeler generated for you. You should notice a very simple, yet exceptionally powerful, pattern. Specifically, the storedValueForKey and takeStoredValueForKey methods. Sure enough: Key-Value Coding (KVC). I am not going to dive into KVC here; sorry to dash your hopes, I just wanted to point it out.

From this point forward, whenever you use EOModeler to generate Java for your User Entity, you can safely assume any custom logic you've implemented won't be overwritten. However, you will have to rename the generated file and "remove the wrench" every time.

What's Your Name?

So how do we determine a User's full name? Well, personally I'm partial to a First Last order, so that's how I implemented my solution. Feel free to come up with your own.

    public String nameFull() {
	return nameFirst() + " " + nameLast();

Now what?

Pages: 1, 2

Next Pagearrow