Welcome to the Leopard WebObjects mess

October 30th, 2007

So, you thought Leopard and WebObjects 5.4 would bring some good news to WebObjects developers, right? Well… so did I.

I’m not even going to talk much about Leopard itself. It’s clearly an unfinished product, with dubious interface “improvements”, and totally unstable, at least on PowerPC macs. I try to keep my blog tecnhically-centered, and not based on personal opinions, but please Apple… you can do much better than that. Stop playing arround with the iPhone and concentrate on what really matters.

Well, about WO… Leopard has a new version of WebObjects, 5.4. It has some bug fixes and improvements over the previous versions, but unfortunately there are still a lot of show-stoppers that keep me from installing Leopard (and as you can guess from the last paragraph, I’m not specially motivated for that).

The first one is that Wonder still does not compile on 5.4. So, if you use Wonder (and you should), you must bring WebObjects 5.3 to Leopard. It’s not a very complicated process, but of course, it means trashing the brand new version. The good news is, if you use Wonder, you don’t really need WO 5.4, because almost all the features are already implemented on Wonder. The ideia is installing 5.4 (basically to get the Apache 2.2 adaptor), them trashing everything else, and finally installing 5.3. I installed it from the xCode 2 DMG and it worked fine. Anyway, Milke did an excellent (as always) document about his trip back to 5.3 on Leopard.

You should note the detail that the plists for LaunchD to boot WOTaskD and WOMonitor are not even in Leopard Client. Apparently, someone actually forgot to include that in the release. Assuming that most people develop without direct connect enabled (I don’t know how true this assumption is, but at least I do!), implying that they actually need WOTaskD to be running, it’s a bit scarry to see that actually no-one at apple tested this, or else they would find out that the files were not included. It surely doesn’t boost my confidance on all this.

Also, I develop using virtual hosts. Basically I set the adaptor URL, in WOLips launch options, to be something like http://aVirtualHost.mac/cgi-bin/WebObjects. I kept getting the “No instance available” message until I run “sudo hostname -s aVirtualHost.mac” on the command line and restarted every WO-related process (apache, WOTaskD, and the app itself). BTW, note that the file included in apache2 configuration for vhost configuration has errors, and will actually kill apache at launch if you don’t remove both examples that come with it (the error is in the logging configuration for both sample virtual hosts). Even worse, if you are trying to look for apache error logs in the error_log apache file as you always did on tiger… forget it. This kind of errors are now thrown to /var/log/system.log.

But the biggest show-stopper is EOGenerator. You do use EOgenerator, don’t you? EOGenerator was based on the same frameworks as the Apple WO tools, like EOModeler. Apple moved those frameworks from “deprecated” to “dead” with Leopard, so EOGenerator went to the grave with them. Relax, there will be a Java replacement included on WOLips, but it’s still not there. Well, talk about living in the information age… the EOGenerator is out! :)

So, if you are an WebObjects developer wondering about jumping to Leopard… my adviced is, wait. Unless you don’t use Wonder and EOGenerator, which is highly unlikely.

onBeforeUnload Javascript BODY attribute

September 14th, 2007

Those who code Javascript know that the BODY tag has two cool attributes where we can hook methods to be run when the page loads and unloads. Those are the standard onLoad and onUnload attributes.

onLoad does what you expect - runs whatever the attribute is set to after loading the entire page (or, at least, all the HTML and Javascript files).

onUnload is a little more tricky. When you have a function hooked to onUnload attribute, and you click on a link, the function will actually be executed after the browser opens the request to get the new page. This can be catastrophic in many ways. Imagine that you are on a page where you can edit some information in an asynchronous way. You edit all the stuff you want, and the browser only sends the data to the server from time to time, and when you leave the page.

Now imagine that the next page reflects the data changes you just did. You would have some kind of AJAX call on the onUnload attribute that would send the final changes to the server. But these changes will be sent after the browser opens the http request to get the next page, and actually get it from the server. You got a problem: the next page won’t reflect those last updates because it was generated before they were sent to the server!

Happily, there is a solution. Someone (I think Microsoft, but I’m not sure) implemented the onBeforeUnload event. As the name suggests, this is a hook to a method that will be executed before the page unloads, and before the http request to get the next page is open. This is a non-standard attribute, but it’s implemented on all the major browsers (IE, Firefox and Safari). And it’s really useful!

There’s a small problem with IE and tabs that you have to handle. I didn’t test this on IE yet, but this guys tell you all about it.

