Leaving Sun is possibly the most difficult decision that a Sun employee may ever make. Sun is not just a great company, but "The Great Company".
Sun has changed the world. A few years ago the data centers at many customers were a nightmare to maintain. It's Sun technology and innovation that has changed that. Java has made things easier. So has N1. So has Solaris. So has dtrace. So have all the different technologies and standards Sun has created during all these years. And, wait, there's more to come. Don't ever doubt it. Now, possibly now more than ever, Sun is changing the world.
And I have been lucky enough to be able to see that change. To actively participate in that change. To help Sun customers build systems that remain years after release, and that are flexible enough to accept new technologies and standards.
And during this travel I have been lucky enough to enjoy working with Great People. People that changes the world with their daily work.
It has been my pleasure to work with you all, guys. Thanks all for making Sun the greatest place to work at (and the toughest place to leave).
It's time for me now to start new personal and professional projects. The best of it is that I may be collaborating with you all, so I'll still be able to work with the best professionals in the world.
I don't mean you have to wrap your car around a tree like this. I'm talking of JTrees and Drag and Drop support.
Inspired by the Swing Hack # 27 (drag and drop in JTrees), I've built a tiny library that automagically provides drag and drop support for those JTrees built using a DefaultTreeModel. As a plus this wrapper eases popup menu handling, performs autoscrolling, automagically expands nodes, does not require the JTree to be extended, cooks the breakfast for you in the mornings and, well, has many other interesting features you may find useful.
viernes febrero 24, 2006 | Java Swing | Permalink
|
I must admit I like JDBM for desktop applications. It looks extremely strong. And it is very compact. It's runtime weights only 85Kb so it looks perfect for Java Web Start downloads. Since JDBM is based on a B-Tree, it allows only for one key for queries, but this is probably good enough for me. The fact is that JDBM allows for different B-Trees in the same database. It also allows for other indexing techniques, such as hashing, so you can use a JDBM database as a huge hashtable for storing stuff.
In this entry I explore the basics of using JDBM, so that I can reference them in further entries. (In the future I'll aggregate all JDBM blog entries into my Links Room). read more
Insistence on desktop persistence
jueves febrero 16, 2006 | Java Swing | Permalink
|
I'm afraid I'll insist in lightweight desktop persistence without RDBMS in this entry (and maybe in a few others). I've found some nice B-Tree based storage mechanisms, that seem to be widely used out there. They're being used in NetBeans, blojsom and OpenJMS, for instance. read more
Will you bundle a full RDMBS with your GUI applications? How are you persisting the model in your desktop
applications? What are the trends in this area? Well. If you build a Swing application that needs to persist your model then you don't
probably want your users to download and install MySQL first. Right?
This is the problem I'm facing with the RSS feed reader I'm buildling. I want to store all the RSS feeds
somewhere and be able to search them. Stuff there should be indexed. That easy. Easy? Or not?
miércoles febrero 15, 2006 | Personal | Permalink
|
I'm moving !!. I don't own five computers as Jonathan does, but I'm a traveller. So it's difficult (and heavy) to carry all my stuff around the country countries. Keeping in synch my office computer, my laptop and any other computer I use is too much a hassle.
So that's one of the reasons why I've been a little bit quiet lately. Another one is that I've been doing some research (more in this later) and, well, of course, overloaded with work. I hope you understand (and forgive me for not posting).
I'm still furnishing this virtual home (you know: I hate moving ;-)), so bear with me meanwhile.
I'll try to post here too, but I've a blog at home (quite cute, a PHP one!). And keeping two blogs in sync is too much overhead. So if you're interested in participating in my new blog please update your bookmarks.
And if you have any suggestions on new rooms for antonio's home, then please just let me know.
So continuing my last post I decided to build an easy-to-use SwingWorkerManager to
monitor how my SwingWorkers run in the wild.
I've built a SwingWorkerManager.getInstance() singleton to which I "submit( SwingWorker )"
for execution. The SwingWorkerManager has a little ListModel that keeps track of
the last executed SwingWorkers (by adding PropertyChangeListeners to them) and monitors their
activity.
Apart of this ListModel the SwingWorkerManager can create also a ListCellRenderer to better
visualize SwingWorker progress.
So as I said before this SwingWorkerManager uses an internal thread pool to
execute SwingWorkers. As Jeffrey wisely pointed out in his comment, the size of the
pool should depend on the number of available processors NCPU in the environment (that is,
it should be a linear function of NCPU=Runtime.getRuntime().availableProcessors()). So,
continuing our previous discussion:
M = F * NCPU < N
Where M is the number of threads in the pool, F is a constant, NCPU is
the number of CPUs in the system and N is the number of scheduled tasks.
Since usually many threads are just waiting for I/O it would be a waste of time to set
F=1 (since then many CPUs would be just hanging around waiting for I/O). So I think
a good F value could be around 3. That way we'll kick those lazy CPUs. You know, CPU speeds
are very high nowadays, and CPU cycles are probably cheaper than any other kind of resource.
So let's assume F=3 is a good bet. Are we missing something? Well, er.. what about
those slow ones?
Come on, you lazy one, hurry up, get out of my way...
Assume you're downloading a 10 Gb file from somewhere. You, of course, want to use a SwingWorker
for that. But that's gonna take quite some time. And we're using a fixed thread pool, right?
So that task is going to reduce the size of our fixed thread pool (and, thus, reduce
the responsiveness of our GUI).
How could we handle this? Well, two solutions come to mind...
a) Increase M slightly to make room for these slow ones.
b) Use another fixed thread pool to schedule these very long-running, very time-consuming
slow processes.
c) Use one of the above and provide a timeout setting for scheduling tasks.
That way those tasks that have not finished before the given timeout value would be automatically interrupted.
The two first ones are not difficult to implement...
Solution a) would require this value for M:
M = F * NCPU + SLOW < N
Where SLOW is a fixed value that approximates the number of simultaneous slow
processes you think may be running in your application.
And solution b) would require adding a new fixed thread pool (of size, say, SLOW) and a new
method (say "submitSlowTask( SwingWorker )") that schedules things into this new
fixed thread pool.
The third solution won't be too difficult to implement, either (by slightly increasing M to allocate
timeout watcher SwingWorkers).
What do you think? Which one do you like best? Come on, give me a hand here! ;-)
The wonderfully complex world of task scheduling
Many Task Scheduling algorithms are NP hard problems.
The SwingWorkerManager presented here implements a simple FIFO (First In-First Out)
solution to scheduling SwingWorkers in a set of threads.
SwingWorkerManager may be a good way to experiment different task scheduling algorithms (say, in a
Computer Science classroom), but I think a FIFO is good enough for me. And, of course, I can watch my SwingWorkers
running. See ma? I hope it's good for you too (and if not, then just complain here! ;-)).
I have a lot of RSS feeds to read. And I want to read them in my Swing
application without blocking the event dispatch thread.
So, of course, I want to use SwingWorkers to
fetch and parse all RSS feeds.
My first approach would be to create a SwingWorker for each of the RSS feed URLS.
The SwingWorker would then download the RSS feed from the given URL (using
a java.net.HttpURLConnection, for instance) and then parse it.
So I instantiate 200 SwingWorkers, each one holding a different URL, and
"execute()" them. Cool.
But... wait a moment. 200 SwingWorkers? That's 200 threads, right?
Well, yes. That's 200 threads. And that's a problem too!
So, to summarize:
If you have a big number of tasks to execute asynchronously don't
use a thread for each one.
Most operating systems won't complain directly if you create a big number
of threads, but probably the system will be slow. There will be a lot
of context switching between threads. And synchronization between them
(if any) may be a problem.
Throttling
So in order to keep resource-consumption under control we would probably
want to introduce some throttling. This is, we want to define a number
M of simultaneous threads to execute those N tasks.
And, of course, having M < N.
A pool of M threads seems a good idea to me. Building a pool of
threads using Java 5 is a piece of cake:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
...
int M = 3;
ExecutorService threadPool = Executors.newFixedThreadPool( M );
And, well, executing SwingWorkers using that thread pool is also a
piece of cake: we just need to invoke the "submit()" method on our
Executor. Like this:
Note that the SwingWorker can be cancelled as usual, this is,
the SwingWorker semantics are not lost if you use your
preferred ExecutorService. What I mean is that in order
to cancel a SwingWorker you still can use the "cancel()" command
as usual (and it's not necessary to handle the threadPool in
any way). Like this:
mySwingWorker.cancel();
Having an ExecutorService is handy if you have a lot of things
to do: you submit them all and that's all. The FixedThreadPool
places all the pending tasks in an unbound queue. And then starts
executing them in order. When one task finishes the thread is returned
to the pool. If there are any pending tasks to be executed then
the recently released thread starts executing one of those.
So, for instance, if we have N SwingWorkers to be executed stored
in an ArrayList we can submit them all for execution with the following
code:
ArrayList<SwingWorker> mySwingWorkers = ...
// This loops over all N workers to execute...
for( SwingWorker worker : mySwingWorkers )
threadPool.submit( worker );
The Singleton Pattern
It may be interesting to have a reference to that ExecutorService
handy in our application. We can achieve this by using the
Singleton pattern. Something like this:
import ...;
public final class SwingWorkerExecutor
{
/** Number of threads in the pool. */
private static final int M = 3;
/** The ExecutorService. */
private static ExecutorService threadPool
= Executors.newFixedThreadPool(M);
/**
* Schedules a SwingWorker for execution.
* @param aWorker a SwingWorker to execute.
*/
public static <T,V> void execute( SwingWorker<T,V> aWorker )
{
threadPool.submit( aWorker );
}
}
So we can say something like:
SwingWorkerExecutor.submit( mySwingWorker );
What else? Monitoring?
We can also take advantage of this SingletonPattern in some other
interesting ways. Monitoring, for instance. This is what I'm
thinking of currently:
Make the SwingWorkerExecutor keep a ListModel with the
list of the currently running SwingWorkers.
Or, even better, make the SwingWorkerExecutor keep a
TableModel with the list of the currently running SwingWorkers,
and their current progress.
Keep statistics inside the SwingWorkerExecutor about
the average wait time (in the unbounded queue) and
the average run time. This may be interesting to fine-tune
an appropriate value for M (the number of threads)
for different scenarios.
Build a mechanism for allowing time-out on execution
of SwingWorkers
So I was wondering what you think. Do you see any other uses
for such an hypothetical "SwingWorkerExecutor"? Any ideas
or suggestions?
Cheers,
Antonio
UPDATE:
As Vaidya points out the SwingWorker implementation in JDK 6 has
a pool of 10 threads, so it won't ever fire 200 threads.
I wish you all a Happy New Year 2006. I'll be unplugged for some days (Xmas break :-)), but couldn't resist wishing you a Happy New Year!!!
I would also like to thank all people that have contributed comments. It's these people that are making this an interesting place. Thanks everybody!!
As a new year resolution, I'll try to make this blog a little more active. By the way, would you like to see something in particular addressed here, then please just let me know.
I've seen at JavaHispano that somebody has grouped a total of 2927 JNLP applications in a single page for you to run. Check it yourself. (lots of games, too). Impressive!!!
As you probably know I've been exploring Bloglines services to easily build just another RSS reader. The fact is that I have found no services to handle channels. This is, you cannot programmatically add/remove/update channels. Too bad. :-(
So, unless I'm completely wrong, we'll have to parse RSS ourselves.
First approach: Rome
The very first approach is, of course, Rome, Sun's open source project for RSS parsing.
But, to be honest, Rome is too big for my liking, too powerful for my modest needs. It depends on JDOM (which, luckily, seems to depend on nothing else). Rome is very good to parse in detail all sort of RSS flavors. All I want it to have a least common denominator of different RSS flavors. RSS 0.91, RSS 0.92, RSS 1.0, RSS 2.0 and Atom 1.0 would be good enough, I think.
Furthermore, I'd like to do it myself so as to exercise Java XML APIs. After all I need to keep up with those things, it's some sort of hobby of mine ;-).
SAX Parsing: the cost of speed
So my very first approach was to go for speed, using SAX parsers. I've built a SAX handler that is chained with other different SAX
handlers for every different flavor of RSS.
And, to be honest, the thing works quite fast. SAX parsers consume little memory and run really fast.
But after all the experiment those SAX handlers looked to me quite similar to AWK scripts. This is: they're difficult to maintain. I don't think I'll be able to modify those RSS handlers myself within, say, one month from now.
XSL to the rescue?
So I thought, why not use an XSLT stylesheet to extract information from those different RSS flavors (RSS 0.91, 0.92, 1.0, 2.0, Atom 1.0) and transform those different flavors in a least common XML file? Then with a single SAX parser I'd be able to parse all sort of RSS flavor.
And, since all transformation is handled in a XML file (the XSLT stylesheet) it should be easier to maintain. Of course there's a cost for this ease of mainteinance: we're loosing speed.
I'm sort of tired now (it's difficult to write coherently, sorry by that), but I think a small diagram could explain things better. There we are:
I've been doing some tests and, well, there's some lack of speed. But I think it's worth the effort. Simpler, smaller, easier to maintain, no dependencies... I like it.
What do you think? Any suggestions? Any way to improve the XSLT stylesheet? (By the way, the XSLT stylesheet can be found here).
Cheers,
Antonio
Mozilla, Paulo Coelho and customer bases
viernes diciembre 16, 2005 | General | Permalink
|
Mozilla
It seems Mozilla and Firefox are the most used browsers hitting the place. This is
a graph of the last 100 browsers used to see this blog:
That's a total of 39+12+9+1+1 mozilla (or mozilla firefox) browsers hitting the place. A total of 62% of browsers. Wow.
Paulo Coelho
It happened by accident. While at the bookstore I happened to meet a portuguese
version of Paulo Coelho's "O Diário de um Mago" ("Diary of a Wizard"). I think
the english translation is entitled as "The Pilgrimage: A Contemporary Quest
for Ancient Wisdom" although I'm not sure. (It talks about a pilgrimage to Santiago
de Compostela, the city were I was born).
It's a great book. After that I've met "O Alquimista" and "Brida". All three in
portuguese. Nice read indeed. I highly recommend them. These Paulo's books are easy
to read (at least in portuguese ;-)) and they talk about the really important
things in life.
So what does mozilla have to do with Paulo Coelho?
Well, nothing at all, of course. The fact is that I'd like to learn
some portuguese (a very difficult language, from my point of view) and
I was told about this
virtual school of portuguese. The fact is that the site does not
work with Mozilla nor firefox (the browsers I own).
That is, put simply, just stupid. Making a web site that accepts only Internet Explorer
and Microsoft users is not a good idea. If my site statistics are right you'll probably
loose 64% of your potential readers. So, by making things Internet Explorer specific,
you're loosing 64% of your potential clients.
And, well, loosing 64% of your potential clients in your very first page in your
web site is just stupid, isn't it?
But, wait, there's even more. You can't visit "Santiago's Way" official
site either!
Xacobeo (which means "from Jacob" in english, you know, Santiago means
"Saint Jacob", actually).
Who selects who?
And this is more food for thought. Trying to select your customer base by rejecting
users that don't use your tools is not a good idea. Because it may become against
you. After all, who selects who? Who rejects who? Is it web sites selecting and rejecting
readers just for the browsers they use, or is it the other way round? The
answer is obvious to me: I reject sites not accepting firefox. Full stop.
So, since I cannot learn portuguese using Escola Virtual
maybe I can learn it anywhere else. Any ideas, anyone?
Thanks!
Antonio
Update: Escola Virtual is working now in Mozilla right now. Damn it! I've already written this blog entry!