The Source for Java Technology Collaboration
User: Password:



Tom Ball's Blog

Community: Java Tools Archives


Testing Your Documentation

Posted by tball on April 21, 2008 at 02:14 PM | Permalink | Comments (1)

One responsibility of the JavaFX Script compiler project is to deliver a programming guide for the language. One mark of a good programming guide is that it has lots of short code examples which demonstrate the language, and as the language evolves, it's really important that the guide be updated to match the definition. Review should find most cases where the documentation no longer describes the language correctly, but it's often easy to overlook subtle changes in grammar which cause the example code to break. So there is a real tension where the more examples you have, the more work it is to verify they still build and run correctly.

Donald Knuth recognized this problem many years ago, and he responded by developing what he called Literate Programming. Literate programming's premise is that both the source code and its documentation should be co-mingled in common source files, which are processed to create the program's source files and printed documentation. The idea is that keeping a program's source code and documentation as close to each other as possible reduces divergence between them. Sound familiar? Right, javadoc and Doxygen are examples of embedding API documentation in source files; not as powerful as true literate programming (which documents the actual source code, not just its API), but a big reason why the large API sets developed over the past decade haven't collapsed from their own weight.

When we were setting up the JavaFX Script compiler project, we believed it was important that its programming guide be generated as part of our build, rather than delivered independently by a separate team. One reason was based on our experience with javadoc, and another is that our two doc-writers are on loan, and so could disappear at any time leaving the development engineers responsible for the manual's maintenance. So we chose to write it using DocBook, which is an authoring system that allows documentation sources to be written in XML, stored in our version control system, generated by Ant or make, and can generate many output formats including as HTML and Adobe's PDF.

Although we have a book which can be edited by anyone with access to our source repository, we still ran into major headaches keeping the code examples compilable. So I just committed a simple command-line tool and Ant task (available here) which extract the text from DocBook <programlisting> elements and generate source files which the build can verify are compilable. The tool is called "DocBookTangle", since Dr. Knuth named his source extractor "tangle". This idea of testing programming documentation by compiling it appears to have originated with Python's doctext module, and it's a good one Agile teams should consider adopting.

Unfortunately, my implementation is a little clunky because DocBook has a strict DTD which we want our documents to adhere to (another automated test possibility!). The <programlisting> element has only a few attributes defined, and the most applicable ones are enumerations. So to start a new source file, we declare <programlisting> with a continuation="restarts" attribute; this creates a file named <chapterName>-<count>.fx, where count is incremented with each new program listing in that chapter. If an example is broken into pieces with explanations in between, subsequent <programlisting> elements use the continuation="continues" attribute, so their text is appended to the source file being currently extracted. "In theory", Java examples can be extracted by setting a language="java" attribute. However, Java programs require that the file name match the file's main class name, so either the tool needs to scan the extracted source for the name, or the build script needs to rename the extracted file. Happily, JavaFX Script doesn't care what the source files are called, as long as they end in ".fx". (Yet another reason to try JavaFX Script. ;-)

How well does it work? After converting the introduction chapter and running this test, thirty compilation errors were found. This shows that the problem was worse than we thought, and shows the value of automating documentation verification. We're now scrambling to convert the other chapters and fix any remaining errors, then run this test with every build to make sure they don't return.



Divide and Conquer

Posted by tball on April 01, 2008 at 09:07 AM | Permalink | Comments (1)

As anyone following the JavaFX Script compiler project knows, we have a schedule gun to our heads to finish a useful tool quickly, so the interpreter-based prototype shown at last year's JavaOne can be retired. It's a big job since the language doesn't have a specification yet, but our team of four engineers plus some really good volunteers are set to deliver what looks to be a great product. Of course I'm biased in this appraisal since I'm one of its contributors, but feel free to browse the project's source or subscribe to its dev and/or commits email aliases and make your own assessment.

Unfortunately, it has become more obvious as the project progresses that when our clients say "compiler" they really mean a full SDK, similar to what is delivered by the JDK. In particular, our management just assumed that a version of the javadoc tool which understands JavaFX Script would magically appear without any stated requirements or staffing. So we had a sub-project with a short deadline, no engineer available, and frustrated customers.

To make matters worse, javadoc engineers are hard to find since the job requires two unique skill sets: compiler engineering and web designing. Why does the JDK's javadoc output look dated? Because compiler engineers have owned it for the past few years. Why was it lagging behind the language a few years ago? You guessed it, our doc-writers were supporting it. Now, our team understands compilers, obviously, but none of us have any design skills worth noting. However, we have some engineers with great design skills on other teams. The "correct" solution would be to pull one engineer from each team and have them work together, but there wasn't time nor anyone available. Sound familiar?

What we did was follow the Unix rules for tool development: break the task apart, define a tool for each part, and use ASCII text to communicate between them. I wrote a simple doclet that dumped all information available from the Doclet API to an XML file (other people have done this over the years), then copied the JDK's javadoc source and enhanced it to provide JavaFX Script-specific information for that doclet (the doclet also works with Java sources when used with the JDK's javadoc). Joshua Marinacci then wrote an XSLT translator to generate XHTML pages similar to what javadoc's standard doclet creates. We use this tool to generate the project's UI Runtime documentation, and soon, all JavaFX Script-based API. The full tool source is here.

This divide-and-conquer strategy really pays off. Neither Josh nor I put much time into this project (as shown by how short both the doclet and XSLT script are), so our main jobs weren't impacted much. This approach also makes it much easier for our community to contribute: don't like the (currently primitive) output? An XSLT file is much less intimidating than javadoc's source, so jump in and make it better. But why limit ourselves to one output format? Just use the tool's -xsltfile option to use your own translator. And why limit ourselves to documentation generation? That XML file defines a model of any JavaFX Script and/or Java-based program, which can be used by other tools. As the Unix tool masters learned early on, breaking a big tool up into smaller, specialized tools opens the door to all kinds of unanticipated uses.



Elephants and the JavaFX Script Compiler

Posted by tball on November 10, 2007 at 04:42 PM | Permalink | Comments (4)

