McQueeney.com
 

Tom's Blog

Thank you, Saul, Monty
Published by Tom | April 09, 2005 03:43 PM EDT |
When I was a high school senior, my English teacher assigned (my translation at the time: forced) me to read Henderson the Rain King by Saul Bellow.

Henderson is a book about an inherited millionaire in his mid-50s (the book was published when millionaire meant "great wealth," not "the guy next door") who is lost in life and takes it out on everyone around him: his wife, his children, a stray cat, his cleaning lady, his neighbors (he starts a pig farm in his front yard to spite them). Uncertain what to do next, he accepts an invitation to visit Africa with a honeymooning couple. He arrives in Africa and welcomely ditches them in search of undiscovered tribes, which he finds -- and he proceeds to make their lives miserable.

In other words, other than being lost in life and wondering who he wants to be when he grows up, this is not the sort of protagonist a high school kid can relate to. Yet read it we did.

Even more, we discussed it. We discussed life, what it means to discover who you are, "becoming" versus "being," "truth comes in blows," tragedy, joy, life, death. This was the first "serious literature" I read in high school that I can recall actually having semi-intelligent discussions about with fellow students and the teacher. Instead of the teacher expecting you to recite what students everywhere have been reciting about literary works for decades, our teacher wanted to hear what the book meant to us.

Our teacher, Mr. Montgomery (like most of my high school teachers, I am embarrassed to admit he exists in memory with only a last name) led us students on discussions of personal identity and the quest for meaning. He was the first teacher I recall who talked to us like we were adults, even when we didn't always deserve it, assuming we had thoughts in our heads that might be worth hearing.

Mr. Montgomery, or "Monty" as we sometimes called in class during light-hearted moments, was a school teacher who was so good at what he did they moved him into "management" writing curricula in the district office. Years later, lucky for me, he took a pay cut to return to the classroom to what he loved -- teaching kids. And his love for teaching showed. Mr. Montgomery exposed me to literature in a way no teacher had, and at a time when I was more able to appreciate it. Honestly, at that stage in life, I wasn't ready to love literature. I still thought our analysis of Henderson was way overblown, and "hero" Eugene Henderson was hard to relate to. But Mr. Montgomery changed my definition of literature; I no longer viewed it as "boring big books sadistic teachers force you to read."

Saul Bellow
Saul Bellow: from New York Times
In college, an unknown force compelled me to read Henderson -- gasp! outside of class. A few years later, I read it again. And again a few years after that. Each time I picked up the book, I saw Eugene Henderson and his quest for life's meaning in a different way, obviously because I was a different person. My respect for "literature" and the power of a good novel grew. My admiration for Saul Bellow grew -- even though I did put down The Dean's December almost in disgust, thinking the author just subjected me to hours of gray, bleak depression and death. More importantly, my respect and admiration for "Monty" Montgomery grew. On each reading of Henderson, I'd recall some of the book's themes we talked about in class, and I finally understood more of what they (Saul and Monty) were saying. Life even dealt me a "truth comes in blows" moment.

When I heard Saul Bellow died Tuesday at the age of 89, fond memories of Henderson and Mr. Montgomery returned. According to Bellow's New York Times obituary by Mel Gussow and Charles McGrath, the author won more literary honors than any other American writer. His awards included the Nobel Prize in Literature in 1976, a Pulitzer Price, three National Book Awards, a Presidential Medal. (If you don't want to register at the NYT web site, you can read an abridged version of the obituary on the International Herald Tribune's web site.)

This blog entry veers from my usual technical focus. It's my way of remembering two people who had an influential impact on my life: a novelist whose words could make me think about life in new ways, and a teacher who shared more of himself than he had to in order to teach me to think and not just parrot the Cliffs Notes.

To Saul and Monty, thank you.


20050409 Saturday April 09, 2005 Permalink
JUG Serendipity: Finite State Machines
Published by Tom | April 06, 2005 09:13 PM EDT |
I checked to see what the next talk was going to be at my local Java Users Group (the Denver JUG) and saw that Eitan Suez was going to be presenting on The State Machine Compiler. My first reaction was, "What the heck is that?"

