Storing page-state in the session is evil / Spammer for a day

This is a cautionary tale on the pitfalls of storing UI state in the session of a webapp.

Very occasionally we have a need to send out a bulk email to a bunch of people. For example: we had several hundred requests expressing genuine interest in The Commentator, one of our April Fools jokes this year, and we sent out a well-humoured email to them explaining it was a joke.

To help manage these mail-outs, we found and installed a nice little cgi webapp. And since I’m currently tracking a handful of people who are participating in the alpha program for FishEye 1.1 (with SVN support), I figured it would save me some time by just using this existing webapp.

Now this webapp is fairly slick: it has a nice-looking UI, plenty of features, and lots of different admin pages you can fiddle with. I went ahead and setup my alpha-program list, and composed an email announcing that the next alpha build was available. At the same time — in a different browser window — I opened up the admin pages for the Commentator list so I could check what settings we had used there. Switching back to the email-composition page, I pressed “submit”.

And suddenly 300 Commentator-hopefuls get an email about the FishEye 1.1 alpha.

And I became a spammer for a day.

And if you have ever written a webapp in-anger, then I’m sure you can guess what went on.

Upon entering the “fisheye-alpha” part of the site, it associated my session (or, more likely in this case, a cookie) with the “fisheye-alpha” list. When it presented the email-compose page, it titled the page “fisheye-alpha compose” because, obviously, that is what I was doing. However, when in another window I started clicking through the “commentator” section, my session became associated with the “commentator” list.

When I then submitted the email form, the browser posted to the webapp the email subject and body. But there was no hidden parameter saying for which mail-list this email was for. Instead, the webapp looked up the mail-list from my session, which was the “commentator” list, and sent them the mail.

The pain! The guilt!

So the moral of this story is simple. If you are using both session-state and request-data when handling a page submit, make sure the scope of the session-state matches the scope of the page.

Imagine some data-collection that is spread over a sequence pages. You can store the data from previous pages in the session: but don’t store them globally in the session. Instead associate them with this instance of the page-sequence. Make up a unique id for this instance on the first page of the sequence, put the page-data in a hashmap (indexed by this id) in the session, and use that id has a hidden parameter on every page.

It’s not that hard. And you might be surprised: make the scope of page-data explicit in your webapp, and it may actually make your code easier to follow.

Space-Time Ray-Tracing using Ray Classification

In 1996, I completed an honours year attached to my Comp. Sci. This involved a thesis, in which I choose to investigate a certain optimization technique in computer graphics. The impressive title of my thesis was: Space-time ray-tracing using ray-classification. I occasionally get the odd email about it, and the ftp server at Macquarie Uni that housed my paper, code and animations is now gone, so I decided it was about time to do a little data dump of my honours project.

The General Idea

Ray-tracing is a neat and elegant algorithm for producing photo-realistic images. Think about what happens when a camera takes a picture in real life: various light sources (the Sun, light globes, etc) bath the scene in photons, which bounce around as they are absorbed and re-emmited by objects. Some of these photons eventually end up passing through the lens of the camera and strike the film. You could easily imagine an algorithm that simulated this by tracing these rays of light forward from light-sources. The problem is that a vast majority would never hit the camera, and you end up tracing rays that never contribute to the scene.

Backward ray-tracing (or just “ray-tracing”) does the opposite: it traces rays out of the camera, bouncing rays backwards through the scene to see if they hit any light sources. This bouncing of rays allows many real-world visual artifacts to be modeled: transparency/refraction (bounce rays through objects), reflection (bounce rays along a perfect angle), diffusion (bounce rays along many angles), shadows (rays bounced towards lights are instead occluded by intervening objects).

There are various models and heuristics for bouncing rays backwards off objects. The real problem is calculating which object a ray hits. The brute force approach is to test for intersection of the ray with every object in the scene, then pick the intersection that occurred closed to the root of the ray. It is easy to see that this will be the bottleneck of the algorithm. Much of the research into ray-tracing has gone into improving the search for the object with which a ray first intersects.