Recovering from optimistic locking exceptions

August 17th, 2007

WARNING: the solution presented in this article is wrong. It’s a partial solution only, it won’t always work, and you may screw up your data. To see why, check my second article on this issue.

There are many situations, in simple web applications, where you don’t really have to deal with concurrent data update. Imagine you are writing a blog app, like WordPress. Even if two persons are changing a post title at the same time (which, by it’s nature, it’s a really rare event), you, as the developer, may simply don’t care about it, and rely on the “last write wins” strategy.

When you are writing more complex stuff, specially when one needs to have really complex data being modified by different users, in different situations, at the same time, and when you have pre-calculated data, because grabbing all the objects and calculating the results in real time (fast enough for a page load) is simply not possible, you will have serious headaches (it’s already hard enough to understand this sentence without re-reading it!).

When developing WebObjects, there are two main classes of concurrency problems to solve. Intra-instance concurrent data updates, and inter-instance concurrent updates. It would appear that the second is much harder than the first… well… it’s not.

Intra-instance updates should be simplified by automatic data merging between contexts. But there are some problems. The biggest problem is that, in fact, it’s possible to totally overwrite a data modification done by another user without getting any notification of that at all. How? See this thread on the WebObjects Dev mailing list. The biggest problem is that, while a context is locked, data merging simply does not occur. So, imagine you lock context A and start modifying data. At the same time, someone locks context B on another thread, changes the same data that you are modifying in context A, and saves it. The data you changed is merged on all the other contexts where the same objects are present, as long as they are unlocked. But remember, your context A isn’t, so no merging will occur for now. Now, imagine you continue working on context A, and finally save it, and unlock it. The merging will occur now - to late, because you already saved, and probably won’t work any more in that context.

By now, you say “Naaah, that won’t happen, because WebObjects will trigger an optimistic locking exception”. No it won’t. Why? Remember that context B saved while context A was locked, right? So, when B saves, the row snapshots of the EOF stack will be updated. When you save context A, assuming that no one else (besided the A and B guys) worked on the same data at the same time, EOF will base the OL check on the row snapshots that is has in the stack. Remember, this are no more the snapshots for objects in context A. They are the snapshots caused by B saving, and those will be the same that exist in the DB. So, no OL exception will occur. Congratulations, A just trashed B data updates, and wasn’t notified at all.

Are you already scared? Good. So be even more scared. There are only two solutions for this. The first one, create a lot of separate EOF stacks (one per session, assuming the sessions are being locked in the normal WO way). This sucks, because it’s too resource expensive. It will use a lot of memory (lots or repeated snapshots in memory) and it will open many connections to the DB, that may be a problem by itself. The second solution… classic Java locking (syncronized keyword, etc). This is the time you start thinking about being a farmer, right?

Well, the news on inter-instance concurrency are better, although far from perfect. Here, there’s no data merging, and no Java syncronized stuff. Everything will be based in locking. Usually optimistic locking, but you can also use pessimistic locking (ie, “real” row-database locking). Pessimistic locking has huge problems and many experienced coders will recommend that you stay away from it. So I will not cover that, and I’ll assume you want to use Optimistic locking.

The ideia is simple: create context, fetch data, modify data, save. If you get a locking exception, re-fetch data, re-modify, and re-try to save it until no OL exception is thrown.

This is simple for simple stuff, ie, when you have one single object causing the failure. Now imagine the following scenario (and this isn’t imaginary, it occured to me): you are working with dozens of objects thay may cause OL exceptions, and if one of them causes it, all the others will probably cause too. Also, I need to create some objects (relationships, mostly, but also some individual objects) depending on what I’m doing. If I get an OL exception, I must go back, delete those objects, and create new ones, because the fact that I create, or not, an specific object depends on the data already present on the data storage. In theory, this will not be a problem: create context, fetch data, modify data, create objects (and save the created objects in a temporary array), save, get OL exception, delete all the created objects, re-fetch data, re-modify data, re-create objects, save. Right? Wrong. Unfortunately I’ve hit some obscure WebObejcts bug, as you can see in this WODev thread. This is the time you start browsing the net looking for a farm to buy, if you don’t already have one.

After a lot of experiencies, I think I have reached a reasonable way to handle this in a simple manner (remember, you will always have to think about intra-instance problems, but we are dealing with inter-instance now). Instead of fighting with WO about deleting created objects, and getting outdated data when one was supposed to get fresh one, simply don’t worry about it, and create everything from scratch every time you try to save. The code will look something like this:

synchronized (lock) { // Solving intra-instance problems,
                      //your millage may vary on this, of course
  int tries = 0;

  // Make MAX_SAVE_ANSWERS_TRY_COUNT something reasonable, like 50
  while( tries < MAX_SAVE_ANSWERS_TRY_COUNT ) { 

    // Setup context
    EOEditingContext context = new EOEditingContext();
    context.setFetchTimestamp(System.currentTimeMillis());

    // Make sure nothing "strange" will happen, this is a simply delegate
    // that blocks merging. Probably it won't be needed but I'm paranoid.
    context.setDelegate(new NoMergingECDeletage());

    // Register the EC in my session lock manager, to handle locking and
    // garbage collection automatically. Your millage may vary, specially
    // if using Wonder in a smarter way than I do.
    session.lockManager().registerEditingContext(context); 

    // Get local copies of objects
    < here you get all the local copies of your objects. Remember the
    context.setFetchTimestamp(System.currentTimeMillis()); line above?
    This will guarantee that ALL the objects you get in this context will
    contain fresh data. You can use EOUtilities.localInstanceOfObject,
    walking trough relationships like object.otherObject().anotherOne(),
    using fetch specifications, whatever. Everything will be fresh. >

    // Let’s do it.
    < Do your thing here. Create objects, modify objects, delete objects,
    go crazy. >

    // Try to save
    try {
      context.saveChanges();
      return;
    } catch (EOGeneralAdaptorException saveException) {
      ++tries;

      // isOptimisticLockingFailure is basically the method
      // with the same name in Apple docs
      if( Util.isOptimisticLockingFailure(saveException) ) {

        NSLog.out.appendln(”Optimistic locking exception”);
        // Note that I don’t refault anything here. I don’t need it.
        // On the next iteration, a new EC will be created, and all
        // the objects will be automatically refaulted.
      } else {
        // It’s some other exception, handle it somewhere else
        throw saveException;
      }
    }
  }

  throw new RunTimeException(”Could not save after ” +
MAX_SAVE_ANSWERS_TRY_COUNT + ” tries. Help me.”);
}

At the beggining, I didn’t like this approach at all. But after using in some places, and seeing it work perfectly, I’m liking it more and more. The main advantage is, it works. No strange problems, no fighting with WO bugs, no strange refaulting behaviour. It’s a dream come true. It just works. But, of course, it has some disadvantages. All the objects are fetched from the data store, with the consequent performance hit. So, if you are dealing with many many objects, this may be undoable for you. Also, it has a more serious problem if you are lazy like me: you cannot have an object binded to the page component, and use it in the processing. The reason is that you need to bring that object “inside” the newly created EC, and localInstanceOfObject won’t copy the unsaved modifications, and will not even copy newly created objects. So you have to manually copy and reproduce all the user modifications to the local copies of objects. More work for you, more work for the CPU, more objects in memory. It’s life.

Written at the beautiful and peaceful town of Serpa. Not on an iPhone.

Testing memory

August 12th, 2007

I wrote some days ago about badblocks for testing a hard drive surface. Now, the same for memory.

As I said, I bought a second-hand PowerMac G5 to replace my old G4. When I got the new machine, I run Apple Hardware Test (AHT), using the Extended Test. AHT tested my hardware, including the 2.5 GB of RAM, taking more than two hours (and making a hell of a noise, because during tests, the G5 ventilation system works in failsafe mode, which means, full power). Everything seemed to be fine. Until I installed Retrospect. I use Retrospect to make all my backups at home, and despite all it’s quirks, it always worked fine on the G4. Since I installed it on the G5, I got strange errors (the famous “internal consistentcy check”) and even crashes.

After nailing down all the possibilities (trashing preferences and existing backup sets, reinstalling Retrospect, etc) I suspected it could be an hardware problem, because I was told that the “internal consistentcy check” appears when the backup set contents are corrupted. So, I thought, my hard drive is corrupting data. I duplicated one backup set with about 80 GB, and surprise - after duplicating and running an md5 checksum on it (and diff), the files were different! This was NOT supposed to happen, naturally. So I tried the same thing on my boot drive - same problem. Ops… it’s not the drives. So, if it’s not the drives, and supposing (more exactly, praying) that it was not a motherboard issue, it must be the memory.

All my collegues at IST System Adminstration team use memtest on PCs to test the memory. This great distribution of memtest has a really nice touch: you can burn this on a CD, and boot the PC from it. It takes less that 200K of RAM, so all the other memory will be tested. Unfortunately, it’s not possible to boot it in Macs (not even Intel Macs - I tried it!). So, you must get the Mac OS X version of memtest, and boot the OS in Single User mode (using command-S during the boot sequence). The OS will take about 50 MB of RAM, which is, of course, much worse than the 200K used by the PC version, because those 50 MB will simply not be tested. But it’s better than nothing.

The official site for the Mac OS X version of memtest is here, but unfortunately, the author requires you to pay a small ammount for the download. I don’t like the approach very much because I don’t really know what I’m buying. the author says that, after paying, he sends a password for the encrypted DMG you downloaded. But I cannot download without paying, because the link is no-where. So… what happens when a new version comes out? Do I have to pay it again? Well, anyway, someone else is distributing memtest for OS X for free. Yes, it’s legal, because the software is under GNU license. So, if you don’t want to pay, just click here and grap your own free copy. Happy testing!

By the way, some tests take a lot of time. Let all of them run. Don’t assume the fact that all the “quick” tests passed means your memory is OK. Some problems may only be found with the more complex and slower tests - that’s why they are there. So, let it run. And if you have a G5, get the hell out of there, or use ear-plugs. It won’t be a nice office to work during testing, trust me.

memtest will detetct lots of common problems in memories, and will probably identify more than 99% of the defective memory modules arround. But never forget: it’s impossible to be entirely sure that a memory module is OK, simply because it’s not possible, in a reasonable time frame, to test all the possible combinations of data. Also, memory may pass all the tests in a day, and fail the next day. There are many factors that may trigger a hidden problem in memory modules: temperature, electrical flutuations, the data it contains, age, etc. If you suspect you have a bad memory module, and if you have time, run memtest for several days in a row, using the option to do many passes.

Mac-compatible ethernet card

August 3rd, 2007

For those of you who need an ethernet card that works with Mac OS X, this may be a useful tip: Mac OS X has a built-in driver for the RealTek RTL8139 chip. I looked arround and found this Netgear card, based on that chip. It’s not Gigabit, but I wanted it to connect my “new” PowerMac G5 to the ADSL modem, so 100 Mbps is fine. It’s not PCI-X, but it complies to the PCI 2.x specification, which means it will work on the G5 PCI-X slots (although the entire PCI bus will work at PCI speed, not PCI-X). It’s cheap, it works, and I can have the G5 doing all the NAT routing stuff, as I like.

Bad blocks? badblocks!

July 16th, 2007

There are not many things I miss from Mac OS 9. But there’s one that was really useful: the ability to test a hard drive surface. OS 9 disk formatter (I don’t even recall it’s name) had a “Test Disk” option that would perform a surface scan of the selected hard drive. That was awsome to test for bad blocks on the drives.

Unfortunately, that’s impossible to do with Mac OS X, at least with it’s built-in software. There are some commerical applications to do that (like TechTool Pro), but I get a little pissed off when I have to spend a lot of money buying a software that does a zillion things when all I want is surface scans, and specially when I could do it with the “old” OS and not with the new powerful UNIX-based one.

Well, Linux has the badblocks command that will do just that: test the disk surface for bad blocks. It’s a simple UNIX command, so I thought there must be a port of that to OS X (and, of course, I could try to compile it in OS X as last resource). After some googling, I found out badblocks is part of the ext2fs tools. And, fortunately, Brian Bergstrand has already done the port to OS X, including a nice installer.

The installer installs all the ext2fs stuff, including an extension that will allow you to access ext2fs volumes on OS X. As always, this is a somewhat risky operation. Personally, I avoid as many extensions as I can, because they run too close to the kernel for me to feel confortable. So, if possible, install it on a secondary OS (like an utility/recover system on an exteral hard drive, or so).

The badblocks command will be installed in /usr/local/sbin/badblocks, and it will probably not be on your PATH, so you have to type the entire path when using, or edit your PATH environment variable.

Usage is simple. First, run the “mount” command, so that you know the device names for the drives you want to test. You can obtain something like this:

arroz% mount
/dev/disk0s3 on / (local, journaled)
devfs on /dev (local)
fdesc on /dev (union)
on /.vol
automount -nsl [142] on /Network (automounted)
automount -fstab [168] on /automount/Servers (automounted)
automount -static [168] on /automount/static (automounted)

The internal hard drive is /dev/disk0 (note that /dev/disk0 is the entire drive, /dev/disk0s3 is a single partition). Imagining you want to test the internal hard drive you would type the command (as root):

badblocks -v /dev/disk0

This would start a read-only test on the entire volume. The -v is the typical verbose setting, so you may follow what’s happening. This will take a long time, depending on the hard drive you use. For a 160 GB hard drive, it took between 2 and 3 hours in a G5 Dual 2 Ghz.

I mention this because time is an important factor when testing hard drives! You should run badblocks on a known-to-be-in-good-condition hard drive, so that you can get the feeling of how fast (or slow) badblocks is. Later, if you test a possibly failing hard drive, and badblocks progresses notably slower, it will probably mean that the hard drive is in bad condition (even if it doesn’t have badblocks).

After running the command, you may get two results: your disk has, or hasn’t badblocks! :) You will see many outputs of a successful surface scan, so I leave here an example of a not-so-successful one:

/usr/local/sbin arroz$ sudo ./badblocks -v /dev/disk0
Password:
Checking blocks 0 to 156290904
Checking for bad blocks (read-only test): 120761344/156290904
120762872/156290904
120762874/156290904
done
Pass completed, 3 bad blocks found.

This is the result of a test on a 160 GB hard drive with 3 bad blocks.

After getting something like this, you may try to run badblocks again, in write mode. Note that this will destroy all the information you have on the hard drive! badblocks won’t copy the information to memory, and than back to disk. It simple destroys it. The point of running a write-enabled badblocks check is forcing the hard drive to remap the damaged sectors. Hard drives have a reserved space to use when bad blocks are found. The bad blocks are remapped to that reserved space, until it fills. And this will only happen on a write. So, run badblocks in write mode, and then again in read-only mode. If badblocks finds no bad blocks, your hard drive is fine (for now). If badblocks still finds bad blocks, it means that there are so many damaged blocks on the disk surface that the reserved area is full. Forget it, and throw the disk away. It’s useless.

WebObjects survey

June 29th, 2007

Pascal Robert has just setup an online survey for WebObjects developers. The survey is short and direct2thePoint :) so you won’t spend more than 5 minutes on it. The results will be delivered to Apple, to help them focus their development resources on the needs of the community. As Pascal said, the rules are:

  • - One survey per organization, if I see the same organization more than one time, I will delete the duplicates
  • - Please, please, be honest in your answers

So, if you are an WebObjects developer, take the survey now!

svgobjects 2.0

June 25th, 2007

As you may know, Safari 3.0 finally fully supports SVGs. Based on that, Ravi Mendis released the first beta of svgobjects 2.0, an SVG framework for WebObjects. Apparently, the framework started with the goal of drawing charts dynamically, but the author extended it to support the drawing of full-screen interfaces that could be used on the desktop and, even more, on mobile devices, like the iPhone. It may become a very useful framework for building iPhone-targeted web apps!

WebObjects rocks

June 15th, 2007

Well, WWDC is almost done, I’m waiting for the last session on Level 3 of Moscone, near one of these really big windows.

It’s a really big pain to not being able to write here all that I have learned about WebObjects (for those of you who don’t know, WWDC sessions are covered by NDAs).

Someone asked on the WebObjects mailing list how do we classify the WO news, from A to C. Well, I can say, A++++! I think the future of WebObjects will be susprising. Apple showed us some stuff that, in my opinion, is probably almost as revolutionary as the original WebObjects framework itself. But we still will have to wait.

The only thing I can say more is: if you are (considering) doing web application development, don’t be stupid - learn WebObjects NOW. Currently, it’s the most powerful web application development environment by far. And in some future time this advantage will be an order of magnitude higher.

W(O)W(O)DC 2007

June 6th, 2007

I’ll go tomorrow to SF, to assist WOWODC 2007 and WWDC 2007, so I won’t post here for some time.

WOWODC was organized by Pascal Robert, as a result of the lack of support Apple gives to WebObjects developers, and will feature some well-known people in the WebObjects community, like Chuck Hill, Mike Schrag or Anjo Krank, who we will certainly flood with questions. Mr. Pierre Frisch, the WebObjects Product Manager at Apple will be there too. This will be a great year for WebObjects, as it’s community will provide the attention it deserves! :)

See you in two weeks.