So I spent a few minutes reading about state machines and realized again why going to JUG meetings is great: JUG Serendipity. By attending JUG meetings, I learn about development tools and technologies I normally would never hear about.

Eitan will talk next Wednesday about the State Machine Compiler, a Java open-source (Mozilla Public License) project to automate creating classes that implement the Gang of Four State pattern. SMC allows you to define a "state machine" mapping file that defines the states your object can be in, what transitions trigger movement between states, and actions that should occur upon state transition. Then, in your Java code, you use a generated state Context object to change states when needed. The generated code handles the work of invoking methods to perform the actions and track the state transition.

By keeping the state definitions and transition logic in a separate file, you remove all the ugly switch and if-then-else state transition logic from your Java code. The down side is you have to learn a new notation to represent the state machine. Fortunately, the syntax defined by SMC isn't overly complex. And it's not XML!

SMC apparently was written originally by Robert C. Martin, then picked up and expanded by Charles W. Rapp. (Apparently not the same Charles Rapp agency that manages Nipsey Russell.) Uncle Bob still has a Java version of SMC available, but without source code.


20050406 Wednesday April 06, 2005 Permalink Comments [1]
Rise of the Scripting Language
Published by Tom | March 19, 2005 07:50 PM EST |
Are the scripting languages threatening Java?

A posting Friday on TheServerSide defending Java against Ruby on Rails made me realize that some Java programmers seem to be feeling threatened by Ruby and its Rails framework. The concern seems to be Ruby, or another scripting languages like PHP, makes developing web applications easier than using Java and one of its many web frameworks. The result being Java will start to die out and really will become the next COBOL.

Granted, there's a lot of hype right now about Ruby and Rails. We all read or heard about the article in January on the O'Reilly ONLamp web site by Curt Hibbs saying Ruby on Rails will let you develop a web application 10 times faster than using Java. That article seemed to strike a chord among Java developers. A lot of blogs have been discussing RoR and why it's the best way to go for developing web applications, or a big step backward for separation of concerns and good design, depending on whom you read.

And there's even been recent hype about PHP as a fast way to develop web applications. IBM last month, announced it will work on products to bring the "do it yourself" simplicity of PHP to products like Zend Core for IBM. The headline on one story proclaimed "IBM Bets PHP Is Open Source's Next Big Thing." IBM accompanied its announcement with a new developerWorks section devoted to all things PHP. This month, IBM developerWorks announced new blogs, by the likes of Sam Ruby, focusing on the benefits of PHP.

Does this mean Java is on the way out for developing web applications? Who knows? But why worry? New languages and new web frameworks will have to prove themselves. They're not going to steamroll over Java without some real projects proving their mettle over Java in the long term.

I do have a concern that some software development managers, in their quest for Cheaper, Faster, Lighter software, might fall for the hype of the scripting language du jour and hire inexperienced developers ("Hey, they're right out of college but they can program in PHP!") to write web applications in PHP or Perl because they've heard these languages will result in faster delivery. The result could indeed be fast delivery -- of horrendously complex, intertwined, unmaintainable code.

But how is that any different than hiring an inexperienced Java developer to do the same thing? I've seen a lot of inexpensively developed Java code that was horrendously complex, tightly coupled and expensive to enhance and maintain. (OK, there is a difference. In the latter case, I can get hired to come in and fix it at a nice rate.)

If the scripting languages and their frameworks like Ruby on Rails really do make developing web applications easier, sign me up. Ruby seems like an elegant, expressive language that allows for good object-oriented design. Exaggerated claims about a language or framework are no reason to dismiss it. If features of Ruby or Rails really make developing software easier, faster and more maintainable, Java and its frameworks eventually will adopt similar features. And if they don't, Java deserves to fade.

