Leopard: WebObjects Notes

Leopard is out and with it comes a slew of WebObjects changes. The release of WO 5.4, the official deprecation of the tool chain (which we’ve known was coming for some time), Apache 2 support, etc.

There’ve been some posts to the webobjects-dev list which I consider required reading. I don’t know if this stuff has made it into the wiki yet, so here are some links:

So, lots going on, and it all looks good IMHO. Should be a good year for WO.

Notes:

  • The permissions on /Library/WebObjects/Configuration needed to be fixed otherwise wotaskd and javamonitor barf.
  • /System/Library/WebObjects/Executables/WOOpenURL seems to be missing. I copied it from the WO53 install and that works. Upate: It turns out that it’s not needed for WO54, it just uses the open command.

Just a few of my favorite things…

Project Wonder is chocked so full of WebObjects goodness that it is hard to envision developing a project without it. Here are three bits that I use all the time.

Autolocking EditingContexts

Step one: Learn WebObjects

Step two: Realize that using the session().defaultEditingContext() exclusively is bad.

Step three: Start using multiple EOEditingContexts.

Step four: Read, re-read, then read again the documentation on EC locking.

Step five: Encounter production deadlocks.

Step six: Cry.

Thankfully Project Wonder provides an amazing solution in the form of autolocking EditingContexts. Enabling them is simple. Set some properties for your project:

er.extensions.ERXApplication.useEditingContextUnlocker=true
er.extensions.ERXEC.defaultAutomaticLockUnlock=true
er.extensions.ERXEC.useSharedEditingContext=false
er.extensions.ERXEC.defaultCoalesceAutoLocks=true

There is an email from Mike Schrag with some juicy details here.

Change your code so that you never call new EOEditingContext(); instead use the ERXEC.newEditingContext() factory method.

ERXThreadStorage

Problem: You need access to an object in your session from an EO. Maybe you want to set a “createdBy” value to the current user in awakeFromInsertion

Adding a reference to the Session in your EOs would be bad so what are you going to do?

Solution: Use ERXThreadStorage to store a reference to the current user and access that from your EO.

In your Session.java:

public User currentUser; // assume exists

public void awake() {
    super.awake();
    ERXThreadStorage.takeValueForKey(currentUser, "currentUser");
}

In your EO.java:

public void awakeFromInsertion(EOEditingContext ec) {
    super.awakeFromInsertion(ec);
    User user = ERXThreadStorage.valueForKey("currentUser"));
    if (user != null) {
        setCreatedBy(user.userName);
    }
}

ERXGenericRecord

ERXGenericRecord is another Project Wonder class that is full of yumminess. Please read the API docs for the full details, but here are a few of my favorites:

willUpdate(); // called after saveChanges() but before validation
              // so it is safe to make changes. See the rest of
              // will* and did* methods for more

primaryKey(); // returns the primary key (null if the EO hasn't
              // been saved yet)

primaryKeyInTransaction(); // returns the primary key as above,
              // but if the EO hasn't beens saved yet, it'll
              // figure out what the pk should be, return it,
              // cache it, and use it later when the EO does get
              // saved. Very cool.

There is much, much more: ERXLocalizer, ERJavaMail, ERExcelLook… Dive into the docs and I’m sure you’ll find something usefull.

WOLips: New .woo editor

There are five files assosiated with a WebObjects component (.html, .wod, .woo, .api, and .java). In WOBuilder you could add and configure a WODisplayGroup in your component and it’s configuration would get stored in the .woo file.

The only way to edit the .woo file in WOLips’ component editor was to use a text editor…

Up until now that is. There is a new “Display Group” addition to the Component editor tabs:

display_group_tab.gif

Which reveals a Display Group manager window (similar to the API manager). Adding a Display Group gives you a nifty Details editor:

display_group_dialog.gif

I don’t use component configured WODisplayGroups much, but I know a lot of people do and this is a welcome addition.

WebObjects Deployment Notes

Deployment is a big hairy subject, and I don’t pretend to be an expert, but these are some notes of things that help me.

Some caveats: I only develop on Mac OS X Client with Eclipse+WOLips and install on Mac OS X Server, so these notes probably won’t make any sense for anyone else… sorry.

WARNING !AOOGA HORN SOUND! Not a tutorial, just a little list of tips, if you’ve got any tips of your own to add, leave a comment.

1. Use Project Wonder:

No justification, just do it.

2. Use split Properties:

Create multiple sets of Properties to minimize the amount of tweaking.

For example: Configure the one in your project (I dub thee “Project”) and the other in the root of your home directory (I’ll call you “Local”) with different values.

Set the Project properties to those that make sense for deployment, they will be overridden by the values in the Local properties which you configure for development.

Additionally, use this suggestion from Mike Schrag:

… and also Properties.yourusername. For instance, I have a Properties.mschrag that lets me set per-project-per-user properties overrides. Very handy.

If you need to access a property in your code use ERXProperties to do so, you’ll get the same property searching and caching behaviour that ERXConfigurationManager uses:

    String admin = ERXProperties.stringForKey("cs.project.adminname")

This means there are far fewer “little tweaks” to be made when deploying.

3. Build locally with embedded frameworks:

Modify your build.xml file to embed your frameworks:

   

This will make your application bundle a lot bigger, but it also means that you’ve completely eliminated any possibility of a version conflict between your new app deployment and any existing applications.

To build the app, just select something in the Eclipse Package Explorer view and ctrl+click -> WOLips Ant Tools -> Install… Select the apps to install and click “OK”.

The resulting app bundle(s) will be installed in /Library/WebObjects/Applications/

4. Copy the app to the server:

I usually zip my app bundle and copy it to the server via ssh where I have a script that extracts the archive into /Library/WebObjects/Applications/. Though rsync is looking more and more attractive… when I get the time. 🙂

5. Prep the virtual doc root:

I’m going to assume that most apps are deployed behind an Apache virtual domain configured to point at a subdirectory of the main doc root (i.e. /Library/WebServer/Documents/_site).

The app’s resource manager is going to expect to find web server resources in the following places:

Application:

 _site/
  WebObjects/
    AppName.woa/
      Contents/
        WebServerResources/

Frameworks:

 _site/
  WebObjects/
    Frameworks/
      FrameworkName.framework/
        WebServerResources/

Because we are embedding all of the frameworks, the framework’s WebServerResources will actually be in your app’s bundle. So, you could copy the WebServerResources directories from the apps and frameworks to those paths, or your could create sym-links, which is what I do.

I use a little script (prepWebObjectsDeploy.sh) to help me do that.

Because I use sym-links, this only has to be done the first time I install the app (unless subsequent releases add Frameworks to the build).

James Brook offers this tasty tip in the comments: Instead you can specify a property in the woapplication task of your ant build. If you set ‘frameworksBaseURL=”/WebObjects/MyApp.woa/Contents/ Frameworks/Library /Frameworks”’ the application will link to the resources in the embedded directories.

6. Test the installed app:

After copying the app, it’s usually a good idea to test the app via the command line to catch any weirdities:

   root# /Library/WebObjects/Applications/AppName.woa/AppName

7. Configure Monitor

I’m not going to talk about Monitor much, there are lots of other places that cover that in detail. The only thing I always make sure to do is to create a directory for the app’s logs (usually in /Library/Logs/WebObjects/AppName/) and set the Output path accordingly.

Profit!