Jesse Glick

Thursday Jun 04, 2009

Chronicle of a ConcurrentModificationException Foretold

In a somewhat feverish mid-conference dream last night, I invented a new Java complexity metric. It is quite simple: the number of calls to methods which either return void or take no arguments or both, including calls to no-argument constructors.

As a quick example, you can see that any usages of the bean "pattern" will cause this count to shoot upwards rather quickly.

The metric is called the code's "omen".

Monday Mar 23, 2009

Hudson support in NetBeans

NetBeans 6.7 M3 includes the first version of a new integrated support for the Hudson build engine.

New and Noteworthy entry

Wednesday Sep 24, 2008

Many annotations are referentially @Opaque

Often Java elements (such as classes or methods) have meaning beyond their "denotational semantics": the name (or, occasionally, just presence) of the element itself is significant to how the application runs, beyond simple references from other Java source code. For example, a field marked with @javax.persistence.Column cannot be freely renamed or shuffled around according to traditional refactoring tools.

It would be great if there were a consistent way to mark these kinds of annotations. Authors of Java frameworks could then indicate to tools that Java elements marked with them need to be treated conservatively.

My suggestion is to introduce a meta-annotation (i.e. annotation placed on other annotations): @Opaque. Here is source code for the annotation and some possible example usages.

Thursday Apr 17, 2008

Update of framework for declarative registration through annotations

I have committed an update to SezPoz, a library letting you register elements of an application (such as menu items in a GUI) declaratively using nothing but Java-language annotations.

The update provides support for JSR 269 in addition to JDK 5's APT; now you can use SezPoz with no special build steps so long as you compile under JDK 6's javac (or another 269-compatible compiler). In addition, it provides better support for incremental builds.

I would be interested in feedback from anyone who has been looking for a lightweight framework for registering features in a modular application.

Saturday Jan 19, 2008

TeamWare to Mercurial history conversions

Since Google shows no options for converting TeamWare workspaces to Mercurial (beyond an OpenSolaris-specific incremental tool), and I had some scripts sitting around that can be used for this purpose, I am sharing them in the hopes that someone will find them useful. These scripts are by no means polished, and may or may not work for you as is.

Here is roughly what you need to do:

  1. Get your TW workspace unpacked somewhere, say /tmp/project-tw.
  2. Make sure you have installed: Perl, CVS, RCS, and Mercurial (0.9.5+).
  3. Install SCCS if you do not already have it. (You do not need TeamWare installed as the scripts just use the SCCS layer.) For Ubuntu 7.10 users, just use: sudo apt-get install cssc, and add /usr/lib/cssc to your $PATH.
  4. Download and make executable: sccs2exploded.pl
  5. First we convert the workspace into an "exploded" series of snapshots with some metadata. Run: sccs2exploded.pl --indir /tmp/project-tw --outdir /tmp/project-exploded
  6. Download and make executable: exploded2cvs.pl
  7. Run: cvs -d /tmp/project-cvs init
  8. Now we try to "implode" the snapshots into a CVS repository. (If you needed to do any cleanups of log messages etc., you could do that most easily on the exploded repository.) Run: exploded2cvs.pl --indir /tmp/project-exploded --outdir /tmp/project-cvs/module
  9. Run: cvs -d /tmp/project-cvs co module
  10. Run: hg convert module project-hg
  11. Inspect project-hg, your new Mercurial workspace. You may need to hg up -r tip -C to get to the "tip" revision. If there are some branches imported from TeamWare, you may need to see what they are using hg heads and resolve them using hg merge.

Good luck! I have run this procedure on Ubuntu on a small TeamWare workspace successfully, but for big projects there could well be some complications. Features and limitations:

  • File deletions (deleted_files) should be correctly imported.
  • Branches (lines of development) may be imported, though I don't really know a lot about this. YMMV.
  • File renames will not be imported, as CVS cannot represent this.
  • Freezepoints are not imported as tags, sorry.

Tuesday Oct 10, 2006

No more uninformative Issuezilla page titles

Are you a Firefox user? Using Greasemonkey you can fix netbeans.org Issuezilla to display issue summaries in the page title, not just the issue numbers. Much nicer when using tabbed browsing and opening a lot of issues at once. Download and install the attachment from:
#57291
Currently only works when you are logged in.

Update: this and other tools are now hosted elsewhere.

Thursday May 18, 2006

BOF-0220 ("Test Patterns in Java") follow-up

Some people who came to BOF-0220 ("Test Patterns in Java") were asking about slides, demo sources, and/or the NB-JUnit library used in the demonstrations. You can find these things, plus a longer exposition of the ideas summarized in the BOF, on the NetBeans website:

Test Patterns In Java

Sunday Feb 19, 2006

Pick a target JDK for a freeform project in NetBeans

