New Phone

e815.gif

I’ve wanted a Bluetooth enabled cell phone for a long time. I tried switching to Rogers and a Sony T68i a couple of years ago but their network has this annoying habit of dying 3 blocks from my home (not good when your cell is your primary phone) so I had to switch back to Bell Mobility.

Unfortunately Bell has the crappiest selection of phones on the planet. It’s taken forever for them to get a Bluetooth phone (that’s not a PDA, or limited to headset connectivity) in their lineup. They’ve finally done so with the Motorola E815.

I picked one up at a Bell Mobility store last night. Though the E815 is not the slickest phone around (I’d prefer a RAZR) it’s that whole "beggars not being choosers" thing.

When I got home I paired it with my laptop and that went without a hitch. I was able to get iSync to successfully sync my Calendar but it failed to sync my Contacts with a "The connection was lost while talking to the device. Device "Motorola Phone" synchronization failed" error.

It turns out that this is a common problem (as noted here, here, and here). Apparently there is a setting in the phone that conflicts with iSync and prevents it from succesfully syncing your contacts. The recommended solution is to perform a seem edit on the phone to disable the offending feature. To do so requires a Windows XP machine, software, drivers, an expensive USB cable, and a bunch of headache.

The alternate, I discovered, is to use OnMadeSoft’s OnSync. OnSync is a $US12 piece of shareware that provides and alternate means of syncing your AddressBook with your phone. I downloaded the demo and tested it, and it works great. OnSync also gives a great deal of control over the format of the phone contacts entries which is nice.

WebObjects Beginners project posted

I’ve posted an Xcode project to accompany my previous rant. The zip archive is available here.

