Monday, March 23, 2009

Determine the Java TimeZone of your web visitors using client-side javascript

You want your Java web application to know what TimeZone your visitors are in. You can use client-side javascript code like the following to produce a timezone string that Java can understand:
function getTimezone() {
  var tzo = new Date().getTimezoneOffset();  //returns timezone offset in minutes
  function pad(num, digits) {
    num = String(num); while (num.length < digits) { num="0"+num; }; return num;
  }
  return "GMT" + (tzo > 0 ? "-" : "+") + pad(Math.floor(tzo/60), 2) + ":" + pad(tzo%60, 2);
}
This will produce strings like GMT-04:00 and GMT-07:00 which you can then pass up to the server and into TimeZone.getTimeZone() to produce a TimeZone object.

Thursday, March 19, 2009

Timing Oracle SQL queries with Glassbox

Glassbox, the slick AOP tool for automatically diagnosing your Java webapp's performance bottlenecks, first caught my eye nearly a year ago. In consulting activities, where off-the-shelf products and custom solution code mix, it can be very difficult to determine whose code is at fault when web pages load slowly.

Glassbox comes to the rescue by tracking each web request through every layer of the J2EE stack. It identifies slow requests and groups them by URL, then identifies the controllers, methods, database queries, network operations, etc. that are causing the operation to be slow. It comes packaged in a war file: just drop it into the app server, hit the webapp root from a browser, and let it autoconfigure itself.

The hitch I ran into was that Glassbox had trouble instrumenting our Oracle JDBC driver, so it couldn't identify the precise SQL queries that were causing slowness. I went to the forums initially, then forgot about it for a while when an answer wasn't readily available.

I became interested again over the past couple days, so I contacted Ron Bodkin directly: he suggested the AspectJ load-time weaving is probably at issue. He gave me some quick pointers on how to use the ajc tool to create an instrumented version of the Oracle JDBC driver so that it wouldn't need to be instrumented on the fly at load-time. I gave it a shot and it worked!

In testing, I purposely crafted a slow query by using a ridiculous number of pointless joins, to verify whether Glassbox would call me out on it.

The cookbook

First, grab Glassbox 2.0 and AspectJ 1.5.3. (To do offline weaving you'll need aspectjtools.jar, which doesn't ship with Glassbox).

Create a project directory and drop in the jar file you want to weave. Then create a lib/ subdirectory. Add aspectjtools.jar from the AspectJ download, and then explode glassbox.war into it. Find ./lib/glassbox.war/install/glassboxMonitor.jar and extract the file META-INF/Xlint.properties from it; place it in the root directory of the project.

Finally, run the following ant script:

Note: Adjust your path to AspectJ as needed.

Things to study when I get a minute

Some of the things I'd like to spend more time with:

Tuesday, March 17, 2009

Reason #82734 why I hate Oracle JDBC drivers

Are you wondering why the date/time values you read from Oracle 10g's jdbc driver are off by several hours? It's because the 9i/10g drivers don't properly account for the jdbc client's time zone when writing the date value.

So what's the fix?

Suppose you know your server date/time values are stored in GMT. You can call getTimestamp() with a GMT calendar, and then you'll get the right values.

public class OracleJdbcDriverSucks {
  public static Calendar GMT_CALENDAR = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

  public static Date getGMTDate(ResultSet rs, String column) throws SQLException {
    return new Date(rs.getTimestamp(column, GMT_CALENDAR).getTime());
  }
}