I'm not worried about Java fading soon. Java has been evolving since it began, learning from other languages and frameworks (even .NET). The EJB remote-object overkill was solved in EJB 2.0. Web services got easier to develop in J2EE 1.4. Annotations were added in JDK 5 and will be expanded in J2EE 5. Object-relational mapping is supposed to get better with EJB 3.0.

But what makes me believe Ruby, Python and PHP won't kill Java is that they haven't been able to do it in almost a decade. Object-oriented scripting languages, even Ruby, have been around for years. Most predate Java. If they were so uber-language powerful, why does Java (currently, at least) enjoy such a large developer and CTO mind share? What I think we're seeing in the Rise of the Scripting Language is that Java is overkill for a lot of projects. Just like we all accepted a couple of years ago that EJB is overkill for a lot of projects. The interest in scripting languages could be a trend similar to the growing interest in Spring and Hibernate to help us simplify our applications.

The interest in scripting languages among Java developers actually seemed to start a few years ago. I remember hearing Bruce Eckel in 2001, saying how Python, with its OO features and dynamic typing, allow him to write software faster and more elegantly. He said in an interview on Artima developer that:

I feel Python was designed for the person who is actually doing
the programming, to maximize their productivity. And that just
makes me feel warm and fuzzy all over.

Since about 2000, Dave Thomas has been saying how Ruby does the same for him. Here's an excerpt from an article he wrote for Linux Magazine in September, 2002:

Ruby is concise (like Python), fully object-oriented (like SmallTalk),
and powerful (like Perl). In addition, Ruby is a remarkably capable
language for building Internet applications. Ruby's libraries and
built-in networking support make networked applications (such as email
clients, SOAP servers, and distributed processing) easy to write and easy
to maintain and extend.

But the interest in scripting languages among Java developers really seemed to begin in the past few months with all the talk about Ruby on Rails. It seemed to start with Curt Hibbs's O'Reilly ONLamp article, the one in which he said:

What would you think if I told you that you could develop a web application
at least ten times faster with Rails than you could with a typical Java framework?
You can--without making any sacrifices in the quality of your application!

The next month, Bruce Tate said in a February blog that Ruby on Rails "is beautiful, simple, and has a little bit of magic to it." He said he loves Ruby.

The Rails lovefest hasn't gone by without some cricism. JavaServer Faces expert David Geary countered Hibbs's claim that Ruby on Rails beats Java hands down:
...ROR is no match for a Java-based web app six pack of
JSF-Shale-Tiles-SiteMesh-Hibernate-Spring .... I'm not going to use the default
views generated by ROR (nobody is, except for simple UI mockups) and implementing
my own views in ROR looks mighty ugly to me. And am I going to just throw away the
incredibly rich collection of open-source Java software, like JSF, Tiles and SiteMesh?
No way. ... [Y]ou take this ROR koolaid. I'll stick with the JSF flavor.
Still, after getting an email from Bruce Tate, who raved to him about Ruby on Rails, Geary responded last week in his blog that he would take a closer look at Ruby on Rails before criticizing further.

I'm going to bet that the use of scripting languages like Ruby, and scripting-language based frameworks like Ruby on Rails, will increase in the coming years. Still, I don't think Java will fade as a result. I think the increase in scripting languages will help developers refine their decisions on where the power or maturity of Java is needed, and where it's not.

And by the way, where's Groovy (JSR 241)? Last year, I heard from a developer that he's several times more productive writing in Groovy than Java, and had several thousand lines of Groovy code under his belt to bolster his comparison. Yet I don't hear developers talking about Groovy to the same level as other scripting languages. Maybe once Groovy reaches its 1.0 milestone, we'll start to hear how Groovy can make us 10 times more productive as developers.


20050319 Saturday March 19, 2005 Permalink Comments [12]
Using Java shutdown hooks to process records cleanly
Published by Tom | December 22, 2004 08:06 PM EST |
I recently had to write a quick standalone Java application to manipulate data so it could be imported to Excel. I wanted to ensure only full records would be output even if the user hit Control-C during processing.

