A new job on the other coast

May 23rd, 2008

After spending most of my life in school—I’m now in the 21st grade—and working for the last half-decade on a Ph.D., my career as a student is nearly at an end. It’s time to find a new one.

For a while, I seriously considered life as a professor, but as a graduate student I saw how the sausage was made, so to speak. It’s not all teaching and research. Professors spend a large portion of their time searching for funding, performing administrative tasks, and struggling with departmental politics. For some, these chores are a small price to pay for the chance to live on the cutting edge of science, train talented students, and possibly become famous in their chosen field. For me, however, having to write grant proposals and surrendering to the publish or perish system takes the fun out of academia.

Instead, I decided on an industry job. It wouldn’t offer as much flexibility and independence as being a professor, but it pays a little more and the hours are more predictable. (I’d never have to kill a weekend grading papers, for instance.) Plus, industry offers something academia can’t: instant gratification. With academic research, I may have to wait ten or even twenty years to see whether my ideas lead to a genuine scientific advancement or just another chapter in the annals of obsolete academic research. I can’t be sure that my hard work will ever have an impact on people’s everyday lives.

An industry job, on the other hand, offers immediate impact. Think about the engineers who built, say, Gmail or the iPhone. These products aren’t exactly technological breakthroughs, but their creators have the satisfaction of knowing that their work benefits millions of people every single day.

I had that feeling once, many years ago, when I worked for a tiny startup company in St. Louis. We were building a handheld medical device for early diagnosis of hearing problems in newborns. It was a remarkable feeling to know that my work would soon end up in the hands of pediatricians all over the country.

In January, I started on a journey to get that feeling back. First, I updated my résumé and uploaded it to a few of the mainstream job sites like CareerBuilder and Monster. Soon my inbox was full of email from staffing agencies, but most of the offers were for web development, user interface design, and application programming, nothing particularly exciting.

Next, I contacted a few companies directly. I’ve always admired products from Google, Apple, and Sun, and just as importantly, they have a company culture that appeals to me. All three are very open-source friendly, for example. I sent them a copy of my résumé and was lucky enough to get a call back from each of them for a job interview.

My luck ended there. After the interviews, Apple said that my “interests and skill set lie elsewhere”; Sun told me that “your work and our needs don’t really match”; and Google somehow decided on the basis of a phone interview that my computer programming skills weren’t on par with their standards.

Eventually, I secured offers from a few other companies, but I wasn’t really fired up about any of them. By now it was April and I was running out of time. Not only was my fellowship funding set to expire, but I was nearly finished with my Ph.D. anyway. I needed to make a decision soon, so I pulled out my job hunting notes for one last look. Maybe I had missed something.

Mixed in with my list of prospective companies was a curious entry that sounded like something out of an Isaac Asimov novel: Perrone Robotics. I wondered why I hadn’t contacted them before. I knew I had planned to, but somehow I never got around to it. I sent them my résumé.

The next day, Paul Perrone called me, and we spoke for an hour about his company, my background, and where the two intersect. Soon afterward, he invited me to Charlottesville, Virginia, where Perrone Robotics is based, to meet the team and learn more about the projects they were working on. One week later, Paul offered me a job, and I accepted.

Even if Google, Apple, and Sun had all offered me a position as well, I probably still would have chosen Perrone Robotics. Getting paid to build bots and autonomous vehicles is more or less my dream job. The opportunity for this kind of career is exactly what brought me back to school as a graduate student in the first place. The work is also a good match for my skills because the company’s technology is built entirely around real-time Java, which happens to be the focus of my Ph.D. dissertation.

I’m not the only one excited about Perrone Robotics. Paul’s choice of technology has recently caught the eye of Sun, the company that created Java. For each of the last three years, Sun executives have invited Perrone and his team to present their work at JavaOne, the annual developer conference for all things Java. The executives probably believe, quite rightly, that remote-controlled helicopters and driverless cars are a more exciting demonstration of Sun’s technology than the usual fare of web services, mobile phones, and enterprise frameworks that have traditionally been Java’s purview.

