Archive

Archive for April, 2010

Code bloat and its inevitability in Java

April 27, 2010 5 comments

[I]f you begin with the assumption that you need to shrink your code base, you will eventually be forced to conclude that you cannot continue to use Java. Conversely, if you begin with the assumption that you must use Java, then you will eventually be forced to conclude that you will have millions of lines of code.

Steve Yegge has an excellent rant on code bloat and its inevitability when using Java.  He makes some very cogent points about refactoring and design patterns, using the metaphor of spring cleaning.  Refactoring and design patterns can be seen as neatly organizing your stuff within compartments in a closet, but if you aren’t able to throw things out, you never will really have a clean code base.  Furthermore, he argues that Java necessitates code bloat and duplication, as it lacks certain features that are necessary to really shrink code bases (lambda functions, closures).

He concludes his article by considering some alternative languages that run on the JVM; it’s an older article (from 2007) and he choose Rhino as his language of choice to rewrite his game in (currently 500 thousand lines of Java code).  I’d be interested to see if he were to revisit this article if he would choose Scala instead. It seems to be a natural fit for what he’s trying to do; it runs in the JVM but adds functional programming features that would surely reduce his source code line count. In the comments many people suggested Scala, but he dismisses them by saying

“Scala folks and Groovy folks: you’re not big enough yet. For something as big as my game, I want a proven mainstream language. I picked Rhino as a complicated multidimensional compromise; the actual reasons are a full blog post. But the short answer is “you’re not big enough.” Sorry.

Given Scala’s somewhat more mainstream position these days, I think he’d be forced to reconsider.

This article hits home for me, because the verbosity of Java is a thing I struggle with on a daily basis; it is definitely one of my biggest complaints about the language, and it makes it a breath of fresh air to use something more expressive and concise, like Python.

Categories: Java, scala Tags: , ,

NetBeans Platform Tip #2: Persisting state in TopComponents

April 27, 2010 1 comment

Given the fact that NetBeans remembers the size, location, and layout of all your TopComponents, it isn’t too surprising that there is an easy mechanism for persisting state information.  Unfortunately it’s not immediately obvious; if you don’t stumble onto the right resources, you might be led to believe you need to deal with the Preferences API or writing to a database or some other flat file, and reading it later.  Fortunately it’s easier than that.  Assume we have a list of Strings we want to remember between invocations of our top component; somehow we get them from the user (the details of that are not important here), and we’d like to remember them.  The secret is in the writeExternal and readExternal methods, which are called when the TopComponent is serialized (saved) and deserialized (loaded).  Also make sure the persistence type you return is TopComponent.PERSISTENCE_ALWAYS; otherwise NetBeans will not attempt to save your TopComponent between invocations of your app.

public class TestTopComponent extends TopComponent implements Serializable {

    private List<String> strings = new ArrayList<String>();

    public EngineeringTableTopComponent(Collection<String> toSave) {
        initComponents();
        this.strings.addAll(toSave);
    }

    public EngineeringTableTopComponent() {
        this(Collections.EMPTY_LIST);
    }

    public void initComponents() {
         // Create GUI
    }

    @Override
    public int getPersistenceType() {
        return TopComponent.PERSISTENCE_ALWAYS;
    }

    /**
     * Save the state of the top component, including which properties are displayed
     * @param oo
     * @throws IOException
     */
    @Override
    public void writeExternal(ObjectOutput oo) throws IOException {
        super.writeExternal(oo);
        Object toWrite = new NbMarshalledObject(strings);
        oo.writeObject(toWrite);
    }