A few notes:

  • This is a WebObjects 5.3/Xcode 2.2 project.
  • There is a ReadMe included, it outlines some of the project details.
  • I tweaked the code a little – read their comments.
  • The project demonstrates using a common parent for your components. Which is easy to do and useful for minimizing redundant code. (Though, it does seem to stop WOBuilder from seeing some page attributes :-()
  • The components all render using CSS.

WebObjects – Flawed beginner info

An EO out of an EC is like a fish out of water

The books WebObjects beginners usually read when they are starting out are the Apple Web Applications tutorial and Joshua Marker’s WebObjects 5 for Mac OS X: Visual QuickPro Guide.

Both are very good introductions. They cover a great deal of territory (and there is a great deal of territory to cover when you’re beginning).

However, they both share a fatal flaw. Both endorse the practice of inserting EnterpriseObjects (EOs) into their EOEditingContexts (ECs) late.

By late I mean: NOT RIGHT AWAY!

The EOF Commandments are very clear on this. Many – myself included – have the nasty experiences to back this up. It is never a good idea to defer adding a newly created EO into an EC. In fact, Chuck Hill is quoted as saying: “I’ll opine that an EO not in an EC is in fact not an EO just a plain old Object.”

That’s a lot to give up. No change notification, no EOGobalID, no undo, no guarantee that awakeFromInsertion is not going to hose any changes you’ve made…

OK, to be fair, the examples in these documents work. It is possible to set some values in an EO prior to inserting it into an EC and have it work.

Maybe.

Some of the time.

But don’t count on it.

And that’s the problem, there are no rules to dictate when it is safe and when it’s not. So, if you are looking for best practices: Just don’t do it – ever.

Learn the correct way first.

I find the Apple Web Applications tutorial is particularly bad in this instance. Not only do they advise inserting the EO into it’s EC late, but they develop a UI around the practice in such a way that if you try to reuse your learning in your own projects (by creating a similar UI) you will be trapped.

Take a look at the UI their Authors tutorial uses:

web_app.gif

Now, I’m not going to spend a lot of time on how confusing this is. I’ve got to assume this is meant just as a learning example, but jeez-louise they could have done it right without any more effort. Honestly, can you tell what the Update, Add, and Save buttons are suppose to do? I can’t.

Anyway, lets look at some of the code underneath this thing:

public Main(WOContext context) { 
    super(context); 
    // Build the fetch specification. 
    fetchSpec = new EOFetchSpecification("Author", null, null); 
    // Get the editing context. 
    editingContext = session().defaultEditingContext(); 
    // Fetch authors. 
    authorList = new NSMutableArray(
        editingContext.objectsWithFetchSpecification(fetchSpec)); 
    // Create an Author object (where form data is stored). 
    author = new Author(); 
}

OK, so this is the component constructor. It fetches the array of authors from using a fetchSpec – I can handle that. Then it creates an empty Author without inserting it into an EC. Bad, bad, bad.

public WOComponent addAuthor() { 
    // Add the author only when it isn’t in the list. 
    if (!authorList.containsObject(author)) { 
        // Add the author to the list. 
        authorList.addObject(author); 
        // Insert author into editing context. 
        editingContext.insertObject(author); 
        // Create a new author. 
        author = new Author(); 
    } 
    return null; 
}

Oh, look, there it is again. Let me check… yup still bad.

public WOComponent updateAuthor() { 
    // Create an Author object. 
    author = new Author(); 
    return null; 
}

And yet again. Umm… nope, still bad.

I can kinda see why they’re doing this. The author needed an object to bind to the form that wouldn’t get saved to the DB when the user clicked save unless explicitly added to the list first. Instead of dealing with the complexity of multiple ECs or using NSMutableDictionaries as proxy objects he did this. And yes, it works in this instance, but that doesn’t stop it from being a bad practice and furthermore it teaches inexperienced developers a bad lesson.

But really, I think the root of the problem is with the design of the UI. If we separate the list and edit functions into two user modes (Yes I know, very Web 1.0, but this is a beginners tutorial!) the need that led to this problem goes away.

Here let me show you.

First some mockups of the pages. AuthorList first:

authors_list.gif

Then AuthorEdit:

author_details.gif

Now the relevent code for the AuthorList (I’m assuming that the list is populated and the WORepetition has all it needs):

public WOComponent addAuthor() { 
    // Create an Author object (properly!). 
    Author author = (Author)EOUtilities.createAndInsertInstance(
        ec(), "Author"); 
    // Where are we going? (Planet 10!)
    AuthorEdit nextPage = (AuthorEdit)pageWithName("AuthorEdit");
    // Pass in the new author
    nextPage.setAuthor(author);
    // And go there
    return nextPage; 
}
 
public WOComponent editAuthor() { 
    // Where are we going?
    AuthorEdit nextPage = (AuthorEdit)pageWithName("AuthorEdit");
    // Pass in the selected author
    nextPage.setAuthor(authorItem);
    return nextPage; 
}
 
public WOComponent deleteAuthor() { 
    // Delete the selected author
    ec().deleteObject(authorItem);
    ec().saveChanges();
    return null; 
    // I prefer to return this.context().page();
    // 'cause it always works, even with complex 
    // embedded components
}
 
// We're gonna need this a lot. 
// Might as well make it easy on ourselves
public EOEditingContext ec() {  
    return session().defaultEditingContext(); 
}

Finaly the relevent code for the AuthorEdit:

public WOComponent backPage;
 
public AuthorEdit(WOContext context) {
    super(context);
    // This be magic!
    // Because the component constructor is called
    // from (Blah)pageWithName("Blah")
    // backPage gets a reference to the calling component
    // Very useful. Don't remember who I learned
    // that from, but thank you!
    backPage = this.context().page();
}
 
public WOComponent saveChanges() { 
    ec().saveChanges();
    return backPage; 
}
 
public WOComponent revert() { 
    ec().revert();
    return backPage; 
}
 
// We're gonna need this a lot. 
// Might as well make it easy on ourselves
public EOEditingContext ec() {  
    return session().defaultEditingContext(); 
}

To my thinking this code is no extra work. It fulfills the requirements of the EOF Commandments and it makes the UI clearer to boot. Most importantly it gives a novice WebObjects developer a strong foundation on which to build. This pattern can be repeated over and over again in their own projects without any risk of invoking the wrath of EOF.

When I get a chance I’ll build this as an Xcode project and post it.

John Simonton – RIP 2005

I am saddened to learn from the Make blog that John Simonton, the founder of PAiA, and probably one of my all-time electronics hobbyist heros, died of cancer sometime last week.

Although I was never able to afford any of his kits as a kid, a friend of mine built the Gnome, and I drooled over the PAiA catalog endlessly. I cannot understate the impact his kits and articles in Popular Electronics had on my electronics career.

create digital music has a good post with plenty of links to commentary and forums.

PAiA has made a resurgence in recent years, I hope his passing will not effect the availability of their kits.

Building a PVR

Inspired by Make, I’ve decided to get my hands dirty again by building a PVR (personal video recorder) for fun. Tivo’s aren’t available in Canada and any of the commercial units are just a tad too "closed" for my liking.

I’m going with MythTV as the core application running on Linux (there is a decent overview of MythTV here). The distro I’ve chosen is the very slick KnoppMyth. It looks like it is definitely the quickest way to get to the end result without having to spend a lot of time hacking Linux (which I have done in the past and would prefer not to have to do again).

Gaining access to Canadian TV listings was a little bit of a concern initially but it looks like MythTV works with a feed from Zap2it Labs.

I downloaded the latest version of KnoppMyth a couple of days ago and the Hauppauge PVR-350 and PVR-500 cards arrived this morning.

The PC I chose is an off-lease Dell GXF240 (P4 1.7 – small desktop). I liked the form-factor, but the card cage may be a little small for the cards (at least the PVR-500). I’m hoping I can get them to fit, but think I’m going to have to do some Dremel work. It was only a couple of hundred bucks, so I don’t mind experimenting.

The 300GB hard drive, DVD burner, and PC should be arriving shortly. Then it’ll be time to get to work.