I don't know what it is about elephants, but they sure work well in analogies. Whether we are ignoring them, seeing pink ones or trying to sell white ones, elephant analogies seem to communicate ideas well. An elephant analogy came to me when I was recently grilled about exactly when the JavaFX Script compiler team will deliver our first milestone release. "I can't give you an accurate date," I said. "It's like pushing an elephant through a door*; until a critical mass makes it past the threshold you just don't know when you'll be finished. Once you pass that threshold, though, the rest happens quickly and in a manner that can be more accurately predicted." And then the tension in the room broke, as I think everyone has been in that situation sometime in their respective pasts.

In a way, this compiler project has turned out to be very similar to some of the GUI toolkit ports I've worked on in the past. We're making lots of measurable progress, which anyone can monitor in our test/features directory; for example, we recently implemented support for our "big three" language hurdles: sequences, multiple inheritance, and functional attributes (aka closures). Since the primary focus of JavaFX Script is as a domain-specific language for Rich Internet Applications, however, few people want an early access release of what we have so far -- like GUI toolkits, it doesn't get interesting until you can start working visually. So even though the JavaFX Script UI runtime needs an overhaul, we're porting it as is for the first release so those necessary GUI features are there.

Another similarity this project has to a GUI port is that most graphical toolkits have a few core components that depend upon most of the rest of the toolkit; call those classes Widget, Component, JComponent, Window, (graphic) Node, it doesn't matter -- there are so many benefits to sharing code between GUI components that these elephant-sized classes are just part of the GUI toolkit territory. So porting a GUI toolkit means that often there will an excruciating period where there is little visible progress as you work through all the dependencies, and then your first window appears, and then most of the remaining toolkit seems to just fall into place quickly. That's what happened many years ago when I was part of a team porting Presentation Manager from OS/2 to CTOS (which was about as unlike OS/2 as could be possible in those days). For several weeks, we slogged along without any visible progress (as voiced daily by our frustrated management), then we finally got the login panel showing and, in less than a week, all of the core applications were up-and-running. That login application was the critical part of our elephant, since the closure of its toolkit requirements encompassed most of the system. It wasn't really the login panel itself, of course, because whatever application is chosen first will be the hardest.

This is all a long-winded way of saying that we are really close toward delivering our first milestone release, but when the exact date will be remains unknown. If anyone is interested in monitoring our progress, check out our JIRA issue tracking system (courtesy of Atlassian), and/or subscribe to our developers alias (comments from experienced elephant pushers are welcome). Once we hit this first milestone, we'll be able to provide a much better road map for the remainder of this release.


*No elephants were hurt during the writing of this blog entry.

"Advanced Java Refactoring" JavaOne Slides Available

Posted by tball on May 10, 2007 at 10:10 PM | Permalink | Comments (1)

Today I gave a talk at JavaOne titled "Advanced Java Refactoring: Pushing the Envelope" to a packed room, and just pushed a PDF of the slides to the Jackpot project site. Unfortunately I mismanaged the talk's time, spending too long on the demo and had to blast through the last (and, IMHO, the most interesting) slides. My apologies to those in the audience for not doing a better job by them.

It was great to see the continued interest in Java refactoring as its state-of-the-art is improving so rapidly among all the Java IDEs. I've come to rely on the 6.0 NetBeans Java editor over the past several months, in large part because many common refactorings and some new ones are fully integrated into the editor, instead of hiding in a separate Refactoring menu. Traditional refactoring improved my productivity when I first started using it many years ago, but this tighter integration is like strapping booster rockets to my chair. So my talk wasn't about the cool refactorings I'm starting to work on, but instead about how Java tools are changing the very meaning of refactoring and taking it much farther than it was first envisioned.

When debating language strengths, one thing Java engineers may be overlooking is how much Java's being a strongly-typed and statically inspectable language determines how refactorable it is. For example, the bytecode verifier that has been a part of the JVM since 1.0 puts several limits on what is considered valid code, since the verifier has to model that code accurately in order to verify it. Therefore to a certain extent, any language that can run on the JVM can be modeled fairly well. But Java adds a lot of semantic information which makes much richer models possible than with most other languages, so that language-aware tools like refactoring editors have much more information to work with when working with Java. It also avoids features that undermine modeling, such as C preprocessor abuse.

Lately I have been disappointing Sun's C and JavaScript tools engineers who want to leverage the NetBeans IDE's new Java refactoring engine (much of which is based on Jackpot), because the only answer is "no can do" -- their languages can't be statically modeled as completely as Java can. So if you get into a late-night pub discussion about how Java is so last century and that dynamic languages will soon rule the world, pick some of your favorite refactorings (those that really improve your productivity) and ask if their language/IDE supports them. Now, there are some brilliant people working on world-class languages, but they will have trouble competing with engineers leveraging the rich Java models generated by javac, Jikes, IntelliJ IDEA, and other Java tools. I suspect improved refactoring is one way Java will remain viable for many years to come.



"Open Letter" or Extortion?

Posted by tball on April 10, 2007 at 02:22 PM | Permalink | Comments (20)

Today, Geir Magnusson Jr., the Apache Software Foundation's VP of Java Community Process, issued an "Open Letter" to Sun Microsystems, addressed to Jonathan Schwartz. I put "Open Letter" in quotes because it reads like an ultimatum demanding a license they like to the Java SE 5 technology compatibility kit within thirty days (or else).

This request/ultimatum seems to have come out of left field. Is Apache Harmony so close to completion that it's ready to officially pass the JCK? Not according to its project page, which states it has 95% of the Java API complete but not necessarily compatible. Now, 95% of the Java platform is a big milestone for which the Apache Harmony engineers deserve a lot of credit for their hard work, but how useful would several thousand JCK errors be to them at this point in the project cycle? If I were in their position, I would instead ask that the JCK's current read-only license be rescinded so that the Harmony engineers can compile and run the tests specific to whatever they are individually working on to see what issues remain. IMHO, the JCK shouldn't be modifiable (it helps define the Java platform), but anyone should be able to compile and run it without legal hindrance. But that isn't what Mr. Magnusson seems to be asking for.