The Specific Idea

My honours thesis concerned a technique for speeding up the ray-intersection calculation that also took into account time (animated scenes). If you really want to know the details you can read the paper, but the general gist goes like this: a ray is defined by 5 parameters, its (x, y, z) origin, and two angles that describe its direction. This means each ray exists as a point in a 5D space. Add time into the equation, and you end up with a 6D space. Subdivide this 6D space, and associate with each cell all the object that might intersect rays from that cell. This reduces the number of objects you need to consider when doing a ray-intersection test.

That might sound complicated, but it is that tried and true technique: convert your problem into a mathematical space and adaptively subdivide the space to reduce the work you need to do.

The Thesis

The (original) PostScript version of my thesis is available here: thesis.ps.gz (384KB). I have since converted it to PDF, which should be clearer to read on screen: thesis.pdf (348KB). An entry for this paper can be found in CiteSeer here: http://citeseer.ist.psu.edu/quail96space.html.

The abstract is as follows:

Throughout the history of computer graphics, a very active area of research has been the attempt to create convincing, life-like images. Ray tracing is a technique for generating photorealistic images, and can easily support a wide range of natural phenomenon. However, producing a ray traced image is very expensive; and producing a ray traced animation is often prohibitively expensive.

This thesis looks at two techniques for efficiently producing ray traced animations; Glassner’s space time hierarchical bounding volume technique, and my space time extension of Arvo and Kirk’s ray classification. The results show that my method is more efficient; however Glassner’s technique has much better memory performance. Based on some of the ideas of my method, some ways of improving Glassner’s technique are suggested.

57 pages.

The Code

I shudder at the thought of making this code public, but here it is: src.tgz. I wrote that code a long time ago, long before I’d been introduced to the concept of common coding conventions. I’ve made a few tweaks to the original source so that it at least compiles without errors on a modern C++ compiler.

The code contains an API for defining the scene to be rendered. So it doesn’t take in a “scene description” text file, you actually define the scene with some C++ code. This works quite elegantly, as the API is designed so that your scene description looks mostly declarative anyway.

Because the scene definition needs to be compiled into the program, you can’t just “run” the ray-tracer. So there is a little rend shell script to mange this process. For example, you can render the “mount” animation like so:

./rend out.txt strcom.cc test/mount.cc

Statistics about the rendering are saved to out.txt. The ray/object intersection algorithm is plugable, strcom.cc is my space-time ray-classifier. There is also a naive (brute force) algorithm, and an implementation of Glassner’s hybrid SS/HVB technique (for comparison). You will want to do a make clean if you change scenes.

The Animations

I created three animations for testing the performance of the ray-tracer. The output of the ray-tracer was a series of TGA files, one for each frame. At the time, I converted these to FLI files (loss-less). I have since converted the FLI files to MOV (Quicktime, lossy). Both are included below.

mount
FLI (376KB) MOV (44KB)

This is a short animation of 3 crystal balls doing a donut above a randomly generated “mountain”. Technically, this tests the ray-tracer’s ability to handle animated transparency.

nightcity
FLI (2.8MB) MOV (248KB)

“Night City” is my favorite; it is the most complicated (in terms of shapes and movement), and is cinematically the most interesting. It depicts traffic in some kind of “particle city”. Lights above illuminate the roads, and the cross-lines on the intersections control the traffic. The camera in the animation follows one “particle” as it makes its way towards a building.

“Night City” was not that difficult to create because objects can be created procedurally. For example, each building could be created with a call like create_building(floors, width, length, colour). The hardest part was modeling the path of the camera as a mathematical function. The goal of this animation was to test both camera movement and object movement.

partycool
FLI (156KB) MOV (84KB)

This last animation is designed to emphasize the “space-time” notion: the motion of objects through time. The motion-blur should be evident.

The End