I know, I know, long overdue, but here it is anyway: a little tool to assist you in building and running a "freeform" project (existing Ant script) using a different JDK from what NetBeans is running on. Ant tasks like javac and the like have long supported selecting a particular JDK executable to use (means they must fork to run the tools), but few people would want to remember to set these attributes consistently. Instead, this tool uses the magic of presetdef to do it for you. The upshot is that freeform projects behave a little more like other projects.

Download the Freeform Project Extras 1.5 NBM (NetBeans 5.0+ compatible)

If you were really paranoid you could make your test target run all your unit tests in turn on each supported JDK...without leaving the IDE. But that's for you to write.

Wednesday Feb 15, 2006

jrunscript in a target VM

Mustang's jrunscript is cool, but it just launches a new VM and runs your script. Sometimes you want to find out what is going on in an existing process, or control it somehow, using JavaScript. Now you can! Download jrunscriptin.jar and run with

java -jar jrunscriptin.jar
(on Mustang) for usage information, quoted here for your convenience:
Usage:
  java -jar jrunscriptin.jar <PID> 
    where <PID> is as in jps
  java -jar jrunscriptin.jar <match> <JavaScript>
    where <match> is some substring of the text after a PID visible in jps -lm
Example using NetBeans IDE (quoting as in Bourne Shell, adapt as needed):
  java -jar jrunscriptin.jar netbeans \
  'Packages.org.openide.awt.StatusDisplayer.getDefault().setStatusText("Hello from abroad!"); \
  java.lang.System.out.println("OK!")'
Requires Mustang (JDK 6) for both this tool and the target VM.
Sources

Mustang agents can be used to probe running NB instances for data

Just thinking about how to extract useful information from a running NB platform instance. Not so hard to do using Mustang, it seems. You can use an API (supported in the Sun JDK at least) to connect to VMs running NB on the same machine and run some code in that VM, which can with a little work make use of NB APIs: project ZIP The API: com.sun.tools.attach A little annoying to develop such an agent incrementally because you can't reload the same agent classes in a given target VM, and Mustang seems to also reject attempts to call loadAgent twice with the same JAR. A workaround is to rename both the agent JAR and agent main class each time you test it. Probably this could be automated somehow, or you could have a "stub" agent which you never change, which just loads a named JAR in a fresh class loader and runs it. Next stop: figuring out how to use this as a stepping-stone to set up a regular JMX client connection. The rub is that jconsole has a nice UI to let you pick a VM to attach to from among locally running VMs, but then shows a generic JMX browser. I want to write a domain-specific JMX GUI client that (in the spirit of requiring zero configuration) will by default display all VMs running on the local machine matching some pattern. The goal is a general-purpose NB runtime inspector: #69773

Sunday Feb 05, 2006

Continuations supersede SwingWorker and Foxtrot

SwingWorker is a pretty complete approach to off-event-queue execution, but clumsy syntactically:

http://download.java.net/jdk6/docs/api/javax/swing/SwingWorker.html

FoxTrot improves the API a bit for the simple cases but relies on the funky trick of pushing a new event thread:

http://foxtrot.sourceforge.net/docs/worker.php

Turns out that using continuations you can make the simple cases even simpler. Try running the following using Mustang's jrunscript -f demo.js:

function cont() {
    return new Continuation();
}

function offEQ(execsvc) {
    var c = cont();
    if (c instanceof Continuation) {
        execsvc.submit(
            new java.lang.Runnable({
                  run:
                    function() {
                        c();
                    }
                })
            );
        return true;
    } else {
        return false;
    }
}

function onEQ() {
    var c = cont();
    if (c instanceof Continuation) {
        java.awt.EventQueue.invokeLater(
            function() {
                c();
            });
        return true;
    } else {
        return false;
    }
}

function showThread() {
    print(java.lang.Thread.currentThread());
}

var swing = Packages.javax.swing;
var frame = new swing.JFrame("Demo");
frame.setLayout(java.awt.FlowLayout());
var button = new swing.JButton("Start");
var es = java.util.concurrent.Executors.newSingleThreadExecutor();
button.addActionListener(
    function(event) {
        field.setText("clicked");
        button.setEnabled(false);
        for (var i = 0; i < 10; i++) {
            field.setText("sleeping #" + i);
            showThread();
            if (offEQ(es)) return;
            showThread();
            java.lang.Thread.sleep(1000);
            if (onEQ()) return;
            showThread();
        }
        field.setText("done");
        button.setEnabled(true);
    });
frame.add(button);
var field = new swing.JTextField(20);
frame.add(field);
field.setText("idle");
field.setEditable(false);
frame.setDefaultCloseOperation(3);
frame.pack();
frame.setVisible(true);
java.lang.Thread.sleep(9999999);

Unfortunately continuations are not available in Java itself, only in the bundled Rhino JavaScript. Some day...