Thursday, December 22, 2005

Wikipedia Watch

There be net.kook-ery here, but this point is valid:

While Wikipedia itself does not run ads, they are the most-scraped site on the web. Scrapers need content — any content will do — in order to carry ads from Google and other advertisers. This entire effect is turning Wikipedia into a generator of spam

Friday, December 16, 2005

The Drunktionary

collection of slang terms for "drunk."

Monday, December 12, 2005

Rant: don't send screenshots of textual information..

Sent to a large audience at work today.

From: Jeff Robertson
Sent: 12/12/2005 12:40 PM
Subject: Rant: don't send screenshots of textual information..

If you're ever trying to email someone a list of files, etc., please don't do so by taking a screenshot of explorer showing those files. This is quite possibly the next-to-least-usable way to convey the information, second only to recording an MP3 of yourself singing the file names to the tune of "I am the very model of a modern major
general.." and emailing that.

Not naming any names. That is all.

Friday, December 09, 2005

So that's how dynamic languages do Refactoring...

Brilliant.

Saturday, December 03, 2005

John Reynolds's Blog: Form Validation in an SOA context

work related

Wednesday, November 30, 2005

Slashdot | Cryptography in the Database

Interesting.

Friday, November 25, 2005

no pictures

I have just toured post-Katrina Bayou La Batre for the first time, and in spite of having a digital camera with me, I did not take even one picture.

First, it would be anti-climactic compared to pictures you've probably seen from elsewhere and from sooner after the storm.

Second, because unless you had a "before" picture for comparison, the "after" picture wouldn't make any sense. There were houses along the waterfront that are now just concrete slabs, but unless you knew about the houses, some of which survived the 1906 and 1916 storms that ended Bayou La Batre's reign as a seaside resort, a concrete slab just isn't impressive to look at.

And third, the most widespread visible change is not demolished houses, it is people living in motor homes, trailers, and tents (yes, tents) outside of otherwise normal looking houses. The real damage is all inside, where you can't see it. I just couldn't bring myself to take pictures of the trailers and tents.

Monday, November 21, 2005

Double Shot of that 80's Flvxx

Sort of.

First up, embryonic, early-80's version of "Flamethrower of Love", utilizing a different piece of hardware that was later abandoned for something much hotter.

Leaf Blower of Love

The next song is named after its chord progression. Almost but not quite an 80's song, it is in fact firmly rooted in 1991 (the year that "Prince of Thieves" came out) and localized to that part of the American South where all good girls love the song "I'm Proud to Be An American" and evangelize their rocker boyfriends.

D.A.G.C.A.

Wednesday, November 09, 2005

Build extra secure Web applications

/work

Saturday, November 05, 2005

Welcome to the 80's

My new musical project is Flvxxvm Florvm is the Evil Empire. After spending the last album paying tribute to 80's video games, this one takes you directly into the fictional world in which Flvxxvm Florvm was actually active in the 1980's.

Warning: Flvxxvm Florvm really sucked back then. And the songs more more overtly political. But with lyrics so bad that you couldn't tell what side of aisle they were on.

So with further ado..


The Year is 1984


The Year is 1984
and I can't wait for the nuclear war!

Sometimes you gotta lose before you can win
that's I vote republican
provoke the reds till they attack
then we'll get our country back

The Year is 1984
and I can't wait for the nuclear war!

Let 'em bomb the welfare queens
and illegal aliens
leave the ones who know how to fight
and the ones who know their rights

The Year is 1984
and I can't wait for the nuclear war!

Friday, November 04, 2005

The Naked Objects Framework

Seems like I've blogged this before. Maybe not. I know I've read it before.

java.net: Further Down the Trail

HTF did I miss this thing the first time? This is like the coolest Java thing evar.

Thursday, November 03, 2005

MySpace Worm Explanation

/work

HTML-Scrubber-StripScripts

todo: re-write in Java

XSS (Cross Site Scripting) Cheatsheet: Esp: for filter evasion - by RSnake

/work

java.net: Handling Java Web Application Input, Part 2

Work-related.

Tuesday, November 01, 2005

java.net: Implement Your Own Proxy-Based AOP Framework

/work

Saturday, October 29, 2005

Does Visual Studio Rot the Mind?

I don't really do any Windows programming, so even if VS does rot your mind, it doesn't affect me. But this looks interesting enough to read later.

Thursday, October 27, 2005

cookie theft demonstration


cookie theft demonstration, originally uploaded by jeff_robertson.

/work

This is some of what you're going to miss seeing if you don't come to my security presentation tommorrow.


Wednesday, October 26, 2005

Using and Programming Generics in J2SE 5.0

/work

Tuesday, October 18, 2005

FDIC: FIL-103-2005: Authentication in an Internet Banking Environment

More:
The Federal Financial Institutions Examination Council (FFIEC) has issued the attached guidance, “Authentication in an Internet Banking Environment.” For banks offering Internet-based financial services, the guidance describes enhanced authentication methods that regulators expect banks to use when authenticating the identity of customers using the on-line products and services. Examiners will review this area to determine a financial institution’s progress in complying with this guidance during upcoming examinations. Financial Institutions will be expected to achieve compliance with the guidance no later than year-end 2006.

Two-factor banking

/work

Steven, I do believe it's fire drill time.

In the U.S., federal regulators
are now requiring banks to have at least two-factor authentication with
their websites by the end of 2006. The Federal Financial Institutions
Examination Council (made up of the FDIC - Federal Deposit Insurance
Corp, the U.S. Federal Reserve, the U.S. Comptroller the Currency, and
others) has very recently issued a press release as well as specific, non technology-specific guidance (PDF) on the need for two-factor authentication. It's an idea being sold to banks and the public as a way to address identity theft in a supposedly proactive manner.

Using setInterval() to Make a JavaScript Listener

/work

ONJava.com: Improving JSF by Dumping JSP

/work

JavaServer Faces vs Tapestry - A Head-to-Head Comparison

/work

Urban performance legends, revisited

This has to be one of the most heavily discussed blog postings to come out of the Java world in a long time. So finally, after weeks of seeing it even turn up everywhere, I'm finally linking to it.

Thursday, October 13, 2005

back from (pseudo-) DC

Sid, if you're reading this, sorry I didn't have time to look you up. I was too caught up trying to hang with the rock stars of my current profession and getting drunken under the table by them.

Full disclosure: the rest of this entry shows me in a pretty irresponsible light.

Monday night, dinner with my co-workers at a Vietnamese next to the hotel. No drinking.

Tuesday night, several conference attendees walked to the nearby mall and ate at "Red Robin". Apparently a chain in these parts; never heard of it before. Large (think TGIF or Fuddrucker's) burgers and 25-ounce mugs of beer.

Wednesday night, the conference provided dinner and I had a few snifter's of liquor to go with it. I then went back down to O'Malley's Guiness-less Irish pub and had several Sam Adamseses. (Didn't count).

Had an interesting conversation with a middle-aged security guy whose presence in town had nothing to do with OWASP; something to do with web applications running on naval vessels. WTF? He also claimed to have had some sort of involvement with the capture of Kevin Mitnick. Don't remember his name so I can't verify.

Then, already drunk, I walked over to O'Leary's Irish Pub, where several of the hard-drinking security crowd had proceeded instead of O'Malley's. Probably about a half-mile walk, but it's along a 4+ lane highway with near-freeway-speed traffic. Not exactly a pleasant stroll down the block.

Had an indeterminate number of Guinessessess, and then someone who shall remain nameless (not to protect his identity, but to avoid giving him any fame as a result of what he did to me!) suggested Jaeger shots.