You can judge for yourself by watching the videos below, where Paul gives the JavaOne audience a taste of real-time robotics. (The MC in these videos is none other than James Gosling, best known as the father of the Java programming language.)

Perrone Robotics — JavaOne 2006

Perrone Robotics — JavaOne 2007

Perrone Robotics — JavaOne 2008

The next step for me is to pack up my belongings and get ready to leave Irvine, California, which has been my home for the last five years. The trip will take me to the opposite side of the country, more than 4000 kilometers away, to a new home and, I hope, the start of a satisfying new career.

A LaTeX template for UCI dissertations

January 8th, 2008

Like most universities, UCI has a strict set of rules for formatting and typesetting doctoral dissertations. The rules fall into the usual categories of margin, typeface, and layout guidelines, as well as some unique requirements for copyright declarations, the signature page, a curriculum vitae, and so on. A complete list is provided in the UCI Thesis and Dissertation Manual.

With so many requirements in this 43-page manual, starting out on the first draft of a dissertation can be rather daunting for Ph.D. students, especially since improper formatting could get the manuscript rejected by the University Archives. A word processor template would virtually eliminate this problem, but according to the AGS website, UCI provides no officially-sanctioned template for dissertations. Each student must format their manuscript from scratch, leading to duplicated effort and wasted time.

A few enterprising students have responded to this problem by creating unofficial UCI dissertation templates. They are designed specifically for LaTeX, a document preparation system favored by EECS and ICS grad students for its computer language affinity, extensive support for mathematical equations, and high-quality typesetting. By starting off with such a template as the foundation, writing a UCI dissertation essentially becomes a fill-in-blank process as LaTeX takes care of the table of contents, list of figures, and other formatting details automatically.

Xianping Ge created the first such template in 2002. It was later refined by Jeffery von Ronne and is now available on Vivek Haldar’s blog. Working separately, I started with Xianping’s original template and made my own set of clean-ups and enhancements with help from Mark Panahi. It improves upon Jeffrey’s version by adding a CV template, extensive comments to help the Ph.D. student fill-in and customize the template, and various minor fixes. In addition, I reviewed every aspect of the template to make sure that its output conforms to the Dissertation Manual as closely as possible.

The template can be downloaded by following the link below, which leads to a ZIP file containing the template, its LaTeX class file, a makefile for generating a PDF of the dissertation, a sample bibliography, and a “readme” file with more details on how to use the template. The link will be updated as new versions of the template become available.

LaTeX template for UCI dissertations
Last updated: April 14, 2008

Convert a servo into a high-torque motor

December 29th, 2007

Small robots have been household gadgets for decades, but until recently they’ve been little more than toys. With a limited range of motion and almost no interaction with their environment, a task as simple as moving from one point to another without bumping into something was too advanced for these early bots.

In the last few years, however, these “toys” have become far more sophisticated. Lifelike humanoid bowlers, dinosaurs with personalities, and robotic dogs that recognize spoken commands are now mainstream products. Even the old-fashioned interlocking plastic brick has gone high-tech with motors, sensors, and programmable circuits.

The miniaturization of these circuits and sensors has certainly played the biggest role in making small robots increasingly intelligent and capable, but a lesser-known supporting player is the humble servomechanism. More commonly known as a servo, it’s essentially an electric motor combined with positional feedback. The servo knows how far it has turned and is able to respond to electronic commands such as: “Turn 60° left of center.” This feature makes the servo ideal for arm and leg joints, sensor scanners, and other robotic accouterments.

With the increasing demand for robot kits and toys, the performance and diversity of servos has been growing. There are now jumbo-sized servos (about 7 centimeters long), micro servos (some as small as 3 grams), servos with metal gears (for extra-heavy loads), and all kinds of torques, speeds, and packagings. There’s even a SERVO Magazine that covers the burgeoning community of robot-building, servo-hacking hobbyists.