I knew Java had the notion of a "shutdown hook" you could register with the Java virtual machine to allow code to cleanup and close resources during a "Control-C" interrupt. After I wrote the application, I wrote this little demo application to show one way shutdown hooks could be used to help ensure records are processed atomically, and any resources could be cleaned up before the JVM exits.

Java shutdown hooks allow code to perform some processing after Control-C is pressed, or while the VM is shutting down for other controllable reason, even System.exit. A shutdown hook is a Thread that hasn't been started. The JVM starts the thread during the shutdown process to allow the thread to perform cleanup work needed before the JVM exits. The JVM starts all shutdown hooks concurrently and allows them to complete before continuing with other shutdown actions, such as running object finalizers. It's a nice feature added in Java 1.3, certainly not as powerful as being able to trap all operating-system signals and running code to handle them, but at least it works across all platforms.

In the case of this demo application, the shutdown hook gets started after the user presses Control-C, then mostly just waits until the latest record being processed finishes. The shutdown hook sets an instance variable flag to tell the main processing loop that a JVM shutdown is in progress -- that way, it can stop processing cleanly.

The main processing loop checks after processing each record to see whether the JVM is being shut down abnormally, such as the user hitting Control-C or the user logging off without quitting the application. If a shutdown is in progress, it breaks out of the processing loop to avoid having the next record being corrupted when the operating system decides the application isn't responding quickly enough to the Control-C and kills the JVM outright.

That is one of the unknowns of shutdown hooks: How long can cleanup code run before the operating system decides the application is an uncooperative rogue process that must be killed? Generally, I wouldn't want to risk more than few seconds for Windows to intervene, or for a Unix user to intervene with "kill -9".

This demo application is pretty simple. It adds "ing" to a list of strings stored in a StringBuffer array. To simulate slow, multi-step processing, that is, something that could get interrupted, the application adds each character individually -- i, n, g -- and takes an entire second to do so.

Here is the complete application: CleanShutdownDemo.java. When you run the application and hit Control-C before the program completes normally, it'll dump the state of its data so you can see whether the data got "corrupted" by having some records getting a partial "ing" added. I'll summarize what the methods are doing, below.

Once you download and compile it, there are two ways to run it: the clean way and the dirty way. If you run this program with the command-line argument "clean", it ensures "ing" is added cleanly to the current string being processed, even if the user hits Control-C during processing. If you run the program without an argument or with an argument other than "clean", it runs in "dirty" mode in which a Control-C leaves the currently processed string in an uncertain state. That is, it could:
  • have been left unprocessed
  • have had an "i" appended.
  • have had an "in" appended
  • have been fully processed by having an "ing" appended
Here are some sample runs. First, the "dirty" way:
> java -cp . com.mcqueeney.demo.CleanShutdownDemo dirty
Registering shutdown hook
Starting processing
About to add 'i' to show...added
About to add 'n' to showi...added
About to add 'g' to showin...added
About to add 'i' to cod...added
About to add 'n' to codi...added
About to add 'g' to codin...added
About to add 'i' to thread...added
About to add 'n' to threadi...added
About to add 'g' to threadin...added
About to add 'i' to blogg...added
About to add 'n' to bloggi^C    <-- HIT CONTROL-C
Record 0: showing               <-- THESE LINES PRINTED BY SHUTDOWN HOOK
Record 1: coding
Record 2: threading
Record 3: bloggi
Record 4: vacation
You'll see that I hit ^C after "i" was added to "blogg" but before the "n" got added. The data dump at the end shows that blogg was corrupted by having only an "i" added. That's the purpose of the "clean" mode, to ensure records get a full "ing" added, or they are left completely unprocessed, in their original state.