I look back on my honours year with fondness, but at the same time it was a lot of hard work. I remember making a mental note to think very, very hard before embarking on something like that again (such as a Ph.D.).

Calamari Safari

As amateur foodies, one of our goals during our trip to JavaOne this year was to sample the fine cuisine San Francisco had to offer.

Our initial strategy was acknowledged as stupid: leave the hotel without advice and without our travel-guide book, and try to find some good food by wandering around. This returned some mediocre results the first two nights, but we hit the jackpot on the third night: Ponzu (104 Taylor St). Its logo of “Eat, Drink, Lounge” is the perfect description: a choice blend of sofas, bevies (Aussie slang for beverages: great beers and some killer sake cocktails), and amazing food. The calamari was heavenly, with lashings of salt and pepper with a beaut’ sauce, as was every other dish we ordered from their Asian tapas-style menu.

However, without a doubt, the highlight of the culinary experience was Tuesday night, when jag took us to the Thang Long “Crab House” restaurant. The entrée included calamari (of course) which was just exquisite, but the crab-and-cheese filled deep-fried pastry “things” were unreal. Then there was the crab. Oh the crab. When we arrived (after 8 hours at the Cenqua booth, with no lunch or breakfast), we informed James that we were, well, starving. So James ordered the food for us. First the waiters brought out some noodles, and enough crabs for one-between-four. After our first taste, we thought “Great, this is awesome!”. Then they bought out some more crabs, enough for half-each. Awesome! But the crabs kept on coming: I’m sure I had more than 1.5 portions of beautiful, garlicy, salt-and-peppery crabby goodness. YUM!

But the foodie expedition didn’t end there. After the last general session on Thursday (today), we went out to lunch with Pamela to a pretty swish (or “shi shi”) mexican restaurant on Geary St (a special thanks to Pamela: you are a champ!). But then our resident tour-guide Terrence Parr took over the reins (Terrence had previously taken us out to dinner at the First Crush (very nice) and to brunch). First stop was the Zeitgeist on Valencia St; the pub that combines pot-smoking beatniks and Netscape millionaires. Much beer was had. Then it was to the Limón peruvian restaurant. Some quality calamari was had there too. I had some paella-style thing which was good, but the pork chop that Brendan and Terrence had was about 3cm thick and looked delicious.

Its been a pretty good run, but we fly back tomorrow night; we will see if we can do any better.

JavaOne so far

I’ve been insanely busy; here is the quick update, in close-to chronological order:

Our t-shirt hurling machine finally cleared customs, and we spent about 16 hours on the weekend re-assembling it and trying to get it to work again. Monday was 8 hours on my feet in the Cenqua booth (booth 417, drop by today if you are around). Spoke to bucket loads of developers.

Tuesday we did our tshirt hurling thing at about 10am. We managed to get a few into the audience, but we had some issues (never let software people build hardware). I’ll have a more detail blog post (with pictures) about that later. Then another 8 hours at the booth. James Gosling took all the tshirt hirling contestants out to dinner, oh my god I have never had crab so good.

And today (Wednesday), I’m now sitting on the floor of the booth, fighting for a slice of the JavaOne wifi (the inkernet at the hotel is hosed).

Touchdown at San Francisco

Have arrived at hotel in San Francisco, for next weeks JavaOne. Shower and change of undies helping stave off jet lag. Now busily trying to create a wifi network between our two hotel rooms. More news as it happens.

The start of this worker thread

I was reminded by BMC today of the beginnings of my working life. He and OJB were outstanding mentors for me in my padwan years. I still use their advice every day, particularly the most useful insight BMC ever imparted to me: Don’t mix your busies and your busies.

I interviewed for that job in late 1996, and started in January 1997. Knowing that they were looking for someone to jump with them onto the Java bandwagon (now 10 years old), I prepared for the interview by reading the first edition of Java in a Nutshell the night before, and coding up one example Applet. Prior to that, I’d spent all my time coding in C++. I remember being well grilled in that interview, but in a friendly kind of way. They ran a good interview process there, even if I was able to fool them with my minimal preparation.