I turned down a cab ride with the rest of them, because I was busy arguing with some local people who IIRC were insisting that RHCP was the greatest band evar. (My argument, from what I remember: I'll give you "Higher Ground" and "Under the Bridge" but what have they done lately?)

On the way back to the hotel, placed the drunkest phonecall I've made in years, to the Mallet lobby phone. I have no idea what I told those kids.

After that, I think I was hazed. A couple of my so-called colleagues took my drunk self to an unfamiliar part of the hotel and left. It was actually worse than that, but I'm not getting into it here. I through what I thought was a door back to my part of the hotel, and found myself outside.

Some point later, not sure how much later, I pulled myself up off the ground in the pseudo-forest of pine trees and found my way back to bed. There were pine needles and such in the bed the next day to prove it.

I was *sick*. Worst hangover since MalletCon 2000. Possibly worst since college. The next day during the conference, I kept having to get up during the middle of powerpoint presentations to go run to the bathroom. Eventually I gave up

Went out with the same bunch to an establishment in Adam's Morgan called "Madam's Organ" (not nearly as bad as it sounds from the name). This time, I didn't touch a drop, I just had dinner. I had forgotten how it feels to be one of the few sober people in a room of drinkers.

Flight back was unmemorable. On MARTA heading back to work, a woman sang:

Got J-O-Y
Joy in the Holy Ghost
Not gonna let the Devil take my Joy
Not gonna let the Devil take my Joy
Got J-O-Y
Joy in the Holy Ghost

Got P-E-A-C-E... etc.,

For a period of about 10 minutes. Nouns inserted in place of J-O-Y included "power", "worship" and even "covering".

Apparently my baby took her first few steps while I was gone.

Monday, October 10, 2005

Jakarta ECS - Element Construction Set

The Element Construction Set is a Java API for generating elements for various markup languages it directly supports HTML 4.0 and XML, but can easily be extended to create tags for any markup language. It is designed and implemented by Stephan Nagy and Jon S. Stevens.

Sunday, October 09, 2005

i'm in DC

Well, no not really in not. I'm Gaithersburg, Montgomery County, Maryland. And I'm somewhat drunk, and somewhat surly.

I'm up here for the OWASP web-app-sec 2005 conference. No link because you can just google it and I'm free forming these thoughts, no time to link anything.

I flew in Reagan National. This at first glance appeared to be the crappiest run-down airport I'd ever seen. Then I least the immediate gate area and saw all these vaulted cathedral-style ceilings and that was kinda rockin, but still old and outdated.

The DC Metro has to be the cruftiest, most 1970's-looking rapid transit system around, and I've been on a lot of 'em. The stations all look like rejected designs for Space Mountain. And approximately half the escalators are under repair.

Montgomery County has their own bus system called "Ride-On" that connects with the Metro but doesn't use the same fare cards. The bus is $1.25.

Today I took a very brief walking tour of downtown DC. Basically the beareaucracy tour. I saw the department of Education, Transportation, HUD, DHS/FEMA.. this is where your tax dollars go people, to build a bunch of big blocky buildings in DC. Your city probably has a city hall and courthouse, and if it is a city of a certain size you probably know how monolithically soul-sucking and imprisoning those buildings are. Well, those are just little slices of DC in your home town. On both sides of the Mall, except for the Smithsonians, it's like a whole city of your local DMV.

Gaithersburg, or at least the parts right around this holiday INN, is worse. I had 'dinner' at 'O'Malley's Irish Sports Pub' in the basement of the hotel. An 'Irish' pub that does not serve Guiness. Ginness. Guinues. I may not be able to spell it but they still don't serve it. Their menu lists a location in Auburn Hills, MI. That's about right. Auburn Hills is the other place I've been to that is this bleak and empty of a suburban experience.

I stopped drinking and came up to my room to blog this, but I may just have to go back down there and drink some more.

Choose a single layer of cleverness (Loud Thinking)

The degree to which this goes against the "the database is sacred and the DBA is the high priest" approach to enterprise development, is down-right mind blowing to someone who, like me, has been taught nothing but since I started my career.

Thursday, October 06, 2005

The Fractal Microscope

I'm sure this isn't the only online Mandelbrot zoomer thingy around, but it's the one linked by Wikipedia, which is how I found it.

Fractals played a very important role in my development as a geek. Back in the 1980's, fractals were "cool" even among people who didn't know anything about math and computers. Being able to write a BASIC program to draw the Mandelbrot set or that Feigenbaum-birfucation-whatsit would impress the chicks and get you laid back then..

Well, not really. (I wish) But it was amazingly cool that using only really basic math (no calculus, not even trig required!) you could make these amazing pictures that looked a lot like the psychedlic acid-trip depictions that were popular again in the late 80's because of the Wonder Years and 20th anniversary of Woodstock and such.

(Note: I've never done LSD myself, so I can only assume that when you do it, it really does look like the Mandelbrot set)

yet more

July 15, 2003
Ok, I'm about to finally jump on the bandwagon and try Firebird.

I first tried Mozilla somewhere around Milestone 13. At first I found that the Windows version was noticeably slower than MSIE, at least on the 500mhz, 128mb of RAM that I had at the time. And I don't just mean startup time, I mean everything was slow (you could actually speed it up appreciably by using the classic theme instead of modern). It actually didn't take many more milestones after that to close this gap, though.

I've been using Mozilla regularly since approximately 0.8. For a while I actually used it on a 133mhz machine running Red Hat 6.2. That was just asking for trouble, and I got some of it in the form of long startup times and occasional crashes, but it did HTML and CSS so much better than Netscape 4 that it was worth it.

Around 1.1 time was when I finally decided to forget how to use MSIE and just use Mozilla for all my browsing except for the few intranet applications that use ActiveX controls and stuff like that.

I guess my point is, except for those early experiences I've never found myself saying "this thing is bloated! I want a smaller browser!". So I just never got the point of the Phoenix/Firebird project. But if that's the way that the Mozilla winds are blowin', I guess I'll have to go along.

Firebird just finished downloading; I guess I'll go install it.

more

I am convinced that Gilmore Girls carries a secret anti-big-government, pro-free-enterprise message.

Proof? Which secondary character is more positively protrayed: Taylor, who constantly tries to use the organs of town government to further his own agenda; or Luke, who just wants to be left alone to run his restaurant in peace?

Watch this space. I may actually get bored enough to write an essay on this topic fit for submission as a 10th grade term paper.

pretty much rounding up every thing I ever said about Iraq

April 15, 2003
Because the U.S. chose to get involved in the affairs of Iraq, we now have a moral obligation to set up an actual free society there. If we replace one tyranny with another, we have betrayed our own highest principles. Ways in which we could fail include, but are by no means limited to, the following:

If we install or allow the formation of some kind of a government where "tribal" membership is very important and tribal leaders have a lot of influence, you can bet that we will just be paving the way for the warlords and their private/family/tribal armies to carve up the place in a few years.

If we install or allow the formation of any kind of theocracy, we will produce a government that will eventually be much more likely to attack the U.S. than the one we just removed.

If we set up a government that has no actual support from its people, then it will either require our continuous military help just to stay in power, or resort to totalarian measures of its own, or fall apart and be replaced by something much worse. Or all three, in that order.

If we decide to keep Iraq under our thumb and run their affairs for an indefinate time, that would be naked colonialism, a repudiation of the principles of the American revolution itself (unfortunately, far from the first in our history).
me

this beginning an orgy of self-quoting

March 19, 2003:
I don't usually say much about war or politics, either here or in email or on usenet. But I don't think this would be a real weblog if I didn't say something now.

Once the shooting starts (and it may have already started by the time you read this), the anti-war folks may as well go home and start working on your signs and slogans for the next big crisis. If protesting didn't do anything to prevent the war (and it didn't), then it sure isn't going to end the war or bring our troops home one day sooner. In the event that the war goes badly (however you define that), no "I told you so!" smart-assed-ness will accomplish anything except to make you look like pseudo-traitors who enjoy seeing the U.S. fail in every way possible.

On the other side, making a spectacle of pouring French wine down the drain and boycotting the Dixie Chicks doesn't accomplish anything except to make the people doing these things look like a bunch of ignorant medieval peasants burning some hated person in effigy. In the event that the war goes well (however you define that), no "I told you so!" smart-assed-ness will accomplish anything except to make you look like bloodthirsty hooligans who enjoy watching your military smash and destroy other countries as if it were all some kind of spectator sport.

If the Iraqis surrender quickly, this could be a short and relatively bloodless war. If they put up a fight, it may or may not be short, but it will certainly not be bloodless. I don't know which of these is going to happen. I do know that the war itself is out of my hands and its out of yours, too. What is still very much in our hands is how we behave towards each other during and after.
me

XSS, Trust, and Barney

Another very old article on web app security, from the waning days of the dot-boom when most people were still happily being paid to crank out XSS-vulnerable applications.

(Aside: note how people in 2000 already thought of 1995 as the ancient days of the web.)

Cross-Site Request Forgeries

I think this is the original email discussion in which Cross-Site Request Forgery was first named and described.

Tuesday, October 04, 2005

my new favorite bit of plumber's jargon

"ballcock"

comp.arch.arithmetic > Where should the type information be?

Tantalyzing information about the elusive Wang character set.

The Wang systems had similar problems with charcter sets, so much so that not only were there "characters" that could not be generated from the keyboard, they also had caracters that could not be represented by an 8-bit hexadecimal code.

captcha

I've turned on the word verification for comments, since I've finally started to get comment spam.

Code page 437 - Wikipedia

Almost the best Wikipedia article EVAR. What would be the best, would be if there was a link to the Wang character set which is cited as the inspiration for the smiley faces and such. Maybe if I could find such a page, it will tell me what the actual use for ⌂ was supposed to be.

<mallet>I wonder if *that* Wang had these characters?</mallet>

Title screen for HLA Adventure?

Classic usenet... from June 2005! A thread that starts out about ASCII art descends rapidly through Microsoft bashing to people calling each other Nazis.

Sunday, October 02, 2005

SourceForge.net: Project Info - PDFCreator

Have I stumbled across a simpler-to-install way for my wife and her friends to make PDFs, than using that "FreePDF" thing I blogged a long time ago? That thing was such a bear to install that I had told my wife that unless her friend wanted to bring her laptop over and let me install it for her, she'd be better off just forking over the money for the real Acrobat.

Saturday, October 01, 2005

strangely inspiring random quote of the day

Comic strips are moving toward a primordial goo rather than away from it.
Bill Watterson

Wednesday, September 28, 2005

my Java blog is created

http://jroller.com/page/jeffrobertson

Now I just need to blogroll myself.

Use Stored Procedures for Java Persistence

Find out why you should use stored procedures to build your Java persistence layer instead of embedded SQL, entity beans, or tools such as Hibernate. Then learn how to do it.


Contrarian, to say the least.

Tuesday, September 27, 2005

the big three-oh, belated

I've been thirty for over a month, and it finally hit me: I'm not a 20-something anymore. What finally did it for me? Looking up the ages of various TV and movie stars on IMDB.

Throughout my 20s, I could count on the fact that actors my age were still being cast as teenagers. You, the old 90210 factor.. a 26 year old guy playing a 17 year old guy is, while not believable to anybody, apparently what audiences want to see.

But once you hit 30, you're finally an adult by hollywood standards.

For example: just last year, Freddie Prinze Jr. was able to play the apparently-teenaged Fred in "Scooby Doo II". Next year, young master Prinze will turn 30. He'd better land himself a nice adult sitcom quick. Whoops, he just did!

my baby pictures!

Several months ago, my wife got on to me for putting pictures of our kids in public view on Flickr. Rather than making them private and setting up the people that I wanted to show them to as friends, I did the lazy thing and just deleted them off of Flicr.

Unfortunately, it turns out that these were the only copies of these particular pictures! Including the first picturs of my younger daughter when she came home from the hospital.

If any of you, for any reason, saved off a copy of any of these pictures while they were online, please send me a copy.

Monday, September 26, 2005

This morning I overslept, and stumbled out to the car, forgetting to take the trash to the curb (now I remember, dammit!), and was very pleasantly surprised by the presence of rain.

I guess this is the after-effects of Hurricane Rita. I think it is also the first time this month that it has rained at my house. Every green growing thing in my yard is thankful.

Sunday, September 25, 2005

Slashdot | Why Vista Had To Be Rebuilt From Scratch

Yes, I'm blogging a Slashdot story. Still in the process of reading TFA, but this one line right here is what makes me think this article is a keeper:
In 2001 Microsoft made a documentary film celebrating the creation of Windows XP, which remains the latest full update of Windows. When Mr. Allchin previewed the film, it confirmed some of his misgivings about the Windows culture. He saw the eleventh-hour heroics needed to finish the product and get it to customers. Mr. Allchin ordered the film to be burned.


Interesting that according to this WSJ article, Microsoft's problem has been too much "cowboy coding" and not enough disciple, whereas the natural tendency of the open source culture is to accuse of closed-source companies as having too much process and not enough freedom.

Friday, September 23, 2005

java.net: Dynamic Interaction with Your Web Application

In this article I will show you the code of a simple servlet. This servlet accepts just one attribute via the POST method. An equally simple HTML page consisting of a text area and a submit button is written to interact with it. Yet despite the simplicity of these two components, what we will have is a powerful tool to interactively analyze the state of any web application.

music to steal

"Black Crow Heart of Gold" by Numbers. This song is very... canonical. The chunk-chunk-chunk of the guitar, that droning keyboard, the lyrics that I assumed had something to do with infinite improbability drives until I found out the song really was supposed to be about crows, the frankly and probably completely accidentally Rush-like arrangement (slow but jerky rythym like "Tom Sawyer", that part starting at 4:00 reminds me of parts of "Bytor and the Snow Dog").. oh hell, just listen to it.

Thursday, September 22, 2005

have the Rita-induced gas panics started yet?

Any price-gouging going on already?

most pointlessly narcissistic thing ever

See if you can recognize the 20 Flvxxvm Florvm songs excerpted here.

0x90.org // [Absinthe :: Automated Blind SQL Injection] // ver1.3.1

Absinthe is a gui-based tool that automates the process of downloading the schema & contents of a database that is vulnerable to Blind SQL Injection.

Absinthe does not aid in the discovery of SQL Injection holes. This tool will only speed up the process of data recovery.

How It's Difficult to Ruin a Good Name: An Analysis of Reputational Risk

To what extent is (or isn't) investor confidence shaken? In other words, why is it the case that information security incidents do not appear to have a greater impact on both investor confidence as well as the public at large? To phrase the question in financial terms: why isn't the top line effected more than it is? To poignantly highlight this phenomena we ask: If 40 million customer credit card numbers are exposed in a security breach at the credit card processor CardSystems , why do a significant number people not cancel their Visa and/or Mastercard?

Wednesday, September 21, 2005

N453 EAT


4th floor hallway of founders hall

This is the top floor from which the aforementioned stairs are (one of) the escape routes. Obviously built out in recent times in space that used to just be attic. Very out of place; almost like being on a spaceship . Check out all those metal doors on the right wall.


stairwell in founders hall, royal holloway, egham, england

These narrow spiral metal stairs are an officially designated fire escape route for the upper floors.


Erinna


Erinna, originally uploaded by jeff_robertson.

Victorian half-naked-lady statue located at formerly all-female college. There's a dirty movie in there somewhere.

Yes, the pictures I took in England finally got developed. This is the statue which, the first time I saw it (across a shadowy courtyard at 2:00 am), struck me as unnervingly.. ghostlike? I think the word is "numinous". The photo really doesn't capture that part.


11Alive.com: Atlanta - Red Cross Kicked Out of DeKalb

Officials with the American Red Cross decided to vacate a mega relief center in DeKalb County at 5 p.m. Monday after the county CEO complained publicly about the agency's services or lack thereof.

Buggin' My Life Away : Anatomy of a Software Bug

I thought I’d discuss the anatomy of one of the more famous bugs we’ve had in Word: the “Disk is full” on save error.

Why software sucks - scottberkun.com

In order for people to say “this sucks” they have to care enough about the thing you’ve made to spend time with it and recognize how bad it is. For things that are equally bad, but are unimportant to someone, you won’t hear the same complaint.

yeah, that's what I need: another blog!

I'm thinking of setting up a separate blog purely for discussion of programming topics. The posts that consist entirely of Java code will go there in the future. Advantages:

  1. Keep that sort of thing off this blog.
  2. Have a blog that consists entirely of completely safe-for-work material so I can put it on business cards and such.
  3. With those eyes diverted to the other blog, I'll have greater freedom of speech here.
  4. A blog on jroller.com or somewhere like that seems likely to attract an audience of people who like to read posts consisting mostly of Java code.
  5. Anybody who wants to read both, can just subscribe to both.
Stretching myself too thin? Considering how few people read this blog anyway, is this just asking for trouble?

Tuesday, September 20, 2005

Woman pass men in IT pay scale - ZDNet UK News

Across all sectors the average female team leader, at 37 years old, is four years younger than her male counterpart, while female IT managers earn on average £45,869 per year — £779 more than the men do.

Georgia's New


Friday, September 16, 2005

see all that stuff in there? that's why your robot never worked

Ever have one of the days where you wake up in the morning and say to yourself: "Self, the world doesn't have enough J2EE web frameworks. Let's make one" ?

My framework, which I will probably not even name much less actually build, will have the following features:

  1. A "web page", with it's forms, buttons, etc., is represented by a POJO, or something very POJO-ish.
  2. Form fields on the web page will have their values copied into like-named bean properties on the POJO. Nothing new there, this is basic Struts stuff.
  3. Buttons, links, etc., being clicked by the user will result in the like-named method of the POJO being executed. Again, nothing new here.
  4. There will be no XML config file. Everything the framework needs to know, it gets from the POJO by doing reflection or annotations or something.
  5. All HTML will be generated by the framework by looking at the metadata on the POJO. That's right, there is NO template language.
  6. Note that does not mean that there will be HTML in the code or the annotations; it means that there will be annotations like "@Textarea" that flag that a certain bean property is represented by a text area.
  7. Annotations are optional, you can use this framework with older versions of Java by conforming to a naming convention for your bean properties and methods.
  8. In other words, all you write is a bunch of plain old classes, that follow some set of naming conventions and annotations, and you produce a working web app.
  9. Maybe the objects don't even have to be written in Java; maybe they are written in a language that does not need to be compiled, to facilitate on the fly hacking.
  10. The HTML produced by the framework will be very basic and is intended to be styled completely with CSS. If you don't think CSS is powerful enough to avoid the need to customize the HTML itself, then you haven't kept up with CSS.
  11. This is a pure web framework; it will not muddy itself by trying to deal with persistence, transactions, etc. Since the page objects are just POJO's, there should be no reason why you can't use them with EJB or Hibernate or something.
How's that for a manifesto?

Tim Boudreau's Blog: Patterns, Schmatterns

it's the same type of hype that says that one day, in the land of milk and honey, all software will be made by "component assemblers" (who presumably get paid minimum wage). I'd like to coin a term for these thingies - YAWMTI - Yet Another Way to Make Talent Irrelevant.

Monday, September 12, 2005

Slashdot | The Six Dumbest Ideas in Computer Security

Actual work-related content on Slashdot! How long has it been? I'm still in the process of RTFA but I do plan to skim the comments.

Friday, September 09, 2005

100 dishes to eat in Alabama before you die

This is old, and I think it's been discussed on certain email lists I'm on a few months back. However, somebody mentioned it to me yesterday so here it is again.

I've had 5 of the 100 dishes (not telling you which ones), although I've eaten at more of the restaurants than that.

Thursday, September 08, 2005

yahoo! vs. google: synerge

Pretty much what it says: yahoo vs. google

something remotely like an actual use for DynamicDelegator

Closer than our barking vehicle example, but still a toy. But hopefully you should be able to see the power of this thing. Without DynamicDecorator, the class below would have to provide an implementation of the entire COnnection interface, with all of it's methods except for close() just tunnelling straight through to the real connection. Something like this (but not exactly this) is why I wrote this kind of code for a real project at work.


/*
* StoopidDatabaseConnectionPool.java
*
* Created on September 8, 2005, 4:24 PM
*/
import java.util.*;
import java.sql.*;
/**
* Really simple example of how you might use DynamicDelegator.
*
* @author jRobertson
*/
public class StoopidDatabaseConnectionPool {

Collection pool = new HashSet();

public synchronized Connection getConnection() {
Connection con;
if( pool.isEmpty() ) {

// no connections already exist, so make one
con = reallyConnectToDatabase();

} else {
// get one from the pool
con = (Connection) pool.iterator().next();

// remove it so no one else can have it
pool.remove(con);
}

// wrap the connection with a proxy that will
// put the (real) connection back into the pool
// when the proxy is closed.
return (Connection) new PooledConnection(con).getProxy();

}


// named class, not anonymous, because of issues using
// reflection on local classes
public class PooledConnection extends DynamicDelegator {

public PooledConnection(Connection c) {
super(c);
}
public void close() {
pool.add(wrapped);
}

}

private Connection reallyConnectToDatabase() {
// not implemented for this silly example!
// if you want to try it, implement it yourself

// create a mock "Connection" that implements the
// Connection interface in the sense of being able
// to be assignable, but which does not actually
// implement any of the methods (they will throw exceptions).
// Another crazy use for InvocationChain.
InvocationChain chain = new InvocationChain();
chain.add(new Object() );
chain.addInterface(Connection.class);
return (Connection) chain.newProxyInstance();
}

public String toString() {
return "StoopidDatabaseConnectionPool: "+pool.size();
}

public int size() {
return pool.size();
}


}

Dynamic delegation, act 2

Last time, I showed an example of an InvocationHandler that used reflection on its own methods to decide when and how to delegate. Today I am going to take this a step further and present a base class that can be extended for any number uses. All of the code in this post has been tested, and I may also make it available in a zip file.

Firstly, the main class, DynamicDelegator. This is an abstract class that needs to be extended to add the methods that you want to override. For a simple example, a wrapper around java.util.Map might look like this:

public class MapWrapper extends DynamicDelegator {

public MapWrapper(Object o) {
super(o);
}

public Object put(Object key, Object value) {
System.out.println("Put called!");
return ((Map)wrapped).put(key,value);
}
}

Another class might use MapWrapper like this:

Map m = (Map) new MapWrapper(new HashMap()).getProxy();
m.put("foo","bar");
System.out.println( m.get("foo"));

When put is called, the method declared in MapWrapper will be executed. When get is called, the method executed will be the one from HashMap. It so happens that in this case, MapWrapper's put method also calls the method on the underlying Map after doing some logging output.

Here is an example that illustrates the introduction of an extra interface (in this case, Runnable) that is not implemented by the wrapped class:

public class MapWrapper extends DynamicDelegator implements Runnable {

public MapWrapper(Object o) {
super(o);
}

public Object put(Object key, Object value) {
System.out.println("Put called!");
return ((Map)wrapped).put(key,value);
}

public void run() {
System.out.println("Whoohoo!");
}
}

Obviiously the above is highly contrived. The code to use it might look like this:

Map m = (Map) new MapWrapper(new HashMap()).getProxy();
m.put("foo","bar");
System.out.println( m.get("foo"));
((Runnable)m).run();


What follows is the actual code for DynamicDelegator and the supporting classes that make it work. (HashKey and MethodSig from last time are used as well, but are not repeated).


/*
* DynamicDelegator.java
*
* Created on January 13, 2005, 9:31 AM
*/

import java.lang.reflect.*;

/**
* A class to make it easy to write dynamic proxies that
* wrap existing classes. Simply write methods that have
* the same names and signatures as the methods that you
* want to override. All other methods will be tunnelled
* straight through to the wrapped object. Uses reflection
* heavily, obviously.
* <p>
* It is not neccessary for the wrapper class to implement the same
* interface(s) as the wrapped object at compile time. Method name matching
* takes place dynamically at run time.
* <p>
* For a simple example, a wrapper around java.util.Map might look like this:
* <pre>
* public class MapWrapper extends DynamicDele {
*
* public MapWrapper(Object o) {
* super(o);
* }
*
* public Object put(Object key, Object value) {
* System.out.println("Put called!");
* return ((Map)wrapped).put(key,value);
* }
* }
* </pre>
* Another class might use MapWrapper like this:
* <pre>
* Map m = (Map) new MapWrapper(new HashMap()).getProxy();
* m.put("foo","bar");
* System.out.println( m.get("foo"));
* </pre>
* When <code>put</code> is called, the method declared in MapWrapper
* will be executed. When <code>get</code> is called, the method executed
* will be the one from HashMap. It so happens that in this case, MapWrapper's
* <code>put</code> method also calls the method on the underlying Map after
* doing some logging output.
* <p>
* Here is an example that illustrates the introduction of an extra interface
* (in this case, Runnable) that is not implemented by the wrapped class:
*<pre>
* public class MapWrapper extends DynamicDelegator implements Runnable {
*
* public MapWrapper(Object o) {
* super(o);
* }
*
* public Object put(Object key, Object value) {
* System.out.println("Put called!");
* return ((Map)wrapped).put(key,value);
* }
*
* public void run() {
* System.out.println("Whoohoo!");
* }
* }
* </pre>
* Obviiously the above is highly contrived.
* The code to use it might look like this:
* <pre>
* Map m = (Map) new MapWrapper(new HashMap()).getProxy();
* m.put("foo","bar");
* System.out.println( m.get("foo"));
* ((Runnable)m).run();
* </pre>
* @see java.lang.reflect.Proxy
* @see java.lang.reflect.InvocationHandler
* @see WrapperFactory
* @author jRobertson
*/
public abstract class DynamicDelegator {

/**
* The inner object that is being wrapped by us.
*/
protected Object wrapped;

/**
* If the getProxy method has been called, thisProxy
* is a reference to the proxy object that was returned
* by getProxy. This reference may be passed to any callbacks
* or other methods where you would normally pass "this".
*/
protected Object thisProxy;

/** Creates a new instance of DynamicDelegator */
public DynamicDelegator(Object wrapped) {
this.wrapped = wrapped;
}


/**
* Uses InvocationChain to tie this wrapper and the wrapped object
* together as a single proxy instance. The proxy implements all
* interfaces that are implemented by either this wrapper or by
* the wrapped Object, as well as any interfaces returned by the
* getAdditionalInterfaces method. Any method called on this proxy
* will be invoked on the wrapper if such a method if found there,
* or on the wrapped object otherwise.
* @see InvocationChain
*/
public Object getProxy() {
InvocationChain chain = new InvocationChain();
chain.add(this);
chain.add(wrapped);
chain.addInterfaces(getAdditionalInterfaces());
thisProxy = chain.newProxyInstance();
return thisProxy;
}




/**
* Normally this returns a zero-length array. Override to specify
* that the proxies created by this class should implement the
* returned interface(s) in addition to any that are implemented
* by the wrapper or the wrapped object.
*/
protected Class[] getAdditionalInterfaces() {
return new Class[0];
}


}


Now, to prove that I tested this thing, here is a JUnit test case which creates a couple of concrete implementations:


/*
* WrapperTest.java
* JUnit based test
*
* Created on January 13, 2005, 9:43 AM
*/

import junit.framework.*;

/**
*
* @author jRobertson
*/
public class WrapperTest extends TestCase {

public WrapperTest(String testName) {
super(testName);
}



protected void setUp() throws java.lang.Exception {
}

protected void tearDown() throws java.lang.Exception {
}

// TODO add test methods here. The name must begin with 'test'. For example:
// public void testHello() {}

public void testMap() throws Exception {

java.util.Map m = new java.util.HashMap();

MapWrapper mw = new MapWrapper(m);

java.util.Map proxyMap = (java.util.Map) mw.getProxy();

proxyMap.put("a","b");

assertEquals("b", proxyMap.get("a"));

assertTrue(mw.putCalled);

}

public void testRunnableMap() throws Exception {

java.util.Map m = new java.util.HashMap();

RunnableMapWrapper mw = new RunnableMapWrapper(m);

java.util.Map proxyMap = (java.util.Map) mw.getProxy();

proxyMap.put("a","b");

assertEquals("b", proxyMap.get("a"));

assertTrue(mw.putCalled);

((Runnable)proxyMap).run();

assertTrue(mw.runRan);

}

public void testRunnableMap2() throws Exception {

java.util.Map m = new java.util.HashMap();

RunnableMapWrapper2 mw = new RunnableMapWrapper2(m);

java.util.Map proxyMap = (java.util.Map) mw.getProxy();

proxyMap.put("a","b");

assertEquals("b", proxyMap.get("a"));

assertTrue(mw.putCalled);

((Runnable)proxyMap).run();

assertTrue(mw.runRan);

}

public class MapWrapper extends DynamicDelegator {

public boolean putCalled = false;

public MapWrapper(Object o) {
super(o);
}


public Object put(Object key, Object value) {
putCalled = true;
return ((java.util.Map)wrapped).put(key,value);
}

}


public class RunnableMapWrapper extends DynamicDelegator {

public boolean putCalled = false;
public boolean runRan = false;

public RunnableMapWrapper(Object o) {
super(o);
}

protected Class[] getAdditionalInterfaces() {
return new Class[] {
Runnable.class
};
}

public Object put(Object key, Object value) {
putCalled = true;
System.out.println("Put called!");
return ((java.util.Map)wrapped).put(key,value);
}

public void run() {
runRan = true;
}

}



public class RunnableMapWrapper2 extends DynamicDelegator implements Runnable {

public boolean putCalled = false;
public boolean runRan = false;

public RunnableMapWrapper2(Object o) {
super(o);
}

public Object put(Object key, Object value) {
putCalled = true;
System.out.println("Put called!");
return ((java.util.Map)wrapped).put(key,value);
}

public void run() {
runRan = true;
}

}


}


You will no doubt have noticed that DyanamicDelegator uses another class called InvocationChain to do the heavy lifting. InvocationChain is what I ended up with after re-factoring as much of logic related to conditional delegation out into it's own class, and generalizing it as much as possible.


/*
* InvocationChain.java
*
* Created on January 18, 2005, 10:46 PM
*/

import java.lang.reflect.*;
import java.util.*;

/**
* Uses reflection to create a chain of responsibility out of a
* collection of otherwise unrelated classes.
*
* @see java.lang.Proxy
* @see java.lang.InvocationHandler
* @see DynamicDelegator
*
* @author jRobertson
*/
public class InvocationChain implements InvocationHandler {

private Set interfaces = new HashSet();
private LinkedList links = new LinkedList();

/** Creates a new instance of InvocationChain */
public InvocationChain() {
}

/** Creates a new instance of InvocationChain
* with one object.
*/
public InvocationChain(Object a) {
this();
add(a);
}

/** Creates a new instance of InvocationChain
* with one object.
*/
public InvocationChain(Object a, Object b) {
this();
add(a);
add(b);
}

/**
* Adds the specified object to the end of the chain.
*/
public void add(Object o) {
ChainLink link = new ChainLink(o);
links.add(link);
ReflectionUtils.getAllInterfaces(o.getClass(), interfaces);
}

/**
* Manually add this interface to this list of interfaces
* that will be implemented by this chain.
*/
public void addInterface(Class c) {
interfaces.add(c);
}

/**
* Manually add these interfaces to this list of interfaces
* that will be implemented by this chain.
*/
public void addInterfaces(Class[] c) {
interfaces.addAll(Arrays.asList(c));
}

/**
* This method implements the InvocationHandler interface. The chain
* of responsibility will be searched until a method of the required
* name and argument types is found, and that method will then be
* invoked. The search stops after finding the first occurrence of
* a method in the chain, so the order in which the objects were
* added is important.
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// search the objects in the chain, one by one
for(Iterator i=links.iterator(); i.hasNext();) {
ChainLink link = (ChainLink) i.next();

// if the class implements the interface that
// declared this method, run it. we do this because
// I've seen cases where methods declared by a class's
// distant ancestors don't show up when you enumerate
// it's methods. specifically, the Connection objects
// returned from Oracle's database driver are like this.
if( method.getDeclaringClass().isAssignableFrom( link.getObject().getClass() ) ) {
return method.invoke(link.getObject(), args);
}

// if the class has a method that has the same
// name and type as this method, find that
// method and run it instead
Method match = link.matchMethod(method);
if( match != null) {
return match.invoke(link.getObject(), args);
}

}

// ok, the fast way of just looking stuff up in a hashmap
// failed... now try the slow way that involves catching
// exceptions. not sure if it is really possible to get
// here, but you never can tell with reflection
for(Iterator i=links.iterator(); i.hasNext();) {
ChainLink link = (ChainLink) i.next();

try {
return method.invoke(link.getObject(), args);
} catch (IllegalAccessException e) {
// nothing
} catch (IllegalArgumentException e) {
// nothing
}
}

throw new NoSuchMethodException("couldn't find metho in my chain of respsonsibility: "+method);
}

/**
* Returns the set of all interfaces implemented by
* any objects in the chain.
*/
public Class[] getInterfaces() {
Class[] intArray = new Class[interfaces.size()];
return (Class[]) interfaces.toArray(intArray);
}

/**
* Creates a proxy that implements all interfaces that are
* implemented by any object in the chain, and with this
* InvocationChain as the invocation handler.
*/
public Object newProxyInstance() {
return Proxy.newProxyInstance(getClass().getClassLoader(), getInterfaces(), this);
}

/**
* Inner class for each delegate in the chain.
*/
private static class ChainLink {
private Map methodMap = new java.util.HashMap();
private Object object;

ChainLink(Object o) {
object = o;
Method[] methods = o.getClass().getMethods();
for(int i=0; i<methods.length;i++) {
Method method = methods[i];

// do not count methods that we can't access
if( Modifier.isPublic(method.getModifiers())
&&
Modifier.isPublic(method.getDeclaringClass().getModifiers())
) {
methodMap.put( new MethodSig(method), method);
}
}
}

Method matchMethod(Method m) {
return (Method)methodMap.get( new MethodSig(m));
}

Object getObject(){ return object; }


}



}


InvocationChain is a pretty wild and wooly utility by itself. You could use it to combine unrelated classes and interfaces in a complete arbitrary way, as this test code illustrates:


import junit.framework.*;
/*
* InvocationChainTest.java
* JUnit based test
*
* Created on September 1, 2005, 12:02 PM
*/

/**
*
* @author jRobertson
*/
public class InvocationChainTest extends TestCase {

public InvocationChainTest(String testName) {
super(testName);
}


public static interface Animal {
String speak();
}

public static interface Vehicle {
int topSpeed();
}

public static class Dog implements Animal {
public String speak() {
return "woof!";
}
}

public static class Sled implements Vehicle {
public int topSpeed() {
return 5;
}
}

public void testChain() {

InvocationChain chain = new InvocationChain(new Dog(), new Sled());

Object dogSled = chain.newProxyInstance();

assertEquals( "woof!", ((Animal) dogSled).speak() );

assertEquals( 5, ((Vehicle) dogSled).topSpeed() );

}

}


Finally, InvocationHandler itself needs a method to enumerate all the interfaces implemented by a class and any of it's superclasses, and the super-interfaces of all of those, and so on. Because this is a general utility I put it into a separate class.


/*
* ReflectionUtils.java
*
* Created on January 18, 2005, 8:07 PM
*/

/**
* Utility methods for reflection, classes, interfaces, etc.
* @author jRobertson
*/
public class ReflectionUtils {

/**
* Recursively walks the graph of all superclasses and interfaces
* that are related to the passed-in class, and adds all the Class
* objects representing all the interfaces that are found to the
* passed-in Set.
*/
public static java.util.Set getAllInterfaces(Class c) {
java.util.Set s = new java.util.HashSet();
getAllInterfaces(c, s);
return s;
}

/**
* Recursively walks the graph of all superclasses and interfaces
* that are related to the passed-in class, and adds all the Class
* objects representing all the interfaces that are found to the
* passed-in Set.
*/
public static void getAllInterfaces(Class c, java.util.Set col) {

if(c == null) {
return;
}

Class[] ifaces = c.getInterfaces();

for(int i=0; i< ifaces.length; i++) {
col.add(ifaces[i]);
getAllInterfaces(ifaces[i], col);
}

getAllInterfaces(c.getSuperclass(), col);

}


}


Next time: more examples of what you can do with this stuff.

NPR : Alabama Town

Bayou La Batre was an impoverished coastal town in Alabama before Katrina swept through its mobile homes and one-story houses. Jim Zarroli went on patrol with a FEMA official and reports and how residents are coping with what's left and what's lost.

Wednesday, September 07, 2005

some real code..

All of the code in the previous post was typed on the fly, and I would not expect it to compile. Before I get any further into refactoring it, here are complete working versions:

MyInvocationHandler.java

/*
* MyInvocationHandler.java
*
* Created on September 7, 2005, 1:35 PM
*/
import java.lang.reflect.*;
import java.util.*;
/**
* Test code for my blog postings about InvocationHandlers.
*
* @author jRobertson
*/

public class MyInvocationHandler implements InvocationHandler {

/**
* The interface for the class that we are proxying/decorating/delegating-to.
*/
public static interface SomeInterface {
int foo(int x);
void bar(String s);
boolean baz();
void quux();
}


/**
* An implementation of this interface.
*/
public static class SomeImpl implements SomeInterface {
public int foo(int x) {
System.out.println("SomeImpl.foo");
return x+1;
}
public void bar(String s) {
System.out.println("SomeImpl.bar");
}
public boolean baz() {
System.out.println("SomeImpl.baz");
return true;
}
public void quux() {
System.out.println("SomeImpl.quux");
}
}



private Object realObject;

private Map methodsMap = new HashMap();

private void addMethod(Method m) {
methodsMap.put( new MethodSig(m), m);
}

public MyInvocationHandler(Object realObject) {
this.realObject = realObject;

Method[] methods = getClass().getMethods();
for(int i =0; i<methods.length; i++) {
addMethod( methods[i]);
}
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method myMethod = (Method) methodsMap.get( new MethodSig(method));

if( myMethod != null ) {
// if it's in the map, run the one from the map
return myMethod.invoke(this,args);
} else {
// otherwise just run the method on the original object
return method.invoke(realObject,args);
}
}

/**
* Replacement method that overrides the matching foo() method
*/
public int foo(int x) {
System.out.println("MyInvocationHandler.foo");
return ((SomeInterface) realObject).foo(x);
}

/**
* Replacement method that overrides the matching bar() method
*/
public void bar(String s) {
// do nothing! hahaha
}

/**
* Replacement method that overrides the matching baz() method
*/
public boolean baz() {
throw new RuntimeException("you can't call baz()!");
}


// notice that we have no replacement method for quux()


/**
* Main method to serve as a basic test.
*/
public static void main(String args[]) throws Throwable {

SomeInterface si = (SomeInterface)
Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(), new Class[]{SomeInterface.class}, new MyInvocationHandler(new SomeImpl()));

// should print:
// MyInvocationHandler.foo
// SomeImpl.foo
si.foo(1);

// should print NOTHING, since the proxy should suppress the call to the object
si.bar("test");

// should print "SomeImpl.quux" because we don't declare a replacement method
si.quux();

// should throw!
try {
si.baz();
} catch (Throwable t) {
System.out.println(t);
}

}

}


MethodSig.java

/*
* MethodSig.java
*
* Created on September 7, 2005, 1:36 PM
*/

import java.lang.reflect.Method;

/**
* Hash key for a map of methods based on method name and parameters.
*/
public class MethodSig extends HashKey {
public MethodSig(Method m) {
super( m.getName(),
java.util.Arrays.asList( m.getParameterTypes()) );

}
}


HashKey.java

/*
* HashKey.java
*
* Created on February 8, 2005, 9:54 AM
*/

import java.util.*;

/**
* A convenience class for easily making hashmap
* keys that involve multiple objects. Essentially
* just a read-only collection of Objects, except for
* the 9 overloaded constructors that allow you to
* write code like this:
* <pre>
*
* map.put( new HashKey("foo","bar"), someValue);
*
* Object v = map.get( new HashKey("foo","bar"));
*
* </pre>
*
* Can be useful as a base class for local hash key classes:
*
* <pre>
*
* public class MyHashKey extends HashKey {
* public MyHashKey(SomeClass thing) {
* super( thing.getFoo(), thing.getBar());
* }
* }
*
* </pre>
*
* @author jRobertson
*/
public class HashKey extends AbstractCollection implements Collection, java.io.Serializable {

private Collection keys;

/** Creates a new instance of HashKey */
public HashKey(Object key1) {
this( new Object[]{ key1 });
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2) {
this( new Object[]{ key1, key2});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3) {
this( new Object[]{ key1,key2,key3});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3, Object key4) {
this( new Object[]{ key1,key2,key3,key4});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3, Object key4, Object key5) {
this( new Object[]{ key1,key2,key3,key4,key5});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3, Object key4, Object key5, Object key6) {
this( new Object[]{ key1,key2,key3,key4,key5,key6});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3, Object key4, Object key5, Object key6, Object key7) {
this( new Object[]{ key1,key2,key3,key4,key5,key6,key7});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3, Object key4, Object key5, Object key6, Object key7, Object key8) {
this( new Object[]{ key1,key2,key3,key4,key5,key6,key7,key8});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3, Object key4, Object key5, Object key6, Object key7, Object key8, Object key9) {
this( new Object[]{ key1,key2,key3,key4,key5,key6,key7,key8,key9});
}


/** Creates a new instance of HashKey */
public HashKey(Object[] keys) {
this( Arrays.asList(keys));
}


/** Creates a new instance of HashKey */
public HashKey(Collection keysToAdd) {
keys = keysToAdd;
}

public boolean equals(Object obj) {

if( !(obj instanceof HashKey) )
return false;

HashKey that = (HashKey) obj;

return keys.equals( that.keys);

}

public String toString() {
return keys.toString();
}

public int hashCode() {
return keys.hashCode();
}

public int size() {
return keys.size();
}

public Iterator iterator() {
return keys.iterator();
}


}

Tuesday, September 06, 2005

Dynamic delegation in Java without ugly InvocationHandlers

I have also seen dynamic proxies (the Proxy and InvocationHandler classes in J2SE) be used for a lot of situations where what the programmer really wants is something more like dynamic delegation.

The design of the InvocationHandler.invoke() works great for when you want to do the same thing no matter what method is being invoked. For instance, logging:


class MyInvocationHandler implements InvocationHandler {

public MyInvocationHandler(Object realObject) {
this.realObject = realObject;
}

private Object realObject;

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// log it
log.debug(m);

// now run it
m.invoke( realObject, args);
}
}