    /**
     * Restore the state of the top component, including which properties are displayed
     * @param oi
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Override
    public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {
        super.readExternal(oi);
        NbMarshalledObject obj = (NbMarshalledObject) oi.readObject();
        strings  = (List<String>) obj.get();
    }
}

NetBeans (IDE) Tip #1: Project Groups

April 26, 2010 2 comments

My coworker showed me a great feature of NetBeans that any developer would do well to learn – it’s called Project Groups.  You can see a small screen cast illustrating the concept here.

The general idea is that NetBeans remembers a set of projects and the associated open files as a Project Group; when you switch between project groups, your settings from the last session are restored.  This is illustrated in the above linked video, but it doesn’t show the main reason I like it so much, namely the ability to create Project Groups automatically from specific folders on the hard drive.

The feature is accessible via File -> Project Group -> New Group.

If you have multiple projects you are juggling, you can create one project group for each project root folder, and then switch between them easily.

I don’t often go digging through menus, so I am indebted to my coworker pointing this feature out to me; I use it on a daily basis and it helps ease the burden of context switching by hiding all the irrelevant projects.

Categories: Uncategorized Tags:

TextMate: Column editing, filter selection through command

April 21, 2010 1 comment

I’ve mentioned TextMate before, as it is the best general purpose text editor I have found on the Mac.  I’d like to show you some of the neat features that I’ve discovered/been told about, as well as examples as to how they are useful.

The first thing I’d like to show you is column selection.


Standard selection

Column selection

You enter column editing mode by holding down the alt/option key; you’re pressing the correct button if your cursor changes into a crosshair.  At that point, you can select rectangular regions of the text.  You can copy and paste them like normal, but that’s not why this mode is useful. If you’ll notice, if you begin type, what you type is inserted at the same point on each of the lines you have selected

This came in very handy today when I had to write a copy constructor for a class that had a huge (> 40) number of variables.  (Yes, in most cases a class should be a lot more than a bag of variables.)  For those unsure of what a copy constructor is, it basically allows you to clone objects, making a new object but using the state information from an existing instance of that class. NetBeans has a lot of support for refactoring, but nothing I found did this automatically; I copy and pasted the variables into TextMate due to the features I’m about to illustrate.

public  class TextMateExample {
 private int varA;
 private int  varB;
 private double varC;
 private int varD;
 private float varE;
 private int varF;
 private  String varG;
 private int varH;
}
 

Use the column selection to get all of the variable names and potentially some of the variable type declarations; don't worry about the excess.

Paste it underneath.

Clean it up, first by chopping off excess on the left, and then manually editing the extra stuff out.

Now it's easy from here.  Paste the column of variable names to the right

We'll call our copied object 'other', and obviously the current object as 'this'.

Make a 0 width selection to the left of the first var column, then type 'this.'

Select the semicolon column and the whitespace in between, and replace it with '= other.'.

Place this block inside a new constructor, and you're all set

The last thing I want to illustrate is how to use the 'filter through command' feature in TextMate.  Any arbitrary selection in TextMate can be used as the input to any command line script you can think of.  This is extraordinarily powerful, especially if you are familiar with the Unix command line.

Let's say that you want to replace all the raw variable access with the corresponding getter methods, for whatever reason. Use the column selection to insert 'get' between the other. and the variable name

The Java Beans getter/setter convention would be to name those variables getVarX, not getvarX.  Since they're named this way, that would be extraordinarily easy to fix; select the column of lower case v's, hit V, and all the v's are instantly replaced. Let's assume that our variables are named much differently, though following JavaBeans convention.  In other words, we want to capitalize the first letter following the word 'get' in that column.

I'm going to show you three ways of accomplishing the translation.

1) Use the built in TextMate case conversion

But that's no fun, and doesn't illustrate the use of filtering through the terminal.  (Again, this example is a bit trivial and it's overkill to use the terminal for this, but I'm still going to illustrate how.  Because I can)

2) Use filter through command with 'tr' command

Select the offending letters (again, all lowercase v's here, but use your imagination), right click on the selection and choose 'filter through command'.

The 'tr' command performs a mapping from one set of characters to another.

echo "cbadefg" | tr "abc" "def"
feddefg

"a" maps to "d", "b" maps to "e", and so on and so forth.  All we need to do is map "abcdefghijklmnopqrstuvwxyz" to "ABCDEFGHIJKLMNOPQRSTUVWXYZ".

Fortunately there is a shortcut for that in tr, since they are common sets of letters: [:lower:] and [:upper:]

echo  "cbadefg" | tr "[:lower:]" "[:upper:]"
CBADEFG

So we can use this command in the dialog box:

Not surprisingly this works.

3) Use 'sed'

Sed stands for 'stream editor', and it is an extremely versatile Unix command line tool.  Let's do a few examples of what's possible with sed before presenting the command to switch the case of all the letters

Perhaps the most common use of sed is to replace one string with another.  The syntax to do that is

's/string1/replacementstring/[g]'

the 'g' argument is optional; if you include it, all instances of string 1 will be replaced per line; else just the first one.

Let's try it out:

echo "Hello, World" | sed  's/Hello/Goodbye/g'
Goodbye, World

There's a lot more to sed; I recommend reading Getting Started with Sed if this piques your interest.  I'll have more blog posts later to illustrate some more, nontrivial uses.

sed can do the same transliteration that the tr command can do, with the syntax 'y/set1/set2/'

The command to use for filtering to convert lowercase to uppercase is then

sed  'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'

Conclusion

The column editing feature of TextMate is fairly unique (I haven't found another text editor that supports it), and it could come in useful any time you need to append a string to the front of a column of text, as could be the case with a set of variables.  For instance, you could prepend 'private final' to set of default access level variables.

I also illustrated the use of 'filter selection through command'; any command you can execute on your terminal is accessible to you here.  The power of Unix is completely at your disposal via this dialog.

Categories: Java, programming, unix Tags: , , , ,

Show only unread messages in Gmail

April 21, 2010 Leave a comment

Gmail is incredibly powerful, but it hides some of the more common features of e-mail under the surface. For instance, you can see at a glance that you have n unread messages, but how to actually see just those messages isn’t immediately obvious.

In the search field, type

in: inbox label: unread

and you will see only the unread messages that are in your inbox. If you want to search in all folders, omit the in: label.

Categories: Uncategorized Tags:

Unix tip #2: explicit for loops, command substitution

April 17, 2010 2 comments

A lot of unix commands are designed to operate on a large number of files at once.  For instance, the move file command, mv, has as its (simplified) arguments

mv file 1 [file 2, ... file n] destination

It's for that reason that you can do something like

mv *.jpg ~/Desktop/Images

and have all the jpegs in the current working directory moved to the Images folder on the Desktop.  So many unix commands are set up that way that you might not need to know how to explicitly iterate (loop).  I was forced to learn this syntax when I had a large number of .tar.gz (roughly equivalent to zip files for those more familiar with Windows land) files to decompress.

The command I usually use to extract the contents of a zipped file is

tar -xzvf /path/to/tar/file

This expects a single file path; doing something like tar -xzvf *.tar.gz will not work.

Nick@Macintosh-2 ~/Desktop/TarExample$ ls
foo.tar.gz  foo2.tar.gz
Nick@Macintosh-2 ~/Desktop/TarExample$ tar -zxvf *.tar.gz
tar: foo2.tar.gz: Not found in archive
tar: Error exit delayed from previous errors

As you can see, this isn't going to work.  Instead we need an explicit loop.  The general syntax is

for i in [iterable]; do [command with variable $i]; done

For instance,

Nick@Macintosh-2 ~/Desktop/TarExample$ for i in 1 2 3 4 5; do echo $i; done
1
2
3
4
5

Recalling our last unix tip, we could replace this with

 Nick@Macintosh-2 ~/Desktop/TarExample$ for i in {1..5}; do echo $i; done
 1
2
3
4
5

The iterable list is whitespace separated.  This is very important for what I'm about to show to you next.

If you're familiar with basic Unix functionality, you know that you list the contents of a directory with the ls command.  Let's do that here.

Nick@Macintosh-2 ~/Desktop/TarExample$ ls foo.tar.gz  foo2.tar.gz
If you'll notice, these are exactly the filenames we need to pass into the tar command.  Let's try with echo first.

for i in ls; do echo $i; done ls
Well, that didn't work.  What's going on?  Turns yout you need to add backticks (the key to the left of the 1 key) around the ls command; otherwise bash treats it as text.

or i in `ls`; do echo $i; done foo.tar.gz foo2.tar.gz
We can go ahead and replace the echo command with our tar command:

 Nick@Macintosh-2 ~/Desktop/TarExample$ ^echo^tar -xzvf

 for i in `ls`; do tar -xzvf $i; done
 a.txt
 b.txt
 a.txt
 b.txt

The stdout here shows the contents that were extracted from the .tar.gz files.

But what is that syntax?

 ^echo^tar -xzvf

?  This is another neat feature of bash; you can repeat the last command, textually substituting the second command for the first.  I could have just as easily hit the up key, moved my cursor, deleted echo, replaced it with tar -xzvf, but this is faster to type for me.

Just for another example,

 echo "Hello"
 Hello
 Nick@Macintosh-2 ~/Desktop/TarExample$ ^Hello^World
 echo "World"
 World

In actuality, I would not use `ls`; what happens if there were things other than .tar.gz files in the directory?  We'd be calling the tar command with the incorrect arguments.  Instead we only want it to affect the files ending in.tar.gz; this is a place where the * wildcard comes in handy.

Nick@Macintosh-2 ~/Desktop/TarExample$ ls
a.txt       b.txt       foo.tar.gz  foo2.tar.gz

 Nick@Macintosh-2 ~/Desktop/TarExample$ ls *.tar.gz
 foo.tar.gz  foo2.tar.gz

So I can use this in my earlier command,

 for i in `ls *.tar.gz`; do tar -xzvf $i; done

Note that you can avoid the use of backticks if you use plain wildcard expansion:

 for i in *.tar.gz; do tar -xzvf $i; done

The reason that this works without the use of backticks is that the ls text is a command that needs to be run by the shell; the * is an expression that is evaluated earlier in the pipeline.  Read more about globbing.

Nested for loops

I haven't had a need to nest for-loops yet, but you can if you wish.

for i in {1,2,3}; do for j in {3,4,5}; do echo $i $j; done; done
1 3
1 4
1 5
2 3
2 4
2 5
3 3
3 4
3 5

Conclusion:

I have shown you how to explicitly iterate over lists in bash, how to use wildcard matching to restrict the set of objects returned by command, and how to replace one piece of the last command with another.  In most cases you will not need to explicitly iterate over lists, due to the way many unix commands are written, but it's a useful skill to have nonetheless.

Categories: programming Tags: ,

Unix tip #1: advanced mkdir and brace expansion fun

April 11, 2010 7 comments

If you don’t know all the ins and outs of the mkdir command, you are probably expending more effort than necessary.  Imagine this fairly common use case:

You are in a folder and want to create one folder which has 3 sub folders.  Let’s call the main folder Programming and its 3 sub folders Java, Python, and Scala.  Visually this looks like

or rendered via tree:

Programming/
|-- Java
|-- Python
`-- Scala

A first pass at accomplishing this would be to create the Programming folder, and then the three individual folders underneath

$ mkdir Programming
$ mkdir Programming/Java
$ mkdir Programming/Python
$ mkdir Programming/Scala

This certainly works, but it takes four commands.

Let's see if we can't do better.  Delete those folders with the command

rm -rf Programming/

This will delete the programming folder and all subfolders underneath it (the r flag is for recursive, the f flag for forcing the removal of nonempty directories)

Like most unix commands, the mkdir command can take multiple arguments, separated by spaces.  So the three separate commands to create Java, Python, and Scala can be put onto one line.

mkdir Programming; mkdir Programming/Java Programming/Python Programming/Scala

Note the ; separator between the two commands.  We need to create the Programming folder before we can create the subfolders.

This is better but still too verbose.  It would be nice to remove the mkdir Programming call; we'd like to be able to create an arbitrarily nested folder and have mkdir create all the parent folders automatically.  Fortunately there is a way to do this: the -p flag of mkdir does exactly this.

 -p      Create intermediate directories as required.  If this option is not specified, the full path prefix of
             each operand must already exist.  On the other hand, with this option specified, no error will be
             reported if a directory given as an operand already exists.  Intermediate directories are created with
             permission bits of rwxrwxrwx (0777) as modified by the current umask, plus write and search permission
             for the owner.

Thus we can change our command to

mkdir -p Programming/Java Programming/Python Programming/Scala

This is better but still not perfect; we're repeating ourselves 3 times with the Programming call.  Enter an absurdly useful Bash shell construct known as brace expansion.

echo {5,6,7}
5 6 7

The arguments within braces are treated as if they were space separated instead.  That wouldn't be terribly useful except that things immediately before the brace are repeated as well

echo hello{5,6,7}
hello5 hello6 hello7

This brace expansion can be used anywhere, since the textual substitution happens before the arguments are passed into other processes.  So, combining this with what we saw earlier, we can put Java, Python and Scala into a list and prepend it with Programming:

 echo Programming/{Java,Python,Scala}
Programming/Java Programming/Python Programming/Scala

That should look very familiar.  Putting it in place of the earlier mkdir command we get the elegant one liner

mkdir -p Programming/{Java,Python,Scala}

Certain versions of bash also support numerical ranges within the brackets:

echo {1..10}
1 2 3 4 5 6 7 8 9 10

Conclusion:

I have shown you how to create all the parent directories using the mkdir command, and introduced you to the brace expansion macro of Bash.  The latter is extremely powerful, and can be used to great effect within scripts.

Note: The arguments within the braces must have NO space between after or before the commas in order for the brace expansion to work.

[572][nicholasdunn: Desktop]$ echo {5, 6, 7}
{5, 6, 7}
[573][nicholasdunn: Desktop]$ echo {5,6,7}
5 6 7
Categories: programming Tags: , ,

ColorBrewer

April 11, 2010 Leave a comment

Just a quick post about a great online tool I was shown (thanks Eric) called Colorbrewer.

There are numerous books and articles online about color palette design, usually from a web-design / aesthetic standpoint.  But there is more to the use of color than mere aesthetics; color can be used as an effective tool in scientific data visualization.  One of the few books on the topic describes its contents as a guide to “how scientists and engineers can use color to help gain insight into their data sets through true color, false color, and pseudocolor imaging.”  While the content of the book is a bit beyond the scope of this post, it’s clear that color gets a lot of use in charts and graphs, and being able to better pick colors is beneficial.
ColorBrewer is designed to help users pick a set of colors that is best used to show data on a map.  Unlike most color scheme choosers where you pick whether you want muted colors, bright colors, pastel colors, etc., ColorBrewer starts by asking whether the data you are visualizing is sequential, diverging, or qualitative.  Sequential and diverging both have to do with quantitative data, e.g. average salaries.  Sequential is the more familiar for data; darker colors usually indicate a higher value on whatever metric is measured.  Diverging, on the other hand, treats the average as a neutral color and then uses colors with sharply contrasting hues for the high and low ends.  Qualitative could also be labeled as ‘categorical’; it means about the same thing.

Among its other features, ColorBrewer can exclude colors that would not come out well when photocopied, as well as those that would be confused by people with color blindness.  It also has mechanisms for exporting the RGB/Hex color codes of the generated color palettes for use in other applications.

Categories: UI Tags: , , ,

Java Swing Drag and Drop Troubleshooting

April 11, 2010 Leave a comment

Dragging domain objects between JTables

Drag and drop Troubleshooting

Drag and drop is an ubiquitous UI metaphor in common desktop/web applications.  I am in the process of finally learning how to accomplish drag and drop in Java through Swing; it hasn’t been an easy process.  I have been keeping track of some of the problems I have run into along the way, and will be updating this post as I find more.  Make sure you read through the whole set of Drag and Drop tutorials before you attempt to implement Drag and Drop; a lot of my mistakes came from jumping the gun and not reading through the whole document.  I will be making a post later with more complete source code illustrating how to drag and drop domain objects between components (the tutorials online usually show text being dragged and dropped rather than class instances).

Problem: When I attempt to drag an item out of the table, nothing happens
Solution:

  • Did you remember to call “component.setDragEnabled(true)” first?
  • Make sure you are not using a DataFlavor constructed with default constructor; if it is the drag action will not occur

Problem: When I complete a drag and drop, I get a class cast exception
Solution: Make sure you have created the DataFlavor correctly; you should define the class of the serialized object within the constructor to the DataFlavor.  E.g. if you are sending an instance of a class named Foo.java, you could create a DataFlavor as follows:

public class Foo implements Transferable, Serializable {

    public static final DataFlavor DATA_FLAVOR = new DataFlavor(Foo.class, "Foo");

    public DataFlavor[] getTransferDataFlavors() {
         return new DataFlavor[]{DATA_FLAVOR};
    }

    public boolean isDataFlavorSupported(DataFlavor flavor) {
        return flavor == FLAVOR;
    }

    public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
        return this;
    }
}

Problem: When I attempt to drop an item onto a table, nothing happens
Solution:
If the table is empty, make sure you called "JTable.setFillsViewportHeight(true)" first?  Explanation:

JTable.setFillsViewportHeight(true)is invoked to set the fillsViewportHeight property. When this property is true the table uses the entire height of the container, even if the table doesn't have enough rows to use the whole vertical space. This makes it easier to use the table as a drag-and-drop target. (http://java.sun.com/docs/books/tutorial/uiswing/components/table.html)

See more info about and drag and drop with respect to empty tables.

Problem: When I move an item from one table to another, the item isn't deleted from the first table
Solution: Make sure you do the modification to the underlying table model in the exportDone method.

For instance:

@Override
public void exportDone(JComponent c, Transferable t, int action) {
    if (action == TransferHandler.MOVE) {
        JTable table = (JTable) c;
        list.remove(table.getSelectedRow());
    }
}
Categories: Java, programming, UI Tags: , , ,

NetBeans Platform Lessons Learned/Gotchas – Part 1

April 1, 2010 3 comments

As I stated in a previous post, NetBeans is my IDE of choice.  I find it extremely powerful and capable; it is the program I spend most of my day working in.  Fortunately the hard work that went into the NetBeans IDE can be leveraged by average users through the use of the NetBeans Platform (NBP for brevity here).  You can create standalone desktop clients using all the same features of the NetBeans editor (syntax highlighting, robust docking framework, property editors, etc.), without having to worry about coding all these complex features from scratch.  With such a powerful and complex API to learn, there are bound to be stumbling blocks.  This is the first in what’s sure to be a series of lessons I’ve learned while working in the NetBeans Platform.

Learning resources

I purchased a book to learn the NetBeans Platform, but I was getting nowhere with it.  Sometimes you need to be handheld through the process of doing something the first few times, and the book just omitted too many steps.  For instance, there are oftentimes you must add dependencies to your project that the book omits.  I highly recommend the NetBeans Platform Learning Trail, particularly the series of tutorials starting with Managing Selection.  There is a concept of a Lookup in the NetBeans Platform which is just a map from Class to the set of instances of that class; it is used extensively in NBP and understanding it is extremely important.  The section in the book did not do it justice; going through the tutorials methodically did the trick.

Lookup Woes

I’m not going to repeat what is said in the tutorial, but I do want to point out one gotcha that had me hung up for awhile.

Rather than keeping track of which windows have focus and reacting to this, you can instead use a Lookup that proxies whatever window has focus.  So if user clicks from editor window to an output window, you can react to this.  Here is the description:

Utilities.actionsGlobalContext() is a Lookup which proxies the Lookup of whichever TopComponent currently has keyboard focus, and fires changes when focus moves to a different component.

The example they give is as follows:

private Lookup.Result result = null;
public void componentOpened() {
    Lookup.Template tpl = new Lookup.Template (APIObject.class);
    result = Utilities.actionsGlobalContext().lookup(tpl);
    result.addLookupListener (this);
}

Why is this useful?  Let's use the Properties window as an example.  When you have the properties window open, it always displays the properties of the currently focused window.


When the editor is focused, details about the source file are provided


When the Files menu is focused, details of the currently selected node are provided

The tutorial does not show how you would listen to the Lookup of just a single topcomponent.  Why would you want to do that?  Say you are writing a custom control which somehow edits aspects of the object(s) returned by the lookup returned by Utilities.actionsGlobalContext().  As soon as you click into your custom component, the focus changes, and the lookup now points to a different object (or none at all), meaning you can't edit the properties you were trying to.  (Somehow the built in properties panel avoid this problem; I don't know what they do).  But regardless, sometimes you would like to listen to just the lookup of a single window.  To do this you might expect something like:

private Lookup.Result result = null;
public void componentOpened() {
    Lookup.Template tpl = new Lookup.Template (APIObject.class);
    // TopComponent implements LookupProvider

    TopComponent componentToTrack = TheTopComponent.getInstance();
    Lookup toTrack = componentToTrack.getLookup();
    result = toTrack.lookup(tpl);
    result.addLookupListener (this);
}

And that would be a good first effort.  Unfortunately, following their pattern doesn't work.  You have to add a call to allItems() or allInstances() before you actually receive Lookup events.  Pretty crazy huh?  The only way I found this out (I don't see it in the Javadocs at all) is through a lot of googling; the page in question is here.  The correct code is thus

private Lookup.Result result = null;
public void componentOpened() {
    Lookup.Template tpl = new Lookup.Template (APIObject.class);
    // TopComponent implements LookupProvider

    TopComponent componentToTrack = TheTopComponent.getInstance();
    Lookup toTrack = componentToTrack.getLookup();
    toTrack.allItems(); // allInstances() seems to work too
    result = toTrack.lookup(tpl);
    result.addLookupListener (this);
}


That issue really stymied me for awhile, so hopefully someone can save some frustration due to this post.  It reminds me of problems I had with Android; the workaround is just as unintuitive.

Wrapping Libraries


Unlike standard Java programs, you cannot just add jars to a libraries folder and expect to be able to use them in a NetBeans Platform project.  Instead, you must create a Module that wraps each jar you want to use.  See the Dev FAQ page for more info.  Fortunately they make it pretty easy to do this; you can just right click the Modules folder, choose Add New Library, then follow the steps in the wizard.

Let's make this concrete; let's say I need to use apache-commons-beanutils in a project.  I download the jar and wrap it.


I now have a module in my project that merely wraps the jar.


I start using the bean classes:

As you can see, it won't compile.  This is because we have not indicated that the API module depends on the commons-beanutils module.


After adding the dependency, everything compiles.

You might expect everything to be fine at this point, but you'd be wrong.  If you ran this example, you would get a ClassPathNotFoundException for some Apache Commons Logging components.  If you had read carefully the dependencies page, you wouldn't be surprised.  But you probably were surprised that you didn't see any warnings of any kind.  The secret is you have to choose "Build" on the wrapped jar file.

If you do, you will see a few warnings like the following:


verify-class-linkage:
Warning: org.apache.commons.beanutils.BeanComparator cannot access org.apache.commons.collections.comparators.ComparableComparator
Warning: org.apache.commons.beanutils.BeanMap cannot access org.apache.commons.collections.Transformer
Warning: org.apache.commons.beanutils.BeanMap cannot access org.apache.commons.collections.set.UnmodifiableSet
Warning: org.apache.commons.beanutils.BeanMap cannot access org.apache.commons.collections.list.UnmodifiableList
Warning: org.apache.commons.beanutils.BeanMap$2 cannot access org.apache.commons.collections.Transformer
Warning: org.apache.commons.beanutils.BeanMap$3 cannot access org.apache.commons.collections.Transformer
Warning: org.apache.commons.beanutils.BeanMap$4 cannot access org.apache.commons.collections.Transformer
Warning: org.apache.commons.beanutils.BeanMap$5 cannot access org.apache.commons.collections.Transformer
Warning: org.apache.commons.beanutils.BeanMap$6 cannot access org.apache.commons.collections.Transformer
Warning: org.apache.commons.beanutils.BeanMap$7 cannot access org.apache.commons.collections.Transformer
(additional warnings not reported)

Those warnings should tell you pretty unequivocally that things are going to go terribly wrong if you attempt to use the jar as it is.  You need to add the dependency to the wrapped library jar, in the same way that you added the dependency to the beanutils wrapper module to the API module.

The reason I went through this example is that nowhere online did I see a real world example like this where wrapped library modules themselves need to have their dependencies resolved; the tutorials always have the ideal world of "A depends on B, so A must declare a dependency on B's wrapper module".

If you've done all this and still have class path not found exceptions, I would advise that you do a full clean build of the project, perhaps replacing the jars with new builds of them as well.  That was the only way I got my dependency problems resolved in one hairy instance.

The moral of the story is ALWAYS attempt to build wrapped module jars.  If you don't, everything will compile fine but you will get nasty runtime exceptions later.  Don't ignore the warnings!

Property Sheets

As mentioned earlier, one of the strengths of the NetBeans platform is that you can use the Swing components that NetBeans have developed in your own project.  One of the most useful one of these is the PropertySheetView.  If you've designed interfaces in the Matisse GUI builder, you're no doubt familiar with this.  See earlier in this post for some screenshots of the PropertySheetView component.  It's fairly simple, merely a two column view of key value pairs.  Properties that cannot be edited are greyed out.  There are mechanisms for creating custom editors (e.g. you can make a color picker pop up when a color is modified, rather than typing in RGB values), and you get a lot of functionality from this component.

In order for the PropertySheetView to display anything, it needs to be associated with a Node.  As the Javadocs say:

This class is a view to use it properly you need to add it into a component which implements ExplorerManager.Provider. Good examples of that can be found in ExplorerUtils. Then just use ExplorerManager.Provider.getExplorerManager() call to get the ExplorerManager and control its state.

It's slightly confusing and complicated, but just follow the examples here and in the previous tutorials.

To definine what shows up when a node is displayed in a PropertySheetVIew, you must override the createSheet method.  The general pattern is as follows:

@Override
protected Sheet createSheet() {

    Sheet sheet = Sheet.createDefault();
    Sheet.Set set = Sheet.createPropertiesSet();
    
    // Replace with whatever object you're wrapping with this node; make sure that your
    // lookup is set correctly
    APIObject obj = getLookup().lookup (APIObject.class);

       // Here is where the hard part is. How do you define these?
    Property[] properties = ...;
    
    set.putProperties(properties);
    sheet.put(set);
    return sheet;
}

Generally, what you want to display in a property sheet view is all the properties of the node, e.g. those variables exposed via getters and/or setters.  I won't rehash how to do this here; the previously mentionedNodes API Tutorial shows how to expose a few properties.

The reason I mention this is because I glanced over part of the source code they provided:

protected Sheet createSheet() {

    Sheet sheet = Sheet.createDefault();
    Sheet.Set set = Sheet.createPropertiesSet();
    APIObject obj = getLookup().lookup(APIObject.class);

    try {

        Property indexProp = new PropertySupport.Reflection(obj, Integer.class, "getIndex", null);
        Property dateProp = new PropertySupport.Reflection(obj, Date.class, "getDate", null);

        indexProp.setName("index");
        dateProp.setName("date");

        set.put(indexProp);
        set.put(dateProp);

    } catch (NoSuchMethodException ex) {
        ErrorManager.getDefault();
    }

    sheet.put(set);
    return sheet;

}

Did you miss it too?

indexProp.setName("index");
dateProp.setName("date");

If you forget the call to setName on a node, your properties will not show up in the property sheet view.  Why is that?  A careful reading of the javadoc for the put methods reveals the answer:

put

public Node.Property<?> put(Node.Property<?> p) Add a property to this set, replacing any old one with the same name.
Parameters:p - the property to add Returns:the property with the same name that was replaced, or null for a fresh insertion

put

public void put(Node.Property<?>[] ar) Add several properties to this set, replacing old ones with the same names.
Parameters:ar - properties to add

My problem was that I was calling setDisplayName on the Property object, without the corresponding setName call.  Thus only the last property I added ended up showing up in the view, because all the Property objects had the same name field (null).  I was led down a false trail when I noticed that all the Property objects had the same hashcode (0).  I reimplemented the hash function to ensure it would be different for all, but the set still only contained one object.  In hindsight, the hashcode of 0 should have tipped me off to a null field rather than assuming that the creators had messed up the hashCode function.

Conclusion

NetBeans Platform is an extremely powerful framework for building Java applications.  The learning curve is very steep, and I hope you can learn from my mistakes.  To recap, the big takeaways were

  • Use the online tutorials rather than a book.  They show each step in detail, instead of glossing over crucial steps
  • You have to add a call to allItems() or allInstances() before you actually receive Lookup events from a LookupListener
  • When dealing with wrapped libraries, make sure you build them to catch any warnings about inaccessible classes
  • When dealing with properties, you must call setName() on them in order to have them show up in a PropertySheetView
    • Read the JavaDocs carefully before you go off and start doing stupid things like reimplementing hash functions.  Chances are, it's not broken, you're just not using it right.  To borrow a phrase, "If you hear hoofbeats, think horses, not zebras"