Thursday Mar 11, 2010

A better NetBeans menu bar

Quick Search in menu bar

If you only use a couple of toolbar buttons but do not want to waste the vertical space required to show a regular toolbar - say because you use a smaller laptop screen - you can get NetBeans to insert the buttons into the menu bar.

Just shut down the IDE, then go into the config subdirectory of your NetBeans user directory (location varies; see Help > About). Create a subdirectory Menu, and in it create three files:

  1. org-openide-actions-GarbageCollectAction.instance (empty)
  2. org-netbeans-modules-quicksearch-QuickSearchAction.instance (empty)
  3. .nbattrs containing the text:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE attributes PUBLIC "-//NetBeans//DTD DefaultAttributes 1.0//EN"
                 "http://www.netbeans.org/dtds/attributes-1_0.dtd">
    <attributes version="1.0">
        <fileobject name="org-openide-actions-GarbageCollectAction.instance">
            <attr name="position" intvalue="9000"/>
        </fileobject>
        <fileobject name="org-netbeans-modules-quicksearch-QuickSearchAction.instance">
            <attr name="position" intvalue="9010"/>
        </fileobject>
    </attributes>
    

After restarting the IDE you should see two new buttons in the menu bar.

Wednesday Feb 17, 2010

Using an annotation processor to enforce Java-like access rules

Sometimes you need to expose a method from one class to another class, but do not wish to make this method public for anyone to call (because you are not prepared to maintain it compatibly forever). If they happen to be in the same package, you can just use package-private access. But this does not work if they are not in the same package.

Some module systems - NetBeans, OSGi - let you declare that some packages or classes are not to be accessed outside of the declaring module, even if marked public. The FriendPackages pattern can be useful in case you want to expose your method to a class in another package so long as that other package is private and is in the same module. But there are many cases where you want to make a method accessible to a particular caller in another module.

Ideally you could just use something like Java's public keyword - i.e., an annotation. But what would pay attention to that annotation? Well, an annotation processor. (At least at compile time; runtime access checks are another matter, but anyone using reflection probably knows how to call setAccessible anyway, so runtime checks would only be useful in security sandboxes.)

If you are compiling using JDK 7, the new AbstractTypeProcessor class in the Tree API lets you write annotation processors which not only can examine the full source tree, but get access to type information - such as what the receiver type of a method call is. This is critical.

I have started to prototype an annotation @Public which can be placed on a nominally public member to declare that it should be visible only to the enumerated classes; and an accompanying annotation processor: PublicProcessor By placing the JAR containing the annotation and its processor in your classpath, and compiling with JDK 7+ javac, you can have a new access modifier intermediate between package-private and public!

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

Saturday Feb 04, 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...

About

jglick

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today