So that means I’ve been a full time Java coder now for — wow — eight and a bit years. I have to admit that Java as treated me very kindly over that time; both as a career path, and as someone who can be quite fussy about the computer languages they use.

I spent much of my 3 years there doing GUI coding. Originally that meant AWT, which really means spending an awful amount of time coding up your own widgets (which is more fun than work for little padwan’s with a bent for graphics). Later it meant struggling through the upgrade process between each 0.x Swing beta. Oh Swing 0.7, where are you now?

Someone in the team always claims we should have gone with Marimba Bongo instead of Swing, but they are as wrong now as they were then. (Oh — you know who you are :P )

We got a lot of work done (we made this easy by over-engineering things), but we also had plenty of fun. Before dropping our application to the test group, we would create an humorous, on-topic slash screen. These were eventually all put together into a nice little poster.

Gearing up for JavaOne

A bunch of us are going to JavaOne this year, and we’ll even have a booth where we can pimp our wares. Now that it is just over a month away, it is time to gear up on our final preparations. We hope to have some premium swag, so make sure you drop by and see us.

Getting ready to hurl

Some of the Cenqua boys were accepted as finalists to this year’s T-Shirt Hurling Contest. As you can see, they have a suitably dark lair from which to work.

And the work has well and truly begun! (Some children’s toys may have been hurt during the taking of this photo.)

I’m not giving away any more info about our hurler, except to quote these two lines from our IRC logs:

cman: I've ordered 2 USB parallel modules
bph: I'm getting a quote on a shitload of aluminium

Speaking of hurling…

After manning our booth all day, we are going to be in dire need of beer-like refreshment. I’m sure someone will manage to organize big meetup (ala last year’s), but if you are going to be in San Fran at the time and want to catch-up, leave me a message/mail.

IM trumps Javadoc

A recent IM conversation:

matt: I think I added javadoc for the funny ones
conor: k, I'll look a bit more 
conor: who needs javadoc when I have you
matt: ah. very true

AJAX talk at CJUG

I did a presentation at CJUG tonight on AJAX. We had a good turnout, the talk went well — and of course there was beer and pizza (thanks Sun and Borland!).

There is nothing like putting together a talk to force yourself to learn a technology: I used DWR for my examples, its a very capable and easy to use library. I think you might start seeing some AJAX techniques slip into some of our products :D

You never know what you’ve got ’till its gone

I upgraded my Apple PowerBook1 to OS X 10.4 (Tiger) this week, which has been quite a feast of new eye-candy, if nothing else.

But sadly, Emacs stopped working. This didn’t seem too bad, since I use IDEA for most things anyway, and this gave me a chance to try out BBEdit. But I didn’t realize how dependent I had become on a particular Emacs feature until I couldn’t use it anymore: cvs-examine. It came time to do a check-in, I found I had no access to cvs-examine and I literally spent an hour looking for alternatives.

I tried BBEdit’s CVS mode, and SmartCVS, but I am addicted to mark/diff-maked/commit-marked.

So, I did what any hacker worth his salt should do: I checked out Emacs from CVS HEAD and built the Carbon version of Emacs myself. This gave me Emacs 22.0.50.1, as opposed to 21.4 which I had been using, so I had to spend some time fixing my .emacs2. But you get that.

Also worth mentioning is that IDEA seems to run far less sluggishly. I’m not sure what combination of the latest IDEA EAP, OS X 10.4 (Tiger), or JDK 1.5 (the Other Tiger), but it is all good.


1 Actually, while we are on the topic of my PB: Macromedia Flash has stopped playing any audio for me. This includes the stand-alone player that comes with Flash MX. If anyone has any tips, please let me know.

2 Which, honestly, has 8 years of cruft in it. Including:

;(setq gnus-select-method '(nntp "nntpb.cb.lucent.com"))

That was a long time ago. :-|