Now, for the "clean" way. Running the program with the argument "clean" ensures no record is left in an indeterminate state:
> java -cp . com.mcqueeney.demo.CleanShutdownDemo clean
Registering shutdown hook
Starting processing
About to add 'i' to show...added
About to add 'n' to showi...added
About to add 'g' to showin...added
About to add 'i' to cod...added
About to add 'n' to codi...added
About to add 'g' to codin...added
About to add 'i' to thread...added
About to add 'n' to threadi...added
About to add 'g' to threadin...added
About to add 'i' to blogg^C       <-- HIT CONTROL-C
Shutdown hook: Waiting to exit
...added
About to add 'n' to bloggi...added
About to add 'g' to bloggin...added
Process interrupted. Shutting down after processing 4 records.
Unregistering shutdown hook
Finished comparison. Processed 4 records.
Record 0: showing
Record 1: coding
Record 2: threading
Record 3: blogging
Record 4: vacation
You'll see that after hitting ^C, the main thread continues executing. The addIngToString method was able to complete adding "ing" to the word "blogg" even after ^C was hit. The main thread was able to complete its work because the shutdown hook (thread) was running and waiting for the method to complete before returning. The shutdown hook in this demo application "guards" against the JVM stopping the main thread prematurely.

The shutdown hook code gets added in the registerShutdownHook method:
    private void registerShutdownHook() {
        System.out.println("Registering shutdown hook");

        this.shutdownThread = new Thread("myhook") {
            public void run() {
                // For demonstration purposes: Don't give chance to
                // shutdown unless flag is set. Just show data.
                if (!runningInCleanMode) {
                    showData();
                    return;
                }

                synchronized(this) {
                    if (!readyToExit) {
                        isVMShuttingDown = true;
                        System.out.println("Shutdown hook: Waiting to exit");
                        try {
                            // Wait up to 1.5 secs for a record to be processed.
                            wait(1500);
                        } catch (InterruptedException ignore) {
                        }
                        if (!readyToExit) {
                            System.out.println(
                                "Main processing interrupted." +
                                " Data corruption possible."
                            );
                        }
                    }
                }

                showData(); // To demo current state of data.
            }

            /**
             * For demo purposes: Show data to see whether it is "corrupted"
             */
            private void showData() {
                for (int i = 0, j = dataToProcess.length; i < j; i++) {
                    System.err.println(
                        "Record " + i + ": " + dataToProcess[i]
                    );
                }
            }
        };

        Runtime.getRuntime().addShutdownHook(this.shutdownThread);
    }

This method creates (but does not start) a new thread, then registers that thread as a shutdown hook with the Java runtime. The shutdown thread uses two instance boolean variables to communicate with the main thread: readyToExit and isVMShuttingDown. If the main thread has already set readToExit to true, the shutdown hook knows the main thread has finished its processing and doesn't need to be "guarded" against JVM shutdown.

If readyToExit is false, the run method sets the isVMShuttingDown flag to true to tell the main thread that it better finish what it's doing (processing the current string record) and then exit -- to avoid being killed by the operating system in mid-record. After setting that flag, it waits for up to 1.5 seconds for the main thread to finish. If the main thread hasn't set the readyToExit flag after waiting, the shutdown hook thread prints a warning to say the data might indeed get corrupted.

Most of the other code in the shutdown hook thread is there for demonstration purpose: to alter behavior depending on whether we are running in "clean" or "dirty" mode, and to print the data being processed in the showData method so we can see for ourselves whether the data has been "corrupted." In fact, the only reason the dataToProcess variable is an instance variable is so the shutdown thread can see it for demonstration purposes.

The other method that cooperates with the shutdown thread is startProcessing. This method checks whether a JVM shutdown is in progress after fully processing one record (which the addIngToString performs).
    public void startProcessing(StringBuffer[] records) {
        this.dataToProcess = records; // Store for demo purposes.

        System.out.println("Starting processing");
        int recordsProcessed = 0;

        try {
            for (int i = 0, j = records.length; i < j; i++) {
                // Process this next record but don't let ^C interrupt
                // unless it takes more than 1.5 seconds.
                addIngToString(records[i]);
                ++recordsProcessed;

                // Don't continue if VM is trying to shut down.
                if (this.isVMShuttingDown) {
                    System.out.println(
                        "Process interrupted. Shutting down after processing " +
                        recordsProcessed + " records."
                    );

                    signalReadyToExit();
                    break;
                }
            } // end while.

            // Tell shutdown hook we're done then unregister it.
            signalReadyToExit(); // In case shutdown thread already running.
            unregisterShutdownHook();

            System.out.println(
                "Finished comparison. Processed " + recordsProcessed +
                " records."
            );
        } catch (RuntimeException rte) {
            System.err.println(
                "Got unexpected runtime exception: " + rte.getMessage()
            );
            throw rte;
        } finally {
            // Cleanup, assuming we had resources to close.
        }
    }