But like any electronic device, servos have limitations. They can’t drive a robot wheel, for example, because servos don’t rotate continuously like a normal motor. Instead, to keep their design and construction simple, they allow rotation only through 180° or so (although some advanced models can do up to 360°). Providing both the position control of a servo and the speed control of a motor would make the servo’s electronics and signaling too complex. After all, if a robot’s design calls for a wheel or other continuously rotating device, a traditional motor can always do the job.

Ironically, though, thanks to improving technology and falling prices, servos are probably the cheapest type of geared motor on the market, especially after factoring in the speed control circuitry (an H-bridge) that comes built-in with every servo. In fact, servos often provide higher power in a more compact package than comparably priced motors. The only catch is that a servo is still a servo: It can’t spin continuously the way a normal motor can.

Luckily, there’s a relatively easy fix for this problem. Because servos are basically a motor with a feedback loop, simply disconnecting the feedback opens the loop. Without feedback to tell the servo it has reached a desired position, it will just keep on turning. The servo effectively becomes a continuously rotating motor that just happens to have a speed control circuit and gearbox conveniently attached to it.

Although this hack is a great way to save money—just convert old unused servos instead of buying new motors—the full conversion process isn’t quite so simple. There are additional complications to deal with, such as the cylindrical stop on the output gear that prevents full rotation. The feedback circuit that detects the angle of rotation (usually a simple potentiometer) also has to be anchored to a neutral position so that it doesn’t accidentally generate feedback signals, causing the servo to turn spontaneously.

A variety of tutorials explain how to get around these problems (search for “modify servo continuous rotation”), and some manufacturers even sell servos pre-modified for continuous rotation. Unfortunately, after starting a project for a two-wheeled self-balancing robot (like a mini-Segway), I consulted a variety of these tutorials and found them inadequate. None addressed the issues of a metal-geared servo, which I happened to be using, nor did they explain the difference between driving the motor with a traditional H-bridge circuit rather than a servo controller.

After struggling through these obstacles, I was finally able to complete the modifications, but not without some confusion and setbacks. To save others from the same kind of trouble, I’ve written the following tutorial on how to modify a servo for continuous rotation. While similar to existing tutorials of this kind, it goes into a bit more detail than most and, given the wide variety of servos available, having another perspective on the process couldn’t hurt.

This tutorial deals specifically with the standard-sized GWS S03T servo, a rather high-end model with metal gears, dual ball bearings, and an extra-high gear ratio that provides almost double the torque of a typical servo. The metal gears improve strength, while the ball bearings ensure smoother rotation and better centering. Note that the addition of these features does not alter the basic design of the servo, which is remarkably similar across manufacturers and models, so the advice offered in this tutorial should be widely applicable.

The first step is to remove whatever horn or arm happens to be installed on the servo. (The S03T ships from the factory with a standard wheel attached.)

Next, remove the body screws. Be careful not to strip the grooves off the screw heads.

After removing the body screws, pull off the top of the case to expose the gears.

Now remove the output gear and the top center gear, taking care not to lose any of the tiny parts. In this particular servo, removing the output gear should expose one of the two ball bearings. (The other should have come off when removing the top of the case and is most likely still lodged inside of it, underneath the opening.)

Turn the output gear over and you should see a plastic slot. This piece connects the potentiometer to the geartrain so that every turn of the servo also turns the potentiometer, thus providing positional feedback. This is how the servo knows when it has reached the desired angle and should stop turning.

The goal here is to transform the servo into a motor, so the feedback needs to be disabled. To do so, simply remove the plastic slot; it should pop right off.

Now, turn the output gear right-side up and note the small cylindrical stop. It mechanically prevents continuous rotation of servo, so it has to be removed. If this gear were made of plastic, the stop could be removed rather easily using a tiny saw, wire cutters, or perhaps even fine-grained sand paper.

With a metal gear, however, removal is more difficult. After many attempts at yanking the stop out of its socket, I eventually had to grind it clean off using a rotary tool. (Be careful not to grind too far into the gear itself. You can see in the picture that I accidentally shaved off part of the gear shaft’s base.)

Note that other tutorials describe an additional step at this point: Replacing the feedback potentiometer with a voltage divider, composed of two resistors, to fool the servo circuitry into thinking the potentiometer is still connected and fixed at the center position. This feat is rather tricky, though, because the exact values for the resistors must be determined by calibrating the servo at its center position and then measuring the resistance across the old potentiometer. An alternative approach, one that works on this servo and probably many others as well, is to manually rotate the potentiometer shaft to its center position, then simply glue it in place! This will achieve the same effect of convincing the servo that it hasn’t reached the requested angle and will thus continue to rotate.

After removing the gear stop, disconnecting the feedback potentiometer, and fixing it in place (either electrically with a voltage divider or mechanically with glue), the modifications are complete. You can now reassemble the servo and send it the usual PWM signals from a servo controller. These signals formerly told the gears which angle to move to; now they control how fast the gears should rotate and in which direction.

But the story does not end here. The original servo motor driver circuits are still in the loop, and this could cause problems. The electronics in a servo are usually designed for the sporadic, off-and-on operation of normal servo usage, not the continuous spinning of a motor. They might not be able to handle the constant activity and could eventually burn out. Also, the controllers that generate PWM signals for a servo typically have higher latency than a standard DC motor driver, especially if it’s a serial servo controller that has to perform the extra step of translating RS-232 signals.

So what’s the solution? Simply rip out all of the electronics from the servo, thereby converting it to a simple geared motor. You will then have to drive it with a standard H-bridge motor controller rather than a servo controller, but you will likely gain faster response time and minimize the chances of early burn-out.

To begin the lobotomy, pry off the bottom of the servo’s case.

Next, turn the servo upside down and note the location of its circuitry.

Cut away the hard tacky glue that holds the circuitry in place, then carefully pull it out.

Now cut off the electronics to complete the lobotomy. (The black piece shown in the picture connects the potentiometer to the output gear. It fell out when removing the electronics, but since potentiometer feedback isn’t needed after this conversion, it can be discarded.)

At this point, you have a choice to make. You can either splice the wires together, or you can remove the motor’s wires entirely. The first option is simpler but might be unreliable depending on how you splice the wires. The latter option requires more work, but it gives you the option of using your own wires, and you can solder them for a more permanent hold. I chose to remove the motor’s wires and attach the original external servo wires directly to the motor. The first step was to scrape off the hard tacky glue off the terminals, then use a soldering iron to melt the solder and remove the wires.

Now you can solder the external servo wires—or any other wires, depending on your needs—directly to the motor. (My soldering job in this picture was quite messy; don’t think I’m trying to pass this off as a good example of a soldered joint!)

Finally, reassemble the servo case and put the gears back on. (Don’t forget to return the two ball bearings to their original locations.) You now have a servo-sized motor with a high-torque metal geartrain in a nice tidy package!

Here’s a short video of the motor in action.

Thanks to Adam Borrell for his helpful advice that made this tutorial possible.

What I Want On My Tombstone

November 1st, 2007

 

Trevor Harmon has gone offline

Research Planet

August 17th, 2007

As a new graduate student, one of the first things I learned was that the success of a researcher depends on the publish-or-perish model. It’s not a perfect system, but the pressure to generate publications of truly novel ideas does tend to motivate cutting-edge research. The peer-review process also provides valuable objective feedback for researchers, and it usually prevents low-quality work from being published. As a result, publication frequency has become—for better or for worse—the primary method of judging a researcher’s status and ability.

With the advent of the Internet, finding these publications has become a much simpler task. Spiders such as CiteSeer and Google Scholar, as well as publisher databases from IEEE and Springer, can find relevant publications with a simple keyword search. Some sites even offer vital statistics, such as the number of times a paper has been cited, to help judge the importance of the work. These tools are an enormous help when researching a topic.

But what happens when the research is done and it’s time to publish your own work? Surprisingly, finding a relevant conference or journal is often more difficult than finding a relevant publication. Searching the web can help, but you might overlook new or esoteric venues. For a more comprehensive search, professional organizations provide complete lists of the conferences they sponsor, but these too are limited. For instance, the ACM conference database doesn’t list IEEE events, while the IEEE database doesn’t list ACM events. And neither web site has any knowledge about conferences outside of their respective fields.

Making matters worse, some conferences have been accused of being “fake,” lacking any form of peer review and accepting all submissions (even randomly-generated papers) simply to make a profit. Journals, too, have been known to spam researchers with offers to publish in exchange for a fee. Given the key role that conferences and journals play in the integrity of research, these trends are disturbing.

After several years of dealing with these issues, always feeling a bit in the dark when it came to keeping track of research venues, I finally decided to do something about it: I created Research Planet, an independent, cross-discipline source of information about conferences and journals. Designed to make the life of a researcher easier, it offers:

  • A searchable database of venues with filtering by acceptance rate, submission deadline, and other criteria
  • A global, interactive map to help you locate upcoming conferences in your region of the world
  • A calendar of events (available for importing into Apple iCal, Google Calendar, and other calendaring applications) so that you’ll never miss another submission deadline
  • A forum for discussing conferences and journals
  • Customizable web feeds to keep you informed of new venues and other updates to the Research Planet database

Over time, I’ll be adding additional features, such as user comments, a rating system, photo handling, and more. I also plan to import conference data from other organizations, making the Research Planet database more comprehensive. Together, these features will help you find the best place to publish your work.

Research Planet

The Kansas City standard

March 16th, 2007

During episode #66 of This Week in Tech, host Leo Laporte reminded his fellow pundits that August 2006 marked the 25th anniversary of the IBM PC. It cost $1565—a fairly inexpensive computer in those days—but Leo noted that’s because it didn’t come with a hard drive, only a cassette port. John C. Dvorak immediately asked, “Does anyone remember if that used the Kansas City standard?”

My reaction was the same as Leo’s: Kansas City standard? Is that a joke? I grew up in K.C. and have lived there most of my life, and yet I’d never heard of such a thing.This thirty year-old standard was actually fairly revolutionary. According to Wikipedia, it was one of the first standards to allow consumer-quality audio cassettes to store computer data. It was thus a catalyst in the rise of the personal computer, offering home users inexpensive data storage at a time when floppy disk drives cost around $1000.An example comes from personal experience. I recall my dad’s old TI-99/4A having a cassette port to which he had hooked up an even older portable tape recorder. I’d use it to save my little BASIC programs and whatnot. I could turn off the computer then come back the next day, playback the tape, and pick up where I left off…hopefully. (As Leo says, those cheap tapes weren’t particularly reliable.)Despite reliability issues, the Kansas City standard remained influential. It even spawned a completely new type of computer data storage: vinyl records! That’s right; old-fashioned 33⅓ RPM records were once used for recording high-tech digital data—formatted according to the Kansas City standard, of course.

Kansas City floppy

And all this time I thought my home town was known only for its barbecue and jazz

The earliest pop-culture Peace Corps reference?

February 26th, 2007

The Peace Corps is a household name. You can ask almost anyone in America if they’ve heard of it, and they’ll probably answer in the affirmative. I’ve always wondered how this small federal agency could have such a huge impact on American culture, but I think it comes down to three basic factors:

  1. It’s exotic. Although many have heard of the Peace Corps, most don’t know exactly what it’s all about. There seems to be a romantic stereotype that Peace Corps volunteers are sent to some tropical village to live in a mud hut and teach the natives animal husbandry or some such skill. (The reality these days is that volunteers are more likely to end up in a city teaching computer literacy, but the stereotype lives on.)
  2. It’s old. Established in 1961, America has had plenty of time to learn about the Peace Corps, and nearly 200,000 returned volunteers have had ample opportunity to spread the word around. In fact, the Peace Corps has been around long enough that it’s even had its own postage stamp.
  3. Peace Corps stamp
  4. Hollywood loves it. I suspect this factor has had the single greatest impact on making the Peace Corps a household name. I’ve lost count of how many references to it I’ve seen on TV and in movies, each one helping to cement a place for the Peace Corps in American culture. My favorite is this segment from the movie Airplane! (click to play).
Airplane!

Filmed in 1978, I had thought that Airplane! was perhaps the earliest pop-culture reference to the Peace Corps. Last week, when I happened to rent The Pink Panther from GreenCine, I discovered I was wrong.

Playing a supporting role in the film was Robert Wagner, better known to today’s audiences as Number Two from the Austin Powers series.

Number Two

In the scene below (click to play), note how Wagner casually mentions the Peace Corps. Moments later, David Niven enters and also drops the Peace Corps name as if it were common knowledge.

Pink Panther screen cap

What shocked me about this scene was the date: The Pink Panther was filmed in 1963, just two years after the Peace Corps was established! It could very well be the first reference to the Peace Corps—ever—in mainstream popular culture. Perhaps even more surprising is how nonchalantly the Peace Corps is mentioned, as if everyone knows what it is.

So, contrary to what I had assumed, the longevity of the Peace Corps may have had little to do with its status as a household name. Judging by this clip, it became well-known almost as soon as it was created.

A set of scripts to unmount drives before sleeping

February 11th, 2007

When I’m at home, my MacBook Pro is hooked up to an external display, a couple of hard drives, and other peripherals. When I need to go on the road, I put it to sleep, unplug all the peripherals, and away I go.

There’s only one problem: Unplugging a hard drive can corrupt its filesystem if it’s still mounted. To prevent that from happening, I wrote a script that automatically unmounts all drives. As an added bonus, the script fails if any of those drives are busy and can’t be unmounted, warning me to take additional action before hitting the road. Here it is:

tell application “Finder”
    eject (every disk whose ejectable is true)
end tell

In most cases, this simple script works great, but it suffers from a few drawbacks:

  1. It ejects not only hard drives, but optical discs as well, which is usually not what I want.
  2. It won’t eject remotely mounted drives, such as NFS or AFP mounts.
  3. It won’t work if Finder is not running, which may be the case for PathFinder users like myself.

To fix these issues, I split the script into two parts, one for local drives and one for remote drives, and I rewrote it so that optical discs would be left alone. Here’s the part that unmounts local drives:

-- Set this list to the names of the local drives
-- you want to unmount
set local_drives to [“Backup drive”, “Clone”]

repeat with drive in local_drives

   set drive to “/Volumes/” & drive
   set driveExists to false

   try — Ignore AppleScript warnings
      do shell script “test -d ” & ¬
            quoted form of drive

      — Test completed successfully; drive exists
      set driveExists to true
   end try

   if driveExists then
      — Eject the drive
      do shell script “umount ” & ¬
            quoted form of drive
   end if

end repeat

And here’s the part that unmounts the remote drives:

-- Set this list to the names of the remote drives
-- you want to unmount
set remote_drives to [“DreamHost”, “DOC”]

repeat with drive in remote_drives

   set drive to “/Volumes/” & drive
   do shell script “umount ” & ¬
         quoted form of drive

end repeat

I don’t eject optical drives, but if for some reason you need to do so, here’s how:

-- This will eject the optical disc in the
-- primary (built-in) drive
do shell script “drutil -drive 1 eject”

-- This will eject all discs in all optical drives
do shell script “drutil eject”

For a downloadable version of these scripts, see my AppleScript page.

A tourist trap in Ghana

January 23rd, 2007

It’s not every day one hears about Ghana. Most Americans don’t know where it is, and many don’t even know it exists. The only mainstream media that gives Ghana any attention is the BBC News, but their stories are almost always soccer-related: a Ghanaian player transfers to a European club, a coach for the Black Stars gets fired, that sort of thing. As a returned Peace Corps Ghana volunteer, I’m a little disappointed the country doesn’t get more press.

That’s why, when watching ABC World News Tonight last December, my mouth dropped open. Charles Gibson suddenly started talking about Ghana! The story, from London-based correspondent Mike Lee, was all about Paga, a small town far in the northeast that is famous for one thing: crocodiles.