I just looked at my calendar and noticed that thirty days from today is smack in the middle of JavaOne, two days after Jonathan Schwartz's keynote. Mystery solved! This isn't about the Apache Harmony team's ability to work effectively -- it's instead a classic JavaOne slimy marketing ploy Java engineers have to endure each year. With the JavaOne schedule moved up I guess the mud had to start being thrown sooner.

I'm disappointed that this sort of tactic was employed by an organization I respect so much. In my opinion it's a form of extortion -- do what we want or we'll destroy your new open-source credibility at your largest developer conference. You expect that sort of behavior from patent trolls, not an esteemed organization like Apache. My only hope is that Mr. Magnusson was working independently of the rest of the Apache organization on this issue.



Get Medieval On Your Code

Posted by tball on November 20, 2006 at 02:22 PM | Permalink | Comments (6)

I realize I'm dating myself paraphrasing 1994's "Pulp Fiction", but it really pays to get and stay hard-core with your project code. One easy way to turn up the heat is to enable all compiler warnings and tell the compiler to treat them as errors -- all of a sudden, those "minor" cleanup issues one never has time for now demand immediate attention. This actually save time in the long run, because once you go through the work of cleaning up all the existing warnings, any new problems can be quickly caught while the new code is being developed (rather than having to scramble after the product ships). Serious C developers have been doing this for years; the Solaris team, for example, bit the bullet maybe fifteen years ago and went "lint free", running the lint tool as part of its build and addressing all warnings it and the compiler reported, then requiring that all new code pass this same hurdle. Even though it was a major effort, that cleanup has paid major quality dividends ever since.

In the past few years, Java has finally started to catch up with C on this front. Third-party static checkers like FindBugs and PMD are now freely available and are easily integrated into a build. In Java 5 the javac compiler added the -Xlint option with several types of checks, which were significantly expanded in Java 6. The Jikes compiler has a similar option called pedantic compilation (+P). All of these tools allow you to enable/disable different types of tests, and unless you strongly disagree with certain tests I recommend that you turn on all the warnings you can.

Sometimes you need to suppress one or more warnings for a specific block of code. Java 5 introduced the SuppressWarnings annotation to enable you to do this, but javac ignored it in that release; happily, it is now recognized in Java 5, update 6 (1.5_06). One big advantage of globally checking for a type of potential error and suppressing it in specific places is that the SuppressWarnings annotation serves as documentation that you really intended to do this questionable practice. For example, Jackpot's parser outputs a big switch statement for a rule set, which is optimized using case statement fall-through. Since fall-though can be a frequent source of bugs, Jackpot is tested with javac's fall-through checking and with a @SuppressWarnings("fallthrough") for this specific method -- that way if there are fall-through bugs elsewhere they will be flagged. Turning warnings into build-stopping errors has also been enabled in Java 6 via javac's hidden -Werror flag (just like the C compiler's). Jikes has the +Z2 flag to do this, and recently it added a -Werror equivalent to be command-compatible with javac.