But one often sees these invocation handlers start to grow hair like this:


private Object realObject;

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if( m.getName().equals( "foo" )) {
// .. insert any special logic for foo method here ..

// followed by actually running the method
m.invoke( realObject, args);
} else if (m.getName().equals( "bar" )) {
// swallow the call to bar() and don't pass it on!
} else if (m.getName().equals( "baz" )) {
throw new SomeException("you can't call baz()!");
} else {
// any other method, just call it straight through
m.invoke( realObject, args);
}

}


While the above will get the job done, it is about as anti-OOP, anti-Design Patterns, and just plain anti-Java-esque a method as you could possibly invent. It violates one of the first rules we learned as Java programmers, which is that switch/case statements (of which the above is really an instance, if only Java supported switching on an object) are a relic from procedural languages and should be replaced by more modern constructs. You'll get this advice from Effective Java, you'll get it from Fowler's Refactoring. How can we remove this ugliness?

What is the code actually trying to do? It wants to match the Method object to any custom invocation code that needs to run when that Method is called. This is a mapping operation, hence this block of if/else statements is really trying to be a Map.

Now, a first approximation of our goal might look something like this:


private Map handlersMap = new HashMap();

public MyInvocationHandler(Object realObject) {
this.realObject = realObject;

handlersMap.put("foo", new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// special code for foo()
}
);

// add mappings for bar(), baz(), etc..

}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
InvocationHandler h = (InvocationHandler) handlersMap.get(method.getName());

if( h != null ) {
h.invoke(proxy,method,args);
} else {
method.invoke(realObject,args);
}
}


Big friggin deal, right? So far all we've done is shifted most of the code into the constructor that builds up the map, and made ourselves look smarter by using some anonymous classes. But considering how much reflection we are using already, maybe we could ue just a bit more to get rid of some of those classes without having to re-introduce the old switch block. Maybe the map shouldn't contain a bunch of baby InvocationHandlers, maybe it should contain Methods. Our Methods! Since we are now dealing with methods more directly, we now need to know the signatures of the methods that we want to intercept, as well as their names. For this purpose, let's say Foo takes and int, bar takes a String, and baz is void.


private Map methodsMap = new HashMap();

methodsMap.put( "foo", getClass().getMethod("foo", new Class[]{ int.class });
methodsMap.put( "bar", getClass().getMethod("bar", new Class[]{ String.class });
methodsMap.put( "bar", getClass().getMethod("baz", new Class[]{ });

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method myMethod = (Method) handlersMap.get(method.getName());

if( myMethod != null ) {
// if it's in the map, run the one from the map
myMethod.invoke(this,args);
} else {
// otherwise just run the method on the original object
method.invoke(realObject,args);
}
}

public int foo(int x) {
// .. any custom stuff goes here ...
return (SomeInterface) realObject.foo(x);
}

public void bar(String s) {
// do nothing! hahaha
}

public boolean baz() {
throw new SomeException("you can't call baz()!");
}


Nice, huh? The above looks nifty, but it isn't quite correct.. the problem is that the SomeInterace/realObject might have multiple methods of the same name which again requires the argument types for disambiguation. So really method's whole signature should be the key to the HashMap. Now, you could just use an ArrayList or something to hold the name and the argument classes, but let's be nice to ourselves and make a helper class for this:


class MethodSig extends HashKey {
public MethodSig(Method m) {
super( m.getName(),
java.util.Arrays.asList( m.getParameterTypes()) );

}
}


MethodSig extends HashKey, which is one of the stupidest classes you could possibly imagine, but which I have actually written for use in real code. Someone please tell me that some new language feature in Tiger or later makes this class unneccessary!


public class HashKey extends AbstractCollection implements Collection, java.io.Serializable {

private Collection keys;

/** Creates a new instance of HashKey */
public HashKey(Object key1) {
this( new Object[]{ key1 });
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2) {
this( new Object[]{ key1, key2});
}

/** Creates a new instance of HashKey */
public HashKey(Object key1, Object key2, Object key3) {
this( new Object[]{ key1,key2,key3});
}

// repeat constructors for as many different objects as you might want..

/** Creates a new instance of HashKey */
public HashKey(Object[] keys) {
this( Arrays.asList(keys));
}


/** Creates a new instance of HashKey */
public HashKey(Collection keysToAdd) {
keys = keysToAdd;
}

public boolean equals(Object obj) {

if( !(obj instanceof HashKey) )
return false;

HashKey that = (HashKey) obj;

return keys.equals( that.keys);

}

public String toString() {
return keys.toString();
}

public int hashCode() {
return keys.hashCode();
}

public int size() {
return keys.size();
}

public Iterator iterator() {
return keys.iterator();
}

}


Now, using MethodSig, we get this:


public class MyInvocationHandler implements InvocationHandler {
private Map methodsMap = new HashMap();

private void addMethod(Method m) {
methodsMap.put( new MethodSig(m), m);
}

public MyInvocationHandler(Object realObject) {
this.realObject = realObject;

addMethod( getClass().getMethod("foo", new Class[]{ int.class });
addMethod( getClass().getMethod("bar", new Class[]{ String.class });
addMethod( getClass().getMethod("baz", new Class[]{ });
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method myMethod = (Method) handlersMap.get( new MethodSig(method) );

if( myMethod != null ) {
// if it's in the map, run the one from the map
myMethod.invoke(this,args);
} else {
// otherwise just run the method on the original object
method.invoke(realObject,args);
}
}

public int foo(int x) {
// .. any custom stuff goes here ...
return (SomeInterface) realObject.foo(x);
}

public void bar(String s) {
// do nothing! hahaha
}

public boolean baz() {
throw new SomeException("you can't call baz()!");
}
}


That code that repeated lycalls addMethod() is the last vestige or the original if/else block. How can we get rid of it? That's when the bolt of lightning hits you. Duh, these methods are declared right on our own class, we can use reflectioin to find them, and loop over them! Our code now becomes:



public class MyInvocationHandler implements InvocationHandler {
private Map methodsMap = new HashMap();

private void addMethod(Method m) {
methodsMap.put( new MethodSig(m), m);
}

public MyInvocationHandler(Object realObject) {
this.realObject = realObject;

Method[] methods = getClass().getMethods();
for(i =0; i<methods.length; i++) {
addMethod( methods[i]);
}
}

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method myMethod = (Method) handlersMap.get( new MethodSig(method));

if( myMethod != null ) {
// if it's in the map, run the one from the map
myMethod.invoke(this,args);
} else {
// otherwise just run the method on the original object
method.invoke(realObject,args);
}
}

public int foo(int x) {
// .. any custom stuff goes here ...
return (SomeInterface) realObject.foo(x);
}

public void bar(String s) {
// do nothing! hahaha
}

public boolean baz() {
throw new SomeException("you can't call baz()!");
}
}


Tada! We have essentially achieved the dynamic delegate pattern (which is accomplished in C++ using templates, and in dynamic scripting languages, etc.) using nothing but plain old reflection. No code generation, no bytecode maniplation, no generics required.

Next time, I will show you what the above ended up looking like after I spent several more iterations refactoring it.

something is right with America

On labor day I went to the Red Cross blood donor station temporarily set up at a local mall, and there was such a long line of people there that 4 hours ended up elapsing between when I put my name on the wait list and when I finally got stuck.

At least it was in the mall, so I could go to the food court and Waldenbooks, etc., while waiting. And like I said, waiting to give blood is a hell of a lot better than waiting to get blood.

People in other cities have told me that they experienced the same thing. More than one person has said that when they went to volunteer last week, they were put on a waiting list and told "don't call us, we'll call you".

I really hope that this represents a surplus of folks wanting to help, rather than a lack of proper organization to do something with them all.

Friday, September 02, 2005

mork.pl


# In Netscape Navigator 1.0 through 4.0, the history.db file was just a
# Berkeley DBM file. You could trivially bind to it from Perl, and
# pull out the URLs and last-access time. In Mozilla, this has been
# replaced with a "Mork" database for which no tools exist.
#
# Let me make it clear that McCusker is a complete barking lunatic.
# This is just about the stupidest file format I've ever seen.

Wednesday, August 31, 2005

Both bloglines and gmail were messed up this morning when I came into work. For once, I spent the first couple of hours of the day actually working!

Tuesday, August 30, 2005

no hurricane news here

Apparently my childhood house in Bayou La Batre is still standing, and flood waters did not reach it.

My family actually fled to Philadelphia, Mississippi of all places. I happened to be on the phone with my father last night when the actual eye passed over them. I have not heard from them today.

Don't know when they'll be able to go home. The website of one of their local TV stations reports:

AL 188 Closed Mobile PADGET SWITCH ROAD TO ALABAMA PORT WATER AND DEBRIS OVER THE ROAD.


That's the main street of Bayou La Batre, and I don't think there are any alternatives routes for it.

My dad works in Pascagoula. I'm not at all sure Pascagoula still exists.

done, for now

It doesn't look like I will be able to fool around with the Nintendo music for a while. My parents gave me a banjo for my birthday, and I want to spend time learning how to play it.

Because of this, I am declaring Flvxxvm Florvm is an 8-bit Whore to be a complete "album". There may be a sequel in the future. Right now there is only a little housekeeping to be done.

Towards that end ofI have re-named the MP3 files so that a normal directory listing puts them into the order in which they should be listened. This just happens to be the order in which I came up with them, punctuated by repeated occurrances of the Zelda death theme.

So you can now find the official, complete set of songs here:

http://www.cba.ua.edu/~matt2/flvxx/8bit/

Also provided for you convenience, this playlist streams all the songs directly off the server to your player with no delay to download the songs themselves. Although if you've been reading all along you probably already did that.

Thursday, August 25, 2005

The Chosen Beers

Schmalz brewery, home of two "HE'BREW" Kosher beers.

Geograph British Isles - photograph every grid square!

The Geograph British Isles project aims to collect a geographically representative photograph for every square kilometre of the British Isles and you can be part of it.

Wednesday, August 24, 2005

one good thing about my job

You can use Space Invaders graphics in a presentation, and it strengthens rather than weakens your credibility.
firewall invaders

Tuesday, August 23, 2005

Tom Ball's Blog: Finally, a Good Use for Finalizers

Look familiar, Scott?

Wednesday, August 17, 2005

The Non-Expert: IKEA, by Matthew Baldwin

Now you are in a maze of twisty little passages, all alike. A skeleton, probably the remains of a luckless consumer, lies here. Beside the skeleton is a rusty SKARPT high-quality steel knife with hard plastic handle and a shopping cart. Search the body. Take the IKEA GIFT CARD (still has $43 on it). Take and eat the SWEDISH FISH for sustenance. Now go:

S, E, D, D, E, SW, W, SW, D, W, U, S.

Tuesday, August 16, 2005

eclectech

The British-est flash animations ever.

Monday, August 15, 2005

I owe David Chandler a coke

For some reason I thought CreateObject was added to CFML in CFMX. Nope:

http://livedocs.macromedia.com/coldfusion/5.0/CFML_Reference/Functions47.htm#1102324

Saturday, August 13, 2005

Seanbaby.com - EGM's Crapstravaganza: The 20 Worst Games of All Time

I'm sure I blogged this a long time ago, or saw it on somebody else's blog, or on Slashdot, or something. Anyway, tell yer mom I said "Custer's Revenge".


Sing Loud Sweet Stereo

I know I promised to get out the slide and get nasty, but instead I decided to stick with last time's Zelda music and deliver a full-blown power ballad.

http://www.cba.ua.edu/~matt2/flvxx/8bit/sing_loud_sweet_stereo.mp3

Consider yourselves lucky to have gotten by with just a power balled. I had originally planned to write a genuine Gospel song, and attempt to sing 4-part harmony through the magic of overdubs, for the section starting at 3:22.

it must be fate but it should be a crime
my heart is yours but yours is not mine

i lost my mind and i'd give my soul
for a chance to have you once to hold

i know you love another man
and you are going to take his hand

sing loud sweet stereo
i need a little music to get me through the sad times

sing loud sweet stereo
i need a little music to get me through the bad times

hold me close just for one time
i want this memory to last lifetime

you can't understand what i feel for you
but that's ok you don't need to

i can live with separateness
as long as you find happiness

sing loud sweet stereo
i need a little music to get me through the sad times

sing loud sweet stereo
just a little music to get me through the bad times

and let the music that you play
help me fill the lonely days
with a little bit of love and light
a little bit of love and light


These lyrics were written when I was in high school, about a real girl, who shall remain nameless here. They were originally written to a different tune, but I think Koji Kondo's music fits them better than mine did.

The title the song comes from a Reader's Digest article I read back in the 1980's, a tear-jerker about your kids going away to college. It also had lines about "the hanging gardens of Disco" and "whenever you come to visit, there will always be a fatted calf in the freezer".

The "love and light" was inspired by a line in 1987 horror flick "The Gate". Go rent it.

Thursday, August 11, 2005

Using the XMLHttpRequest Object and AJAX to Spy On You

Work related. Read later.

Tuesday, August 09, 2005

a brief interruption

This is not a Flvxxvm Florvm song at all, it is a mere 15 or seconds of music taken directly from (emulated) Legend of Zelda, modified only by having it fade out smoothly and delaying the right channel ever so slightly to make it sound more 'stereo'.

In the game, this is the music that you hear after you die, before you choose from one of your saved games or start over again. It provides a momentary pause in the action, time to go the bathroom or get a drink or hand the controller over to someone else. And that is also it's purpose here.

http://www.cba.ua.edu/~matt2/flvxx/8bit/brief_interruption.mp3

When this "album" is finished, the final track order will insert this same 15 seconds of music between every couple of songs.

Why more than one song from the same game? Because Zelda is the best music of the 8-bit era. It stands up alongside "real" music, both popular and classical. That's my freaking opinion, and my opinion is the only one that counts here. You will hear more from Zelda before I'm done.

A Hero in Every Aisle Seat - New York Times

Registration (or BugMeNot) required.
If our leaders are really planning for panic, in the technical sense, then they are at best wasting resources on a future that is unlikely to happen. At worst, they may be doing our enemies' work for them - while people are amazing under pressure, it cannot help to have predictions of panic drummed into them by supposed experts.

Monday, August 08, 2005

ColdFusion MX 7 -- Validating form data using hidden fields -- Version 7

ColdFusion MX 7 -- Validating form data using hidden fields -- Version 7

Quite possibly the single most stupidest thing in any programming language, ever.

Thursday, August 04, 2005

Lookin' for Chicks

I wanted to use slide guitar on this song, but my daughter had taken my slide and hidden it somewhere, and I didn't find it until just now.

Not much to say about the lyrics, they are about as tastless as I'm willing to get without my slide. Next time, you're really gonna get it.

http://www.cba.ua.edu/~matt2/flvxx/8bit/lookin_for_chicks.mp3

Oh, yeah, almost forgot the game. You knew it was Donkey Kong. But I will point out that this is the NES Donkey Kong, not the Arcade. Can you hear the difference in the tembre of the opening "duh-duh-duh-duh doooooo-doooooo"?

Lookin' for chicks at Home Depot.
Lookin' for chicks among the boat people.

(Lookin' for Chicks!)
(Lookin' for Chicks!)

Lookin' for chicks in the elevator.
Lookin' for chicks in Decatur.

(Lookin' for Chicks!)
(Lookin' for Chicks!)

Lookin' for chicks who give second chances.
Lookin' for chicks who give lap dances.

(Lookin' for Chicks!)
(Lookin' for Chicks!)

java.net: Building Web Components Without a Component Framework

CategoryWorkRelated

Tuesday, August 02, 2005

Last time, I promise

One more change to Annie's Alibi. Through the magic of Audacity's "change tempo" function, I have kicked it back up to roughly the actual speed of the music in the game. I had previously slowed the whole thing down which not only dropped the key but also the tempo. In other words, I am now officially guilty of using digital processing to make it seem like I can play guitar 25% faster than I actually can.

Monday, August 01, 2005

decodeunicode.org

A Wiki with entries about individual Unicode characters. How geek is that? It appears to mostly be in German, though.

The Fixedsys font has no Euro glyph

And therefore if you are viewing this in IE or Firefox, instead of a big fat Euro, you'll will see a big fat square.



Opera, however does the right thing and displays the Euro symbol from a different font. Which font? How does it find it? I don't know, but it does it.

ŦĦ£ ώëñð¥ Ħõů$€

The most interesting thing about this blog is the title. It appears to be a modern Unicode-enabled version of the old DOS BBS practice I described here.

I don't know if this blogger has BBS connections, or if this kind of mis-use of international characters is just an obvious enough idea that people tend to invent it independently.

Saturday, July 30, 2005

I have remixed Annie's Alibi so that you can actually hear the Megaman music. After listening to it using several different pair of headphones, I realized that the game music was so buried in the mix as to not be noticeable. Since "Annie's Alibi" is the first song alphabetically, which means that least some folks will listen to it first, that was not a good thing.

Thursday, July 28, 2005

To Layer or not to Layer? That is the Architectural Question

/work /j2ee

Wednesday, July 27, 2005

Annie's Alibi

Not only is this song not about anyone I know named Annie, that name wasn't even what this song was supposed to be called. I wrote these lyrics while filling up my car at a gas station near my house, using the name of a flower shop that I saw across the parking lot. Unfortunately, I can't use that name for reasons that I can't even discuss on this blog. So Annie it is.

The lyrics are basic blues or country material, and I tried to blues it up as much as possible on the lead guitar. The game music is the "Crashman" level of Mega Man 2. It is slowed down quite a bit, to fit the speed at which I wanted to sing the lyrics. The choice to set these particular lyrics to this particular music was totally arbitrary, based purely on the fact that I wanted to use "Crashman" for something..

http://www.cba.ua.edu/~matt2/flvxx/8bit/annies_alibi.mp3



Annie don't you worry.
Annie don't you cry.
You know that I will always
be you your alibi.

I'll tell the judge and the jury
that you were layin' in my arms.
I'll them 'em that you were with me
the night your old man come to harm.

Annie what's the matter?
Did I offend your pride?
Can't you say that you love me
just to save your hide?

Annie I don't believe it.
Annie how can this be?
You're gonna point your little finger
and make a scapegoat out of me.

The judge done banged his gavel,
and soon I'm gonna fry.
But you know that I still love you.
And I'll still be your alibi.

I'll tell old Saint Peter
that you were layin' in my arms.
I'll tell 'im that you were with me
when your old man come to harm.

Monday, July 25, 2005

FIPS PUB 81 -- DES MODES OF OPERATION

File under: work related, security, crypto

Saturday, July 23, 2005

My Adrienne: a Legend of Zelda Murder Ballad

Like "Oh Jessica", this song has the name with a girl I knew in high school, but is most emphatically not *about* her.

The game music is subject to more manipulation than on previous songs. The two parts, "treble" and "bass" of the original mono track were separated by a complicated series of actions involving Audacity's "noise removal" plug-in. They were panned left and right, and their differences were exagerrated. The treble part was pitch-shifted up an octave. The bass (which carried the melody) was shifted down an octave, and then filtered until it was almost just a sine wave, then amplified and clipped to turn it into something more like a square wave.

I originally intended to have the guitar double the melody, but it was too hard to play. So then I tried to have the guitar double the high part, but that was hard too. So I gave up and overdubbed two acoustic guitars each playing different notes from the main chords. These guitars parts are on a loop so I wouldn't have to play them more than once. A third guitar comes in later, played straight through and not looped.

For whatever reason, I decided to let it start with just guitar and adds the game music after the first verse. This is a departure from all the other songs so far.

http://www.cba.ua.edu/~matt2/flvxx/8bit/my_adrienne.mp3


My Adrienne,
show me your face;
so out of place.

My Adrienne,
come to my room;
I'll seal your doom.

My Adrienne,
take off your clothes;
put on my robe.

My Adrienne,
drink from this cup;
it will wake you up.

My Adrienne,
why do you scream?
I'll set you free.

My Adrienne,
oh how you cry.
It's time to die.

Friday, July 22, 2005

Re: StaleCon


Thursday, July 21, 2005

Session Riding (PDF)

Not sure if I've blogged this before or not.
In this paper we describe an issue that was raised in 2001 under the name of Cross-Site Request Forgeries (CSRF) [1]. It seems, though, that it has been neglected by the software development and Web Application Security community

Tuesday, July 19, 2005

Down in the C64 Dungeon

Longtime Flvxxvm Florvm Fanclvb members will recognize this one. This is an attempt to return the FF classic "Down in the Dungeon" to something like the way originally written.

http://www.cba.ua.edu/~matt2/flvxx/8bit/down_in_the_c64_dungeon.mp3


There are two versions (here and here) , but the older of these was still recorded several years after the idea for the song germinated.

As you should know if you read my wonderful liner notes, the lyrics were originally going to be set to some of the music from the "Popeye" cartridge for the Commodore 64 (I'm pretty sure it was a cartridge, not a disk. I didn't even have the game, I remember I was playing it at someone else's house when I thought up the song).

So anyway, here it is, the actual (well, emulated) game music with those now well-worn lyrics and some poorly thought out guitar slapped on because, well, I'm a compulsive guitarist the way some people are compulsive liars. And fake handclaps provided by a drum that I borrowed from a friend in 1996 and have yet to return. (Why couldn't I have kept that Big Muff I also borrwed back then instead?)

This is a bit of a step down from the last two songs, I know. It has neither the mainstream appeal of "Kissed Your Ruby Lips" nor the rawk-n-roll excess of "Oh Jessica". It sounds almost like a children's song, or it might if you have very strange children.