|
|
|||
Tim Boudreau's BlogCommunity: JavaDesktop ArchivesThe Capability Pattern - Future-Proof Your APIsPosted by timboudreau on August 11, 2008 at 01:00 AM | Permalink | Comments (19)Here is a simple pattern which you can use to make your APIs extensible, even by third parties, without sacrificing your ability to keep backward compatibility. It is very frequent to create a library which has two “sides” — an API side and an SPI side. The API is what applications call to use the library. The SPI (Service Provider Interface) is how functionality — for example, access to different kinds of resources, is provided. One example of this is JavaMail: To read/write email messages, you call JavaMail's API. Under the hood, when you ask for a mail store for, say, an IMAP mail server, the JavaMail library looks up all the providers registered (injected) on the classpath, and tries to find one that supports that protocol. The protocol handler is written to JavaMail's SPI. If it finds one, then you can fetch messages from IMAP servers using it. But your client code only ever calls the JavaMail API - it doesn't need to know anything about the IMAP service provider under the hood.
There is one very big problem with the way this is usually
done: API classes
really ought to be I won't go into great detail about why this is true here (my friend Jarda does in his new book and we discuss it somewhat in our book Rich Client Programming). In abbreviated form, the reasons are:
Exception.getCause() in JDK 1.3).
So adding methods to a public, non-final class in an API is
a backward-incompatible change.
Given those constraints, what happens if you mix API and SPI in the same class (which is what JavaMail and most Java standards do)? Well, you can't add methods compatibly because that could break subclasses. And you can't remove them compatibly, because clients could be calling them. You're stuck. You can't compatibly add or remove anything from the existing classes. As I've written elsewhere, it is the height of insanity that an application server vendor is supposed to implement interfaces and classes that its clients directly call — for exactly this reason. It would be much cleaner, and allow Java APIs to evolve much faster, if API and SPI were completely separated. But part of the appeal to vendors, for better or worse, to implement these specifications, is that they can extend them in custom ways that will tie developers who use those extensions to their particular implementation. This behavior not entirely about being evil and locking people in. There is a genuine case for innovation on top of a standard - that's how standards evolve, and some people will need functionality that the standard doesn't yet support. Enter the capability pattern. The capability pattern is very, very simple. It looks like this:
public <T> getCapability (Class<T> type);
That's it! It's incredibly simple!
It has one caveat: Any call to getCapability() must
be followed by a null-check. But this is much cleaner
than either catching UnsupportedOperationExceptions,
or if (foo.isAbleToDoX()) foo.doX() or
if (foo instanceof DoerOfX) ((DoerOfX) foo).doX().
A null-check is nice and simple and clean by comparison. It's
letting the Java type system work for you instead of
getting into a wrestling match with it.
Now, what can you do with it? Here's an example.
In my previous
blog I introduced an alternative design for how you could
do something like
In light of what we just discussed,
public final class TaskStatus {
private final StatusImpl impl;
TaskStatus (StatusImpl impl) {
this.impl = impl;
}
public void setTitle (String title) {
impl.setTitle (title);
}
public void setProgress (String msg, long progress, long min, long max) {
//We could do argument sanity checks here and make life
//simpler for anyone implementing StatusImpl
impl.setProgress (msg, progress, min, max);
}
public void setProgress (String msg) {
//...you get the idea
//...
}
public abstract class StatusImpl {
public abstract void setTitle (String title);
public abstract void setProgress (String msg, long progress, long min, long max);
public abstract void setProgress (String msg); //indeterminate mode
public abstract void done();
public abstract void failed (Exception e);
}
So we have an API that handles basic status display. But people are going to invent new aspects to status display. We can't save the world and solve everybody's task-status problems before they even think of them - and we shouldn't try. We don't want to set things up so that it's up to us to implement everything the world will ever want. Luckily, it doesn't have to be that way. Since we've designed our API so that it can be compatibly added to, we let the rest of the world come up with things they need for displaying task status, and the ones that a lot of people need can be added to our API in the future. The capability pattern lets us do that. We add two methods to our API and SPI classes:
public abstract class StatusImpl {
//...
public <T> T getCapability (Class<T> type);
}
public final class TaskStatus {
//...
public <T> T getCapability (Class<T> type) {
return impl.getCapability (type);
}
}
Let's put that to practical use. Someone might
want to display how much time remains
before the task is done. Our API doesn't handle that.
Through the capability pattern, we can add that. We
(or anyone implementing
public interface StatusTime {
public void setTimeRemaining (long milliseconds);
}
A task that wants to provide this information to the UI, if the
UI supports it, simply does this:
public T runInBackground (TaskStatus status) {
StatusTime time = status.getCapability (StatusTime.class);
for (...) {
//do some slow work...
if (time != null) {
long remaining = //estimate the time remaining
time.setTimeRemaining (remaining);
}
}
}
Even better, our But we know we need a UI - and we know we are targetting Swing right now. How can we really keep this code completely un-tied from UI code and still have it be useful? The capability pattern comes to our rescue again - very very simply. An actual application using this UI simply fetches the default factory for StatusImpls (you need such a thing if you want to run multiple simultaneous background tasks and show status for each — my next blog will explain how this can be injected just by putting a JAR on the classpath) and does something like:
Component statusUi = theFactory.getCapability (Component.class);
if (statusUi != null) {
statusBar.add (statusUi);
}
(or if we want to allow only one background task at a time,
we can forget the factory and put the Component fetching
code directly in our implementation of StatusImpl).
If you are familiar with NetBeans Lookup API, the capability pattern is really a simplification of that (minus collection-based results and listening for changes).
The point here is that the capability pattern lets you have an
API that is composed completely of nice, future-proofed,
evolvable, It also helps one to avoid trying to “save the world” — by allowing for extensibility, it is possible to create an API that is useful without needing to handle every possible thing anyone might ever want to do in that problem domain. Trying to save the world is what leads to scope-creep and never-finished projects. In this tutorial I discuss the don't try to save the world principle in a practical example. Does the mirror-class design seem a bit masochistic? I think it does point up a weakness in the scoping rules of the Java language. It would definitely be nicer to be able to, on the method level, make some methods visible to some kinds of clients, and other methods visible to other kinds of clients. But regardless of this, it's even more masochistic to end up “painted into a corner,”[1] and unable to fix bugs or add features without potentially breaking somebody's code. That's how you end up with ten-year-old unfixed bugs. [1]painted into a corner &mdash An English idiom meaning to leave yourself with no options — you were painting the floor of a room in a pattern such that you end up standing in an unpainted corner of the room, and you can't leave the corner until the paint dries. Where's the state?Posted by timboudreau on August 07, 2008 at 01:04 PM | Permalink | Comments (14)Where's the state? This is a small but useful question when deciding how a problem domain gets carved up into objects: What things have state? What things have values that can change? When and how can they change? Can the changes be observed? Who needs to observe changes in state? These questions make a good start for figuring out how to carve up a problem domain into objects, if you observe the principle keep all related state in one place. I would go so far as to say that the majority of the appeal of Model-View-Controller (MVC) architecture is that it encourages you to keep state in one place. One big reason why statefulness matters is threading. In practice, it is common to see designs where threading was an afterthought. This is to be expected. Concurrency is a not natural way for human beings to think. So commonly a library is designed with no thought about threading; then a problem shows up which multi-threading can solve. Threading ends up being introduced into a codebase that was never designed for it. Retrofitting a threading model on something designed without one is very painful and sometimes impossible. Some threading models can be simple. For example, any time you are writing a Swing application, and you have a method that can do long running I/O, the first line of that method should be assert !EventQueue.isDispatchThread();under all circumstances. But keeping I/O off the event thread is the trivial case. Managing mutations to a model inside an application is a more complicated, less obvious problem. ![]() Any time you find yourself writing a setter (or more generally, mutator) method, it is worth asking yourself Who does this piece of state really belong to? Am I putting state in the right place? Blindly following the beans pattern (add a getter/setter to whatever type you happen to be editing) can result in state being distributed all over objects in an application. The result will be harder to maintain, and if it has any lifespan, less and less maintainable over time. Like entropy, or the no broken windows theory, the more state is distributed all over the place, the more that will masquerade as design and make it okay for a programmer to further diffuse state throughout objects in the application. Human beings can only hold so many things in their minds at a time. The more state is diffused, the more things someone must pay attention to simultaneously to solve a problem in that code. Another question above was Who needs to observe changes in state? There are some corollaries: Where should those changes be published? and Does the thing observing the change need a reference to the thing that changed? Let's return to the concept of having a model for a minute. A model gets all related state in one place quite well. It does nothing for threading issues — these still have to be handled somehow within the model, or appropriate use of the model in a multi-threaded environment must be documented. There is a thing you can do at this juncture that can make life much easier — and it is all about how the code that uses the model is designed. If you're creating an API, there is probably more to it than just a data model. There is also how the model is accessed. Essentially what you can do is this: If you design the rest of your API so that the only way to get a reference to the model is to be passed one (i.e. “don't call us, we'll call you”), then you know the context (particularly, on what thread, while holding which locks) in which your code is going to be called.
I'll pick a class at random as a case in point:
![]() I mentioned mixing concerns: Avoiding mixing concerns is not just an academic issue of idealized architectural purity. APIs are things human beings use. If you avoid mixing concerns in a public class, you can name things more clearly, and the result will be easier to understand and need less documentation (which most people won't read unless they have to anyway). In a perfect world, a thing representing a task should probably be stateless (subclasses can have state if that makes sense for them - but no setters or getters or mutable state in the interface/superclass). If the code that does the work is passed a reference to a model object it can set task state on, that untangles the task-state concern from it.
It also
removes a bit of psychological weirdness: Someone who is writing a
Detangling the other concern is
as simple as returning a
public interface Task<T> {
public T runInBackground (TaskStatus status);
public void runInForeground (TaskStatus status, T backgroundResult);
}
public interface TaskStatus {
public void setTitle (String title);
public void setProgress (String msg, long progress, long min, long max);
public void setProgress (String msg); //indeterminate mode
public void done();
public void failed (Exception e);
}
and then perhaps you would have a concrete TaskRunner class that runs tasks
public final class TaskRunner {
public <T> java.util.concurrent.Future<T> launch (Task<T> task, TaskStatus statusUI) { ... }
}
or, perhaps preferably,
What's the difference between this and
More importantly, by passing in a
One of our questions above was Does the thing observing the
change need a reference to the thing that changed? In this case,
absolutely not. In fact, to make the You'll notice that we've completely removed use of the listener pattern here. The listener pattern is seriously overrated, but is often used by default because developers have seen it in the Java core libraries — we use what we know. The listener pattern has a number of problems. If you've ever had to debug a Swing application where you have a severe bug that only occurs after you switch Windows from Classic to XP appearance or vice versa, then you know this pain — I know I do. What is happening is:
Especially when you have a situation where it is very
unlikely ever to have
more than one listener, the listener pattern is probably
not a good choice. Listeners monitor changes in state.
It is not good design to assume that multiple things will want
to monitor the status of a
public final class ProxyTaskStatus {
private final TaskStatus[] statii;
ProxyTaskStatus (TaskStatus... statii) {
this.statii = statii;
}
public void setTitle (String title) {
for (TaskStatus status : statii) {
status.setTitle (title);
}
}
//...
}
if that's really a need; or leave that up to someone implementing
What we have, instead of the listener pattern, is a situation where we're passing in the model object (in this case, the thing that holds state about status), as opposed to having the state belong to the task itself and having other code listen for changes in the state. Most likely that model object writes directly to a UI showing task progress. I believe I've read of this pattern being called don't call us, we'll call you somewhere (if anyone can point me to where I ran across that usage, let me know so I can give credit where it's due). To get back to threading for a minute: There are three ways I typically see threading + statefulness dealt with in code:
This last item brings me to my main point here:
The combination of keep all related state in one
place plus don't call us, we'll call you
creates the possibility of encouraging and even
actually enforcing a
threading model over a complex data model,
without
(generally) having to document lots of rules about
threading and pray that people obey them. A weakly enforced
example of this from the JDK is ![]() Lastly, for anybody about to scream that I have misrepresented SwingWorker here (it has lots of complexity about batching up interim results and so forth, and the above is a simplification), I'll mention that
API BlogsPosted by timboudreau on August 05, 2008 at 11:38 AM | Permalink | Comments (13)
Egads! An actual Swing Tree-Table!Posted by timboudreau on June 03, 2008 at 03:36 AM | Permalink | Comments (22)Four years ago, I went on a hunt for best practices for doing tree table components in Swing. We had a tree-table component in NetBeans, whose maintenance was my never-ending nightmare and the biggest source of bugs on my bug list. It had been written, with the best of intentions, based on Scott Violet's Swing Connection article about how to quickly hack up a tree-table component in Swing (Scott's article was also written with the best of intentions, and I have no intention to ding him here - what he wrote does work for simple use-cases - a debugger is not a simple use-case). When I canvassed folks who had done Swing tree-tables on our mailing lists, most of them were based on that article, as ours was. What I heard back varied between groans of pain and mad rabid howls of pain. There are a few things in that original tree table design that just don't work - not reliably, anyway. Sending events to an offscreen component as if it were on-screen and expecting it to behave sanely is just a really bad idea that happens to work if the look and feel is a subclass of BasicLookAndFeel, and other look and feel implementations have been tormented into supporting this abuse by all the evil Tree-Table implementations in the wild. But the bottom line is, a look-and-feel author would have to be slightly insane to code their TreeUI to behave as if it were a live component when it has no parent and obviously is not one. In other words, the fact that the JTree-as-cell-renderer design works at all is just an accident of how BasicLookAndFeel's TreeUI implementation was designed, which other look and feels inherited. Never mind trying to use said JTree as a cell renderer in a table (I once made a 400% performance improvement in our tired, tortured, hacked-up TreeTable just by having it translate the graphics context instead of repositioning - and thus causing a re-layout) is seriously abusing the component. Now try convincing said offscreen JTree that it has keyboard focus in order to get it to paint appropriately in its role as a cell renderer for another component. On all look and feels. On all platforms. Everywhere. You see what I mean. After doing that canvassing back in '04, it was obvious that Swing needed a real tree-table component. So I started to write one (and the layout cache classes JTree uses were very, very helpful - thanks, Scott!). I started on it, got the basics working, and then moved back to the U.S., changed jobs and ended up travelling the world full-time teaching other people to write NetBeans modules - but it didn't leave time to finish up the Tree Table work. Thankfully, my former office-mate, David Strupl, picked up where I left off when he left Sun to work on Nokia's NetBeans RCP app for managing cellular telephone networks. The really, really great news is: This week, Standa Aubrecht - who took over a bunch of the stuff when I left full-time development of NetBeans in '04 and amazed me with how quickly he was able to get going in a complex codebase - committed it into the main line of NetBeans sources yesterday. So anybody who gets a dev build of NetBeans as of today has a perfectly working Swing Tree Table component they can use (the class name is Outline - I borrowed the name from Apple's Cocoa library - it's a little less clunky than "tree table" but gets the point across). The JAR file is org.netbeans.swing.outline.jar. Usage is incredibly easy - you just provide a standard Swing TreeModel of whatever sort you like, and an additional RowModel that can be queried for the other columns contents, editability and so forth. And you never have to worry about cells painted half one color and half another because the tree-cell part got repainted after focus went to a popup menu. It actually works!
The real credit here goes to David and Standa for getting this thing production-worthy - I just was pissed-off enough at having a gargantuan list of unfixable bugs (well, fix it on one platform, break it on another, or leave it unfixed everywhere, or semi-fixed some places - pure evil if you hold the illusion that what we do is computer science) four years ago to get the ball rolling. They're the guys who delivered it.
I'm incredibly happy to see this finally be real and available not just to people writing NetBeans modules, but anybody doing GUI apps in Java. There has been a need for a real, reliable tree table component for Swing programmers for a long, long, long time. All hail David and Standa!
What if we built Java code with...Java?Posted by timboudreau on January 30, 2008 at 01:36 PM | Permalink | Comments (23)My friend Jon had an interesting insight: Both Ant and Maven rely on lots of XML. XML is good for describing data and terrible for describing behavior. A build is mostly behavior. What if, instead of tormenting Ant into iterating on a bunch of subprojects of subprojects, if we just used an actual programming language to write build scripts. Like, oh, say...Java, for instance? So he created the Gosling project. It's pretty embryonic - and I think some of the file and resource classes could be replaced by straight usage of things like javax.tools.FileObject, but it has a nice simplicity. Here's the constructor for Gosling's own build to build itself. It has a similar feel to what Jon did in designing Wicket's APIs:
public GoslingProject() {
final Folder root = new Folder("/Projects/gosling/workspace/gosling");
final Folder source = root.folder("src");
final Folder lib = root.folder("lib");
final Folder target = root.folder("target");
add(new JavaApplicationBuilder() {
@Override
protected Set
Wizard project updatesPosted by timboudreau on September 24, 2006 at 08:33 PM | Permalink | Comments (21)I spent part of the weekend adding some needed features to the Wizard library on java.net. If you need to do wizard-style UIs in Swing, this library makes it pretty easy to do something slick. The Wizard library now supports JLF-spec summary panels - so you can easily display a final page which lists what the wizard has done. I also added background completion support with a progress bar and proper threading handling - so if what the wizard will create is slow, you can show progress while it is going. Something I added some time ago that is fairly useful for speeding up the Wizard creation process is a class called WizardPage - you simply add components to this panel, and set the name of each component; the framework will automatically listen for changes and put whatever the user inputs into the settings map. If you want validation, that is easy to implement as well. There's also a new Quick Start Guide and a WebStart™ demo (BeanNetter)
Sunrise over Denver airport (yes it's a real photo - it was quite a sunrise) A Single-Mouse-Gesture Color Chooser for SwingPosted by timboudreau on June 05, 2006 at 05:56 PM | Permalink | Comments (1)Ever needed a faster, slicker way to let your users select a color in Swing? I just set up a new java.net project, which produces just such a widget. Press the mouse and a palette pops up; drag over the palette and release when the color is right; use combinations of ctrl/alt/shift to switch palettes (palettes are pluggable if you want to write your own).
The widget is the Quick Color Chooser -
It's actually been sitting around in So the code is fairly mature and solid - I just split it out into having a separate UI delegate so it's more Swing-like and the painting behavior is overridable, but it's the same logic as before. Feedback appreciated.
If you want to try it using Matisse in NetBeans, there's a NetBeans module that installs the component in the component palette for immediate drag-and-drop use (created using BeanNetter). The module includes the javadoc.
Got JavaBeans? Here's a way to distribute them...Posted by timboudreau on April 03, 2006 at 11:53 AM | Permalink | Comments (10)BeanNetter - the NetBeans Module GeneratorSo NetBeans has this cool component palette from which you can drag and drop components onto Swing
forms. But where are all the cool components? NetBeans just shows the default JDK Swing components - but there are lots of components out there. Wouldn't it be nicer if you could make them just appear in your IDE? And there are sites such as nbextras.org with NetBeans plug-ins, and there is an update facility built into NetBeans - so why shouldn't you be able to download JavaBeans straight into the IDE from them? Well, first, it needs to be easy to create a NetBeans module that embeds JavaBeans and puts them on the Component Palette. So I wrote a small tool that generates a NetBeans plugin. It's a wizard, and you point it at a JAR file with some Swing components in it. It finds all the declared JavaBeans that are there, and lets you choose to add or remove other classes. Then it asks for some info like the name of the library - this will be your Beans' category on the Component Palette.
When you complete it, it generates a complete, redistributable NetBeans Module (
What to do with the resultsNow you've got a module, but the point is to get that module to other people. How to do that? Well, first, if the components are open source, I bet the folks at nbextras.org would happily host them, and that site's been getting a lot of attention lately. If they're commercial, there is the Third Party update center that every release copy of NetBeans checks for plug-ins, and that could be a good place - the partner page would be a good place to start.
Sources and Screen Shots
Sources are in
BeanNetter - the NetBeans Module Generator
Choosing a License - Extra points if you can identify the text above | |||
|
|