For NetBeans projects, it is easy to set these flags by right-clicking on the project, selecting its properties, clicking on the Compiling panel and putting them in the "Additional Compiler Options" field. It can be a pain changing all of your Ant build files to do this, however. You can set this property globally, however, because NetBeans projects have a javac.compilerargs property hiding in the nbproject/build-impl.xml file we can use. To set this for all projects which have this property, add this line to $HOME/.antrc (which probably doesn't exist):

ANT_ARGS='-Djavac.compilerargs="-Xlint:all -Werror"'
The Ant startup script reads this file and passes the ANT_ARGS property to Ant's main class. If your project wasn't created by the NetBeans IDE, you can still edit the build.xml file and add this property to the javac task references.

Separate static checker tools can be integrated into your build as well. Ant tasks are available for both FindBugs and PMD. Both tools have a failOnError parameter which can be set true so the build stops if a warning is issued. Both of these tools support the SuppressWarnings annotation, too.

Now, those of you who are really hard-core will point out there are many other ways you can stop coddling your build and make it cough up its bugs. You are right, and in future blog postings I'll investigate other ways to get medieval on your code.

Hacking Open Source javac!

Posted by tball on November 13, 2006 at 01:20 PM | Permalink | Comments (1)

Hallelujah! Java SE is now an open-source project, with the HotSpot VM and javac as its first sub-projects.

This is great news for anyone interested in Java performance, as the world now has full-access to both the static (javac) and dynamic (HotSpot) optimizing compilers from Sun's Java implementation. Remember back when everyone laughed at the prediction that with dynamic compilers like HotSpot, Java performance will eventually surpass C++? This is starting to happen now with the continued performance gains in Java 5 and soon Java 6. My hope is that an open-source HotSpot and javac will encourage the world's best and brightest to augment the excellent work of the JDK team to drive Java performance further.

So how can you start contributing? The first step is to download and build the source using the links above. But wait! There is an easier way to work with javac's source: NetBeans has a brand-new nb-openjdk project which makes downloading and building the javac source painless and productive. My guess is that this project will grow to support the HotSpot project as well as the rest of the JDK's components as they are released. Happy hacking.

Hacking javac

Posted by tball on September 16, 2006 at 03:55 PM | Permalink | Comments (20)

hack (hăk) n., A non-obvious solution to an interesting problem.

This definition is on the front of a tee-shirt I have from O'Reilly Media to promote their Hack Series, which includes one of my favorite books, Swing Hacks by fellow java.net bloggers Joshua Marinacci and Chris Adamson. The reason I like the Hack Series is that even for subjects you know fairly well, these books describe interesting solutions which I hadn't realized. It's that constant discovery of "non-obvious solutions" which has kept me so interested in programming over the years.

Take compilers, for example: they just compile source code into object code, right? Hacking them is generally frowned upon because as Ken Thompson discused in his ACM award acceptance speech, Reflections on Trusting Trust, they are a great place to hide a trojan horse. But if the compiler is designed to function as a tool library, as javac is, much more interesting (and benign) hacks are possible. Mustang (excuse me, Java 6) has three related API which all Java tool hackers should check out: JSR-199: JavaTM Compiler API, JSR 269: Pluggable Annotation Processing API, and the Tree API (com.sun.source.tree and com.sun.source.util).

The Compiler API is deceptively simple: it gives you the ability to programmatically invoke javac (actually, any tool that implements the Tool interface such that ServiceLoader can find it) and compile one or more source files to class files. That's nice if you are writing an appserver container, perhaps, but not very hack-inspiring, right?

As Robin Williams said in the Disney cartoon Aladdin (I have small kids), "Wrong! But thanks for playing." The first hack leverages JSR-199's DiagnosticListener interface, which lets you listen to the errors and warnings created by the compiler. NetBeans uses this technique to display errors while you are editing Java sources; compilation is run regularly in the background but only the diagnostic events are used. JSR-199 improves on the old trick of parsing error strings with Diagnostic instances, which provide accurate source position information, and locale-independent error IDs with locale-specific error text.

Still bored? How about creating your own scripting language? Rather than write a complicated intepreter, write a (hopefully) simpler compiler which outputs Java source files. Then use the Compiler API with a custom ClassLoader to dynamically load these classes on-the-fly, as if they were interpreted. Think the process is slow? The Jackpot rule language parser generates Java sources and uses this hack to compile them (look in $HOME/.jackpot). We used to conditionally compile scripts only if they had changed, but found that javac is so fast that caching didn't make a difference (we just keep the files for troubleshooting). If you don't want to write anything to disk, a related hack involves implementing the JavaFileManager interface to use memory instead of files -- javac doesn't care about files since it only uses streams supplied by whatever JavaFileManager implementation you provide.

JSR-269 is officially the "Pluggable Annotation Processing API", and while it does that very well it also enables lots of other hacks. A general way to think of JSR-269 is that it gives you access to all of the types and elements (symbols) in any set of source files, not just its annotations. Its javax.lang.model.util package has easily extendable visitor and scanner base classes which can be used by tools to inspect projects at the semantic level. One group of tools which can use this hack include error checkers that validate design rules, such as that any class which extends Object.equals() also extends Object.hashCode(). One advantage of using JSR-269 types and elements rather than your own parser for these sorts of tests is that while you can infer many properties from a parse tree, the javac semantic model knows the correct properties.

If you want to dig deeper than types and elements, the Tree API makes this sort of hacking simpler. Because the Tree API is not defined by a JSR, the JSR-199 and JSR-269 APIs cannot directly refer to it. So if you just look at those API, it seems impossible to inspect class members beyond their declarations. The semi-secret hack here is that javac's javax.tools.JavaCompiler implementation returns a CompilationTask instance which is also an instance of com.sun.source.util.JavacTask. This class is much more interesting to tool hackers, since it give you access to the parse trees and all JSR-269 information, plus control over javac's execution. Don't need to generate class files? Just invoke JavacTask.analyze() instead of JavacTask.generate(). This class also provides access to the Types and Elements utility classes, which make hacking even easier. So if you know you are using javac as the tool provider, you can just cast the task instance to JavacTask and have fun.

These API provide a read-only model of Java source code, so it is difficult to modify source code programmatically (you can overright the files, of course, but comments and formattting get blown away). For hacking source files without angry mobs coming after you, you'll want the Jackpot API, which extends these API to provide model transforming and formatted source rewriting. These four API work together to define a toolkit to create just about any Java language-aware tool. What sort of "non-obvious solutions" can you create with them?

Munge: Swing's Secret Preprocessor

Posted by tball on September 05, 2006 at 01:57 PM | Permalink | Comments (7)

This may seem like ancient history now, but when Swing was first developed the team was sucked into a maelstrom of technical and corporate controversy. The biggest areas of contention were:
  • It must be fully JDK 1.1-compatible, distributable as a separate library;
  • It must make use of the new Java 2D and other interesting features in the upcoming Java 2 release;
  • It had to be part of the core classes, since developers didn't trust that non-core classes would be available on all Java platforms;
  • "Your VP promised us at JavaOne it would release in three months; where is it?"
JDK 1.1-compatibility plus Java 2D support (the first two items) posed a big problem because Swing needed to extend the Graphics class to cache its state for an essential performance gain, while Java2D's Graphics2D extends Graphics for other reasons. Since Java doesn't support multiple-inheritance, SwingGraphics in 1.2 had to extend Graphics2D, which didn't exist in 1.1. We tried dynamically loading two different extension classes, but found a ripple effect through our source as more and more classes that reference SwingGraphics had to be dynamically loaded as well.

This problem would be a no-brainer in C/C++: use its preprocessor. But back then one of Java's perceived advantages was that it didn't have a preprocessor, and it would have been politically-incorrect for the JDK team to then create one. A more pragmatic reason was that source was distributed and needed to be compilable without other tools, plus have full comments (cpp strips them). Another reason is that to meet our "three-month" release target, we usually skipping running make and instead ran the Java interpreter with the -checksource flag, which automatically recompiled as needed (I really miss that feature).

The other big issue was what Swing's package names should be: com.sun.swing.*, java.swing.*, javax.swing.*, some.other.wacky.name.*, etc. It sounds a bit silly today, but like a lot of engineering discussions this seemed like a life-and-death issue to many developers. People really wanted Swing in core but weren't will to wait for 1.2 to release (smart move, in hindsight ;-), and were leery about any name with "Sun" in it. Even the final names, javax.swing.*, were controversial because they didn't seem "core enough" to address everyone's concerns. Since Swing was releasing every week at that point, we wound up changing the package names several times.

So a combination preprocessor and string translator, Munge, was created to address these two problems (source). Since its requirements were that it be small, fast and require no maintenance (it wasn't a product, after all), it purposely has no features that weren't needed by the team. It won't have your favorite cpp or sed feature, but what it did, it did quickly and correctly. It wasn't open-source then, but if you wanted a feature you were handed the source and told to have fun.

Munge used an approach which is now fairly common: embed the preprocessor directives in comments so the source is still Java and can be compiled without modification. This means picking a "preferred" target, which in our case was the Java 1.1 API since we first shipped Swing for that platform. For example (from Java 1.2 SwingUtilities source), support for the Java 1.2 security API is conditionally referenced, so that only the "a doo run run" line (original comment) is executed by default:

    final static void doPrivileged(final Runnable doRun) {
      /*if[JDK1.2]
        java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction() {
                public Object run() {
                  doRun.run();
                  return null;
                }
            }
        );
        else[JDK1.2]*/
        doRun.run();  // ... "a doo run run".
      /*end[JDK1.2]*/
    }
The mystery of those gaps in the old Swing source files is now solved: Munge stripped out either the 1.1- or 1.2-specific code, leaving those gaps so the line numbers would still match in stack traces.

So why call it Munge? The main reason was to discourage developers from overusing it, so I picked a word that suggested that the tool might do nasty things to your source files (plus I'm an old Zork fan). It doesn't hurt your source files, however, and can't if you use version control (which you should).

Munge was used to build Swing until the 1.1-compatible version was finally retired, and was quietly used by other JDK teams for similarly reasons. Now that the JDK team doesn't include Munge in its build any more, hopefully other developers find it useful.

See You at JavaOne

Posted by tball on May 12, 2006 at 11:53 AM | Permalink | Comments (3)

It's been a crazy couple of months, but JavaOne waits for no engineer. Most of Jackpot's new UI has been implemented and was pushed yesterday. This spec required fundamental changes in the transformation engine, which I think strengthened its design even though it impacted the schedule. It's also more Swing form coding that I have done in a long time, but thanks to Matisse I just made the JavaOne milestone.

If you are interested in Jackpot, there will be an announcement regarding it at NetBeans Day. Thursday morning I'll be presenting Creating and Deploying Custom Jackpot Queries and Transformers (TS-1278), which will describe how developers can create their own bug-searching and fixing tools and share them with others or deploy them within an engineering organization. Friday, there will be a short Jackpot demo at James Gosling's keynote. (Looking up the URL, I just found out Scott McNealy will be hosting that keynote, too. I better "kick butt", as he likes to say, during the demo!)

If you are attending JavaOne, please check out these "Jackpot sightings" if you can. If you see me rushing down the hall, join the rush and introduce yourself.

Jackpot's Coming (Finally!)

Posted by tball on March 03, 2006 at 11:05 AM | Permalink | Comments (7)

Patience is a virtue? I never really learned that growing up, and impatience has served me and most of my fellow developers much better in our careers. So it's been a frustrating time since JavaOne lining up my ducks (an expression which probably doesn't translate well, but visualize how hard that would be) to make Jackpot available. Yesterday we had a big breakthrough, though, with marketing buy-in for a phased release plan. "O frabjous day! Callooh! Callay!� He chortled in his joy."

There were two important requirements for a Jackpot release: provide a public, stable API that doesn't reference any javac internals, and fully integrate it into the IDE environment. The good news is that the read-only Java model developed by the javac and apt teams is now almost finished and Jackpot's API has been converted to reference it. Yes, the JCP process is painfully slow for those of us who lack patience, but both teams have delivered great work that should stand the test of time.

I have been moving more slowly on the IDE-integration front, but things are looking up. Because of the focus on rewriting the engine to use the new public APIs, I haven't had time yet to write any killer transformations. The early release will therefore just have sample commands which demonstrate Jackpot's potential, so expect some disappointment when you first try it. Its UI is also much too modal: you start a "session", invoke queries and transformers, then end the session to save the changes. To make matters worse, if you edit any files in the middle of a session, the session is invalid but you won't be notified of that until you try to save. My apologies for creating such a bad interface, but it's temporary.

This week's other good news is that because NetBeans 5.5 is now in preview, I will finally get some help from the overworked NetBeans UI team. We've only had one meeting so far, but I left with several excellent ideas for better integration of Jackpot and thus a better UI. Let my mistake be a warning to others: just because you are a good coder (or even a former Swing architect) doesn't mean you are a good UI designer. I never thought I was very good at design, but this meeting reinforced that awareness of my limits -- I guess once a systems engineer, always one.

So the current plan (don't call it a schedule) is as follows:
  • Early-access release in a week or two, as soon as I can pull it all together for distribution. This release will be focused on engineers interested in exploring Jackpot's rule language and API so they can write their own queries and transformation (you can join the project here). We're looking to attract smart engineers who want to create and contribute transformations for the rest of the world to use. As I said, the UI will be rough and the included set of commands very limited, so this release won't be of much interest to folks who just want to use canned commands. This first release will just be NetBeans binary modules, since I don't want to hold up access while going through the open source process steps. Source code for the distributed queries and transformers will be provided as samples, however.

  • Because we'll be distributing Jackpot via the NetBeans Development Update Center, there will be frequent updates depending upon community feedback. We'd like as much feedback and response as possible, similar to Swing's pre-1.0 bi-weekly updates that proved so useful. Source code for Jackpot's IDE integration and rules editor modules will be made available in the NetBeans CVS repository during this period.

  • A beta release of Jackpot, with the new UI and richer command suite, is targeted for the JavaOne 2006 timeframe. Because this will be a more stable release, it can be distributed via the NetBeans Beta Update Center and run on NetBeans 5.0 or 5.5.

  • Jackpot 1.0 in early fall 2006, depending upon feedback and meeting normal release requirements.
I want to thank you for (im)patiently waiting, and look forward to your comments, suggestions, and criticism once Jackpot is available.

JavaOne Jackpot Talk Available

Posted by tball on November 01, 2005 at 07:16 PM | Permalink | Comments (4)

For those of you unable to attend my talk on Jackpot at JavaOne last June, the presentation is now available either as a multimedia web show (audio and synchronized slides) or as a PDF file. You need to be a Sun Developers Network member, but registration is free and only takes a minute or so. Once you are registered, here is the talk. BTW, all of the presentations are available, not just mine!

CVSspam: Very Cool CVS Notification Tool

Posted by tball on October 25, 2005 at 12:31 PM | Permalink | Comments (6)

One feature I rely on for shared development is for the source control system to email a notification of any changes. CVS supports this notification and it is easy to implement: just add an email command line to the repository's CVSROOT/loginfo file (or separate ones for each project, if desired). The problem I have with these commit messages is that while they describe what projects and files have changed, you either get a verbose diff message or have to use a separate tool to see what changed. Consequently, after enough of these messages fill up my inbox I tend to just scan them quickly without reviewing the changes.

We recently upgraded an internal CVS repository to use CVSspam to format CVS commit notification messages, and what a difference it makes! CVSspam generates HTML-formatted commit messages that use colors, fonts, and a nice design to allow me to do a much more thorough review of the message in the same time that I did for just a quick-scan of the old format. Here's a simple example (snapshot from my email client):

CVSspam screenshot

It's obvious what file changed and where. What this example doesn't demonstrate is how easy it is to review a large set of changes, since each changed file is listed at the top and linked to its section. The column listing for how many lines were changed in each file is also a helpful scanning aid; I often just focus on the file with the most changes, as it is usually the one that can benefit the most from a code-review. Here is a big example report from the CVSspam site -- notice how the report found TODO and FIXME comments in the source files and made links to them.

The bottom line is that with CVSspam, informal code-reviewing just got easier.

Can't Tell the Forest for the Trees

Posted by tball on September 20, 2005 at 08:39 AM | Permalink | Comments (3)

One big reason Jackpot hasn't released yet is because it is tightly bound to javac's private modeling API for abstract syntax trees (parse trees), types and symbols. The two teams have been working together on how such an API can be exposed without locking down javac and preventing future innovation.

The solution the javac team designed is an interface-based AST abstraction, which javac will implement while still keeping its internal implementation private. This, along with the proposed enhanced Mirror API that is part of JSR-269: Pluggable Annotation Processing API as well as JSR-199: Java Compiler API, will be the only javac API that Jackpot developers will use.

Interested? Peter von der Ahé has a blog entry describing how to join Tree API project. See you there!

JFind: a simple jar file locator

Posted by tball on September 03, 2005 at 01:24 PM | Permalink | Comments (13)

I'm a big fan of the Unix find utility for managing large projects. One task that's difficult to do with it, however, is finding which jar file contains a Java class -- you can't use search commands like grep because it will match on any class that references your target, not just the defining class itself. There are several utilities that do this on the web, but most are big GUI-based tools which seem like overkill for what should be a small job.

So a while back I wrote a simple command-line utility called JFind, which is now in the NetBeans repository here. It's a single, simple class, which relies on the java.io and java.util.zip packages to do the heavy lifting. Just specify the class or package you want to find and a directory to start your search, and it will report the jar file or path that defines it.

For example, to find which jar provides org.openide.ErrorManager in a NetBeans distribution, run:

    java -jar jfind.jar org.openide.ErrorManager dist
To find which jar provides the javax.crypto package in the JDK:
    java -jar jfind.jar -p javax.crypto JDK-directory
One could write a more complex, Swiss-army-knife-like utility (like the Unix find utility), but sometimes short and sweet works best.

Project Jackpot at JavaOne

Posted by tball on June 15, 2005 at 11:35 AM | Permalink | Comments (11)

My apologies for not writing recently, but it has been for a good reason: I will be giving a JavaOne presentation on Project Jackpot: A New Java™ Technology for Source Transformation, and have been working hard on a NetBeans plug-in to demonstrate it. I am really excited to be able to finally discuss our work to such a wide audience.

What a long, strange trip it's been! James Gosling and Michael Van De Vanter started the Jackpot Project at Sun Labs back in the spring of 2000, and I joined a month later. For the first three years, "Jackpot" was just the project name while we investigated different ways tool improvements can enhance Java developer productivity. Rather than publish papers with our ideas, we made the radical decision (for Sun Labs, anyway) to publish our results as open-source NetBeans modules. The metrics (now obsolete) and classfile modules are a couple of Jackpot "publications".

In late 2002 we focused on an experiment James developed which read Java source into a model, applied transformations to that model, and then wrote the model back to source files. What was different about his approach is that its model allows a tool to make much more radical (but safe) changes to Java source code than is possible when working with syntax trees. The need for a deep understanding of the Java type system in a source transformation tool became even more apparent when generic types were added in Java 5. Project Jackpot therefore uses every scrap of information it can pull from javac rather than try and create its own parser, as it is a huge effort to correctly model all of the subtleties of the Java language.

When James became Sun's Chief Technical Officer of the Developer Products Group, the rest of Project Jackpot transferred over as well to the NetBeans core engineering team. Jackpot was put on hold so that javac's parser and error-checker could be leveraged by the NetBeans refactoring engine and editor. Once 4.0 released, the Jackpot engine has been re-designed and re-written (hey, it was just a research prototype!). Now that this rewrite is fairly stable, my top priority is incorporating Jackpot into NetBeans so Java developers can start using it. And yes, the plan is to make it an open-source project, just like the rest of NetBeans. As my father used to tell me, there is no rest for the wicked. :-)

I hope you are coming to JavaOne and can attend my session on Tuesday, June 28th at 1:30. I will also be attending NetBeans Software Day on Sunday the 26th. After JavaOne I will be writing more often about Project Jackpot and the tips and tricks I learned while developing it.

JackpotIcon.png


Optimize a Swing App by Slowing It Down

Posted by tball on April 11, 2005 at 04:54 PM | Permalink | Comments (4)

Swing is slow, right? That seems to be a common perception which fast Swing apps like LimeWire seem unable to shake. Even the Jackpot GUI app is sluggish these days, and we all know it cannot be that my code is at fault, right?

I think the real problem is that yours and my computers are too fast, or at least too fast relative to our customers' systems. Because software developers and quality testers tend to have very fast systems so they can multi-task effectively, an unfortunate side-effect is that they tend to run their applications faster than their customers do. As a result, it's easy to overlook inefficient and redundant GUI operations as long as the result looks and feels okay on a fast system. Slow your system down enough, however, and these problems leap out at you, demanding attention.

One easy way to slow down a Swing application is to turn on DebugGraphics functionality. Although DebugGraphics was designed to display potential problems with display painting and layout, it has a nice side-effect of pausing after each paint operation (otherwise you wouldn't be able to see it work). Here is an example of how one might use this:

    private static final boolean debugGraphics = true;
    ...
    if (debugGraphics) {
        DebugGraphics.setFlashTime(100);                 // 100 ms. pause
        DebugGraphics.setFlashCount(1);                  // only pause once per paint
        DebugGraphics.setFlashColor(new Color(0,0,0,0)); // no color

        // turn off double-buffering, or this gets optimized away!
        RepaintManager.currentManager(myComponent).setDoubleBufferingEnabled(false);
        myComponent.setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION);
    }

The first time you run this code, do so in the debugger. If it appears to hang, suspend the app and see where it is stuck. When I first ran it on my app, I had turned DebugGraphics on for my whole component tree -- DebugGraphics was pausing after each bump was drawn on my JSplitPane slider! Not very useful...

Once I only turned debugging on for my main panes, it became painfully obvious that some operations of my apps GUI operations were redundant. My app has a JTable which is supposed to select a JTree node when a row is clicked, but selection was happening multiple times. Setting a breakpoint on my ListSelectionListener showed I needed to first check ListSelectionEvent.getValueIsAdjusting() and only handle the event if its false; failing to do so was causing a new list selection event to be fired for each entry in the tree path for that node (maybe Swing wasn't the problem after all!). These multiple selection events were not that noticeable on my fast system, but after fixing this and other similar problems, the GUI is much perkier.

I am going to leave this code enabled in my app for a few more days. The slow display will irritate me a lot, and so I'll just have to make it faster some other way. Wish me luck!

Exceptional Debugging

Posted by tball on April 04, 2005 at 03:36 PM | Permalink | Comments (9)

Exceptions (and their stacktraces) are one of the features that first attracted me to Java back in early 1995; C++ obviously had exceptions, but I never worked with any C++ projects that used them as effectively as the Java core classes did. I find well-designed exceptions to be a significant productivity booster.

My first project on the JDK team was developing the debugger API, and I think it was the first debugger where you could set a breakpoint that tripped whenever a specified exception type was created (please correct me if you know of earlier systems). The justification for exception breakpoints was simple: exceptions (should) indicate abnormal control flow in a program, and since we spend most of our time in debuggers figuring out why our programs are acting abnormally, there should be an easy way to halt whenever the program is indicating something worth investigating.

But few engineers I've met use this feature, and it puzzles me a little. Most recently, I filed a NullPointerException problem which didn't log a stacktrace, and the assigned engineer first added logging code so he could get a stacktrace to see where the problem was, which he then spent a lot of time reading various source files to determine what could have caused it. If he had instead set an NullPointerException breakpoint, the debugger would have stopped at the offending statement with all of its local variable and stack information immediately available. This is much, much faster than running until a stacktrace prints, editing the code to add debug statements if the cause isn't obvious, and looping until the problem is figured out. Isn't impatience supposed to be one of the attributes of a good programmer?
Exception breakpoints can be useful even when you aren't debugging exception failures, too. In NetBeans, I always have breakpoints set for NullPointerException and AssertionError (running with the -ea flag), to catch these conditions as soon as they rear their ugly heads.

I have heard complaints that exception breakpoints are "too noisy" because they can trip in places you don't expect. I think this indicates a couple of potential design flaws:
  • Overly general exceptions: although you don't need a separate type for all possible exception cases, it is often very useful to do more than "throw new InternalError()" when a problem arises. The java.io package derives FileNotFoundException and EOFException from IOException, since for many apps these are much more common recoverable error conditions than, say, a SyncFailedException. A custom exception is a great documentation aid if you have a public API, and exception classes are simple to create and maintain.

  • Using exceptions for flow control: as Josh Bloch argued in Effective Java, "Use exceptions only for exceptional conditions" (item 39). In the Solaris JDK a few years back, for example, system font files were discovered by trying to open all possible font names and catching all the FileNotFoundExceptions. This was much slower and more memory intensive than using File.exists(), due to all the exception object creation and collection. If your program is querying a class by poking it and testing for exceptions, add a method to that class to get the information directly.
Another complaint is that exception breakpoints catch exceptions in OPC ("other people's code", the source of all developers' woes :-). For example, Swing uses NullPointerException for flow-control in a couple of places, so I filed bugs when they tripped (should be fixed in Mustang) and now just hit continue. I strongly recommend filing such bugs as you find them (along with a recommended patch), so as to eliminate these nits and improve the Java platform as a whole. After all, the more successful it is, the more successful we Java developers will be.

The Most Powerful Refactoring?

Posted by tball on March 07, 2005 at 02:01 PM | Permalink | Comments (13)

As earlier readers have probably figured, I'm working on automated Java refactoring technology these days. It's becoming a crowded field with some really good tools already out there, but since I'm a normal software engineer I know I can do better. As Alexander Pope stated, "Fools rush in where angels fear to tread," and as my family will attest, I am no angel.

Now that the Jackpot engine is humming along nicely, our marketing folks want it to demonstrate some "powerful" refactorings from Martin Fowler's book, Refactoring: Improving the Design of Existing Code. From a tool perspective, there are certainly some hairy refactorings to consider implementing, such as "Extract Method" or "Replace Inheritance with Delegation", but I do not use those very often, and when I do it's always by hand.

Perhaps I am looking at this problem incorrectly. The above book defines refactoring as "... the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure." I want to add to that description: "... or increases its clarity." As a production developer, I rarely get to work solely on my own code; I inherit other engineers' work and pass it on afterwards to still others. A big source of bugs in this environment is source that is hard to understand, code that doesn't clearly describe its functionality and the intentions of its authors. Consequently, much of my refactoring cleanup involves changes that make the code more "obvious" to the next engineer in the chain. Most well-applied refactorings do just that.

So what is my candidate for most powerful refactoring? It's "Rename Class", which isn't even in the book! "Rename Method" is, however, and the author's description of its benefits also apply to classes and variables. I use the beta 4.1 version of NetBeans, and find I'm frequently renaming classes since its refactoring support makes it both easy and fool-proof (being a fool, I need the proofing!). I change class, method and variable names as my understanding of their purpose improves, and a nice side-benefit is that it makes picking them from a code-completion list faster since their names are more obvious.

So, what refactoring has your vote as "most powerful"?

The New Golden Hammer

Posted by tball on October 19, 2004 at 11:48 AM | Permalink | Comments (7)

I think all Java developers have at one time or another fallen in love with a new technology and wanted to use it to solve all problems; after all, when you have a "golden hammer", every problem starts looking like a nail. Remember when Java Reflection was all the rage when it was first introduced? All of Java's perceived ills could be solved with it, provided one ignored how slow and unreadable the solution using it was. Now the "first love glow" has subsided, and reflection is now an important but specialized technology in our toolkits.

With the release of Tiger, annotations are rightly getting developers excited, but its companion tool, apt, is starting to look a little too golden in my view. Last week, it was suggested that apt should replace javac, and while I applaud that sort of "out of the box" thinking, others are taking a cool thought experiment too literally. Users have already complained on the NetBeans forums about how its upcoming release doesn't support this "feature", even though the apt Mirror API doesn't support code types that a compiler needs.

I think what bothers me about wild apt scenerios is that folks are forgetting (or ignoring) the problem annotations are trying to address: that much of the specification for a class is done outside of its source code in other files, or is done in repetitive boilerplate code that has little to do with the class's problem domain. Information about a class is called metadata, and annotations allow developers to define metadata without external files (other than new annotation type declarations), special naming patterns or other error-prone hacks.

Java developers have been creating ad-hoc solutions to this problem for years. If you look at the Swing sources, for example, you'll find undocumented "@beaninfo" Javadoc tags, which a custom doclet in its build uses to create its BeanInfo classes (XDoclet is an excellent tool that takes the grunt work out of such metadata file-generation doclets). Another tool that adds pre and post-condition checking via custom doclet tags is JContract. The problem with these approaches is that, like all comments, metadata stored in comments can drift away from the source if not carefully tracked by its developers. It's also fragile, in that this metadata isn't checked for typos; for example, try misspelling "@deprecated" in a doc-comment and notice how the compiler just ignores it as comment text, instead of either recognizing it or reporting it as an error.

The Java 1.5 annotation support doesn't fix all metadata problems, but it helps in several ways. First, annotations are true Java types whose definition and usage are verified by the compiler. This makes it much harder to break metadata with a typo, but more importantly it means that if you enhance the definition of an annotation type and forget to update a class that uses it, the compiler will catch that error. I'm very partial to letting the compiler do as much project validation as possible (followed by my unit test suite). It also allows metadata to be discoverable in a standard way in classfiles and at runtime, so that tools like deployment tools or introspectors don't have to use external files and classes.

What makes apt and annotations so exciting to me is that anyone can write an annotation processor as easily as an XDoclet module, writing metadata using a verifiable Java language facility instead of comment text. So instead of trying to see how apt can replace existing tools, look at all the metadata your project has and see how it can be better handled using annotations. If your classes take more than one file to define (such as a factory or "info" class), has boilerplate code in it or doc-comment tags that aren't documentation-specific, consider defining it using annotations. If you need a compiler, stick with javac or jikes.

The Problem with Unit Testing

Posted by tball on October 08, 2004 at 12:47 PM | Permalink | Comments (3)

"Writing tests is QA's job." I've heard that line ever since I started being paid to program over twenty-five years ago. It wasn't just from other developers looking to cut their workloads, but also from my management, QA engineers and their management. Since QA is responsible for product testing, unit tests fall within their jurisdiction. Go back to coding, Tom, and leave the testing to the professionals.

When Kent Beck started promoting a test-first best practice as a part of eXtreme Programming, lots of testing experts weighed in on the importance of full-coverage and other metrics in unit tests, invasive strategies for testing private methods, and other heavyweight procedures to ensure test "compliance". My reaction, like most developers, was summed up elegantly by King Arthur in Monty Python and the Holy Grail: "It's the legendary black beast of Aaaaauuuugghhhh! Run away! Run AWAY!!!"

Remember how at the circus there are the trapeze artists that use a net, and the "daring" ones that don't? As a kid I noticed that the non-daring ones actually did much cooler, more difficult tricks, because they had the net! Without the net, the artist has to be more careful and circumspect in his work, or make a big (possibly final) splat in front of his fellow artists. Like most developers, I hate making a big splat (breaking the build, introducing showstopper bugs, etc.) in front of my peers. It's a good aversion to have when working on a team, but it can lead to paralysis if you lack confidence that your changes are correct.

As a development engineer, all I want from unit testing is a safety net, not a huge, QA-approved test monster (for awhile, JavaSoft only had the JCK to do automated testing, which required a very large disk partition and took hours to run). So over the years, I've built several safety nets, keeping them hidden and avoiding names with words like "test", "quality", "verification", etc. The problem with a single tool as a safety net is that like all software it grows over time and becomes its own maintenance headache (to my horror, management learned of one of my test tools and shipped it!).

The advantage of a safety net approach is that it allows me to focus on those areas where I'm most likely to "fall": difficult algorithms, past regressions, murky designs. Shining a unit test light on the latter has proven especially important, as writing tests for some feature I haven't given enough thought to tends to highlight the bad aspects of my design. It also shows testability problems which seem to me to be directly related the cost of maintaining that code. Testable code is maintainable code, and like most developers I would rather write new code than maintain old.

But a safety net approach differs from full testing in that it is much more lightweight practice, which takes less time for me (as a developer) to implement and enhance. Unlike traditional testing approaches which can hurt my individual productivity, having and enhancing my safety net improves my productivity, because like a trapeze artist, I am able to implement more impressive changes to my code without fear of breaking it. These days, I'm a happy JUnit user who finds JUnit's green bars to be a great mood and productivity enhancer. My safety net of unit tests is very incomplete from a QA perspective, but it continues to improve along with my current project.

So what's the problem with unit testing? Unit tests are not tests, but rather a developer's safety net. QA doesn't own unit testing, developers do, and it's an important tool to be shared with your fellow developers on any project. Rename this engineering best practice, and it will be perfect.



Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds