Java Class.forName(String className) and JDBC

A reader asked a question via a comment a couple months ago that I didn’t really have an answer for (and had always kind of wondered the same thing). In the original post (which showed how to use JDBC with ColdFusion), I used the following snippet of code:

Class.forName("jdbc.DriverXYZ");
Connection con = DriverManager.getConnection(url,
  "myLogin", "myPassword");

and the reader wanted to know what the Class.forName(..) method did. The most common answer you’ll hear is that it loads the database driver, which, while technically true, is shallow. Where does it get loaded? How does it happen? And why?

To answer the question I started with the JavaDoc for the Class.forName() method. According to the documentation, the method:

… attempts to locate, load, and link the class or interface

I wasn’t perfectly clear on what “locate, load, and link” meant, so I did a little digging through the Java Language Specification. According to chapter 12 of the JLS:

Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a compiler, and constructing, from that binary form, a Class object to represent the class or interface.

Next, again according to the JLS, it must be transformed from it’s binary representation to something the Java virtual machine can use, this process is called linking. Finally, the class is initialized, which is the process that executes the static initializer and the initializers for static fields declared in the class.

So then back to the original problem, when Class.forName() is called with an argument like this:

Class.forName("org.gjt.mm.mysql.Driver");

the classloader attempts to load and link the Driver class in the “org.gjt.mm.mysql” package and if successful, the static initializer is run. The MySQL Driver (download the source code) static initializer looks like this:

static {
  try {
    java.sql.DriverManager.registerDriver(new Driver());
  } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
  }
}

So it calls a static method in the java.sql.DriverManager class which apparently registers a copy of itself when it loads.

So now I understand the where and the how, what about why? To understand the why you have to look at the next line in the initial code example:

Connection con = DriverManager.getConnection(url,
  "myLogin", "myPassword");

The DriverManager class (view DriverManager source here) returns a database connection given a JDBC URL string, a username and a password. In order to create that connection, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it (ie: the registerDriver(Driver driver) method illustrated above) and calls the acceptsURL(url)) method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL.

So there you have it. Class.forName explained.

Links: 7-29-2005

Adaptive Path interview with Jared Spool: how to ask questions

Great story from an interview that Adapative Path’s Peter Merholz did with the founder of User Interface Engineering Jared Spool:

PM: Any other mistakes, in terms of how tests are structured?

JS: There are many problems I see in terms of people not
understanding the effects of testing affecting results.
Here’s a simple example that we discovered. We were working with a
client, testing a website that sold furniture. And the client had
already done some testing. They had created some simple tasks, and
one of the tasks was basically asking users to come to the site and buy
a bookcase they might want to buy.

Every user in that study went to the search box, and typed in the word “bookcase,” immediately. So they were off trying to improve the hits on the word “bookcase,” and get the results better. We did a subsequent test, and instead of asking people to look for a bookcase, we gave them a slightly different task.

We said imagine you have 300 different paperback and hardcover books in
cardboard boxes, all strewn through your living room. You need a way to
organize this stuff such that you can find the stuff you like, and
people who come over can be impressed with your collection. What do you
do? People would go to the site, and then click on links. They’d click
on furniture links; they’d type into the search engine storage systems,
and then type in shelves. Not a single user in our phase of the study
typed in the word bookcase. So by changing the description of the task,
we got a completely different result.

Asking the right question really is half the battle.

del.icio.us poster

Last month I wrote about a quick utility which uses the delicious-java and Apache XML-RPC libraries to grab posts from my del.icio.us account and post them to my Metaweblog enabled (in my case Movable Type) blog. I’m not sure that it’s useful unless you have your own server or always on desktop PC, but I wasn’t satisfied with the original product, so I updated it with better documentation, a license (GPL), an Ant build file and the ability to edit the format of the posts using a Velocity template. Oh, and it’s all in Subversion now. You can read all about it by checking out the del.icio.us poster project page.

Links: 7-11-2005

ASP.NET: The resource cannot be found.

Spent some time today buried in IIS trying to figure out why an ASP.NET application would throw the following error message for every single page that existed in an application within a website:

Server Error in ‘/myapp’ Application.
—————————————————-
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested Url: /myapp/default.aspx
—————————————————-
Version Information: Microsoft .NET Framework Version:1.1.4322.2032; ASP.NET Version:1.1.4322.2032

Googled for “resource cannot be found” and found this link on the third result page. In it Jarrett mentions that he solved the problem by reading this experts-exchange.com question which suggests setting up the application as a Virtual Directory in IIS instead of simply marking the folder in the website as an application, which of course solved the problem for me as well. Since a picture is worth a thousand words, here’s the difference between a Virtual Directory (which is an application in and of itself) and directory in IIS that has been marked as an application:

virtual_directory.gif

directory.gif

My suspicion is that the problem has to do with ASP.NET configuration inheritance settings with Virtual Directories not inheriting from parent directories like a folder marked as an application would, but there isn’t much to go on. Any Microsoft IIS experts out there want to talk about the difference between a Virtual Directory and a folder that has been marked as an application from a configuration standpoint?

Trailing Slashes, IIS and F5 / Big-IP

We’ve had a problem on our websites at work for the last couple years where if a user doesn’t use a trailing slash when visiting a directory, ie:

http://www.hostname.com/mydirectory

the user gets a “The page cannot be displayed” error. The problem is that if you don’t use a trailing slash IIS sends a redirection to use the trailing slash:

REQUEST
---------------------
GET /mydirectory HTTP/1.1
Host: hostname.com


RESPONSE
---------------------
HTTP/1.x 302 Object Moved
Location: http://hostname.com:xxx/mydirectory/

Notice that the redirect includes the port designation? We run multiple websites on a single box and (for reasons beyond me) we don't use host headers so we have to use non standard ports in IIS. In the case above the web server thinks it's running the site on port xxx, which it technically is, but the world doesn't see that, nor can it use that port to access the site. At the time I thought it was the F5 that was redirecting users inappropriately, but there was nothing on the F5 website to back that up. There is now: How do I stop redirects from the web server behind BIG-IP?

In short, any website (IIS or Apache) running behind the F5 / Big-IP that is not using port 80 will show this behavior, there are a couple fixes:

a) use an IIS ISAPI filter (or mod_rewrite on Apache) to rewrite the redirects

b) use an F5 / Big-IP port redirect rule

c) use an F5 / Big-IP trailing slash redirect rule

If you read the tech note you'll see that Option 'b' will result in 2 redirects (client requests hostname.com/mydirectory --> IIS redirects to hostname.com:xxx/mydirectory/ --> Big-IP redirects to hostname.com/mydirectory/) and also lets any technical users know which port we're running on websites. Option 'c' is mentioned in the tech note as being the last gasp: "F5 Networks recommends using this rule only if there is no other alternative" so I chose option 'a'. There is a free ISAPI rewrite engine called (conveniently) ISAPI_Rewrite from helicontech.com. I installed it and then added the appropriate rewrite rule:

RewriteCond Host: (.*)
RewriteRule ([^.?]+[^.?/]) http\://$1$2/ [I,R]

and everything works again. Balance has been restored to the world.

Links: 7-7-2005