You can see that after each call to addIngToString, the "if" statement:
    // Don't continue if VM is trying to shut down.
    if (this.isVMShuttingDown) {
        System.out.println(
            "Process interrupted. Shutting down after processing " +
            recordsProcessed + " records."
        );

        signalReadyToExit();
        break;
    }
checks to see if the shutdown thread has warned us that the JVM is being shutdown early for some reason. If so, it calls signalReadyToExit to tell the shutdown thread that we've acknowledged the JVM shutdown and we are NOT in the middle of processing a record, so it is OK to exit and allow the JVM to complete shutdown processing. It then breaks out of the "for" loop to skip processing further records.

As a side note, the check of the isVMShuttingDown variable should be in a synchronized block for complete thread safety, especially on a multi-CPU system. The Java memory model guarantees cooperating threads can see changes to shared data only when a thread owns the shared lock. I left it out of the above code for ease of reading.

The last method we'll call out for special attention is the method we are trying to ensure runs atomically. The addIngToString simulates the method that performs some important processing that, if interrupted by a JVM shutdown, we still want it to complete processing.
    private void addIngToString(StringBuffer buffer) {
        char[] toAppend = { 'i', 'n', 'g' };

        for (int i = 0, j = toAppend.length; i < j; i++) {
            System.out.print(
                "About to add '" + toAppend[i] + "' to " + buffer
            );
            sleep(333); // Sleep to simulate long processing
            buffer.append(toAppend[i]);
            System.out.println("...added");
        }
    }
This method slowly adds "ing" to the given string buffer argument. The sleep method performs the obvious Thread.sleep call.

Although this demonstration program has a lot of code, most of it is there for verbosity. The extra code allows us to watch what is happening and be able to set the two different runtime modes to see how the data can get "corrupted" if not being guarded by the shutdown hook. The actual code to protect against data corruption is quite small: 14 real lines of code in the shutdown hook and about six lines in the main application to set and check the shutdown flags being set and watched by the shutdown hook.

Once you get used to the threading issues, adding shutdown hooks to applications for cleaner handling of JVM exits is easy, and helps insulate applications against unexpected interruptions.
20041222 Wednesday December 22, 2004 Permalink Comments [3]
Firefox browser upgrade blues
Published by Tom | November 23, 2004 06:34 PM EST |
I momentarily got the Firefox upgrade blues when I upgraded my Pre 1 browser to the 1.0 release. As has happened nearly every time I've upgraded Firefox, my installed extensions break.

I figured this upgrade probably didn't change a whole lot on how Firefox handles extensions, so I thought I could rifle through the extension XPI files and tell them it's OK to run in 1.0. Thirty seconds later, I said, "that was easy!" and I figure I'd write the instructions here for other folks whose extensions stopped working after they upgraded to Firefox 1.0.

Before I went to the trouble to write the instructions, I checked to see if there already were instructions out there to forcibly "upgrade" browser extensions. Um, yeah, a few, including comments on several extension pages whose authors hadn't yet upgraded the XPI files.

The first set of instructions I found using Google were from Liew Cheon Fong. So why repeat his work?

I wonder though, rather than unzipping the XPI file, editing the install.rdf file, then rezipping everything back into an XPI file, would it work to edit the exploded XPI file in my Firefox profile directory? I haven't tried it yet, but I think it should work.
20041123 Tuesday November 23, 2004 Permalink Comments [2]