Note that Mike mispronounces the town’s name: It’s pägä, not pāgä. (Surprising, given that he actually visited the place.) Otherwise, it’s a nice segment that provides a fun glimpse into Ghanaian-style tourism. If you’re interested in even more scenes from Paga, check out the videos Straddling a Crocodile and sight n sound from the jungle.

These videos are especially fascinating for me because I’ve never actually been to Paga, even though I lived for twenty-six months in Tumu, a town less than 100 kilometers away. And I would often pass through Navrongo, a town just 10 kilometers from Paga, for my trips south. (If you use Google Earth, see just how close I was.)

So why did I never end up in Paga? At the time, I was much more interested in using my vacation days to head down to Accra, the only place in the whole country where a guy can get a burger, a shake, and a movie! But the next time I visit Ghana, I’ll definitely be swinging by Paga.

How to use Saxon with Ant

January 8th, 2007

As the only open-source processor that supports the XSLT 2.0 specification, Saxon is becoming indispensable. I use it in my HR-XSL project, and the new functions and features of XSLT 2.0 have helped make the code a lot simpler.

A typical way of running Saxon is via Ant, which offers built-in support for XSLT processors. Its Xslt task defaults to the Xalan processor, but because this task understands the TrAX API, switching to Saxon is trivial. All you need to do is put Saxon’s JAR on the classpath. (This works because Saxon declares support for the TransformerFactory service in its manifest. When TrAX finds a match for this service, it knows which processor to use.)

But there’s a problem here. Xalan also supports TrAX, so it specifies the TransformerFactory service, as well. Thus it becomes a contest. The first processor listed on the classpath wins!

Now, one would think this wouldn’t be an issue. Xslt’s classpath attribute trumps the system’s classpath, right? Unfortunately, that’s not how it works—as discussed in the Ant FAQ—and as a result, you get unpredictable behavior: Your Ant script may or may not use Saxon depending on whether Xalan happens to be in your system’s classpath. This can be a real problem if, for example, you’ve used Fink to install Ant, which places Xalan on the system classpath by default.

All right, so that’s bad. Is there an easy way to solve this dilemma? How about the <factory> element of the Xslt task? It specifies a particular transformer factory to use, rather than letting TrAX instantiate the first one it happens to find. With this element, you should easily be able to force Ant to use Saxon, like this:

<xslt ...>
    <classpath location=“/path/to/saxon.jar”/>
    <factory name=“net.sf.saxon.TransformerFactoryImpl”/>
</xslt>

Alas, this also fails to work. For some reason, Ant always throws a ClassNotFoundException when you try to use the <factory> element this way. (See bug #41314 for more details.)

This was starting to hurt. I didn’t want my HR-XSL users submitting bug reports just because Ant couldn’t find Saxon. I needed a way to ensure that Saxon would run every time.

After following a number of dead ends, I finally found a solution. The trick is to set the Java property javax.xml.transform.TransformerFactory to Saxon’s transformer factory class. The TrAX implementation in Ant happens to look for this property and, if set, it will use the specified class rather than whatever it discovers on the classpath.

The hard part, surprisingly, is how to set the property. Ant provides no mechanism for changing Java’s system properties, so I rely instead on a custom Java class that extends and replaces Ant’s default TrAX handler. Just before a transformation occurs, it sets the transform factory property to net.sf.saxon.TransformerFactoryImpl, forcing Saxon to be used, then it restores the previous setting when the transformation is complete. (Restoring the property prevents conflicts with other XSLT-related Ant tasks, such as FOP.)

Once this class has been compiled, you tell Ant to use it via the processor attribute. For example, if the custom class is called SaxonLiaison (to reflect the class that it overrides, TraXLiaison), you’d call the Xslt task like this:

<xslt ... processor=“SaxonLiaison”>
    <classpath location=“/path/to/saxon.jar:/path/to/SaxonLiaison”/>
</xslt>

That’s it! Saxon will be used every time, regardless of what’s on the system classpath.

You can find a complete listing of my SaxonLiaison custom class in the util directory of the HR-XSL distribution.