Tuesday, December 29, 2009

Default right-click in all text components of an application

First of all, Merry Christmas and Happy New Year everybody!

Many people are still surprised not to see a default right-click popup in all text components of a Java application. One way to do it, is to push a new EventQueue to the default one. One concern could be applets in general (unsigned applets, global EventQueue).
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new PopupEventQueue());
Below is the code for the event queue.

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.EventQueue;

import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;

import javax.swing.AbstractAction;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import javax.swing.text.JTextComponent;

public class PopupEventQueue extends EventQueue {

private final JPopupMenu popup = new JPopupMenu();
private final TextAction[] popupActions = new TextAction[4];

public PopupEventQueue() {
popupActions[0] = new TextAction("Cut") {
private static final long serialVersionUID = -3844049016540352208L;

public void actionPerformed(ActionEvent ae) {
textComponent.cut();
}

@Override
protected void postTextComponentInitialize() {
setEnabled(textComponent.isEditable() && isTextSelected());
}
};
popupActions[1] = new TextAction("Copy") {
private static final long serialVersionUID = -3844049016540352208L;

public void actionPerformed(ActionEvent ae) {
textComponent.copy();
}

@Override
protected void postTextComponentInitialize() {
setEnabled(isTextSelected());
}
};
popupActions[2] = new TextAction("Paste") {
private static final long serialVersionUID = -3844049016540352208L;

public void actionPerformed(ActionEvent ae) {
textComponent.paste();
}

@Override
protected void postTextComponentInitialize() {
setEnabled(textComponent.isEditable());
}
};
popupActions[3] = new TextAction("Select all") {
private static final long serialVersionUID = -3844049016540352208L;

public void actionPerformed(ActionEvent ae) {
textComponent.selectAll();
}

@Override
protected void postTextComponentInitialize() {
setEnabled(!textComponent.getText().trim().equals(""));
}
};

for (TextAction action : popupActions) {
popup.add(action);
}
}

@Override
protected void dispatchEvent(AWTEvent event) {
if (event.getID() == MouseEvent.MOUSE_RELEASED) {
MouseEvent e = (MouseEvent) event;

Component c = getSource(e);

if (c instanceof JTextComponent) {
if (SwingUtilities.isRightMouseButton(e)) {
final JTextComponent txtComp = (JTextComponent) c;
for (TextAction action : popupActions) {
action.setTextComponent(txtComp);
}
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
}
super.dispatchEvent(event);
}

private Component getSource(MouseEvent e) {
return SwingUtilities.getDeepestComponentAt(
e.getComponent(),
e.getX(),
e.getY());
}

private static abstract class TextAction extends AbstractAction {

private static final long serialVersionUID = -7708937505251885197L;
protected JTextComponent textComponent;

public TextAction(String name) {
super(name);
}

public void setTextComponent(JTextComponent textComponent) {
this.textComponent = textComponent;
postTextComponentInitialize();
}

protected boolean isTextSelected() {
return (textComponent.getSelectionStart() != textComponent.getSelectionEnd());
}

protected abstract void postTextComponentInitialize();
}
}

Monday, August 24, 2009

The making of an OSGI based IRC Bot

I've released the source code of JerkBot, an IRC bot based on Jerklib and OSGI. JerkBot source code is a multi-module maven project. It's not some OSGI/Java blueprints as I'm no OSGI expert, plus JerkBot is basically a 24 hours effort without bug fixes.

The library itself is distributed under BSD license, but the bot provides plugins such as SVN for example using SVNKit , which is subject to other licensing terms.

The bot uses Declarative Services for OSGI and Java technologies such as :

  • Apache Lucene for Javadoc Search
  • Quartz for job scheduling(session tracking, pending registrations, etc.)
  • Javamail to send emails for user registration
  • EclipseLink for persistence
  • A subset of JAAS for security
  • JMX for administrative commands (accessible through JConsole or through the bot jmx command)
  • The usual Jakarta libraries and couple of other libraries

I didn't provide scripting languages to the bot for security reasons, there's only JMX. I would prefer to offer scripting languages in a secure way with a custom SecurityManager to prevent drama from happening :-).
Let's say scripting is enabled, and someone accidently tries one or all the following instructions in a scripting language.

  • File("/somepath").delete()
  • System.exit(0)
  • Download("http://website/hugefile.iso").saveToDisk();

JerkBot was roughly a one day effort with 4 rewrites(1 full day each), and of course bug fixes time to time:
  • The first version was using traditional OSGI, well not so traditional :-), with BundleActivators service trackers and listeners, etc.
  • The second rewrite used Declarative Services with manually written XML descriptors
  • The third rewrite was based on Felix IPOJO. I would have preferred to use IPOJO, but found some annoyances(abstract based classes, JMX flexibility, etc.).
  • The last rewrite is using Felix SCR but with annotations to generate XML descriptors for components. Simplify code, remove unnecessary abstractions, consistent logic, etc.

I'll be providing the binary distribution soon. The binary distribution contains everything necessary to run the bot : OSGI configuration files, Bot configuration, jars, a user/developer guide, etc.

What the bot doesn't provide is a logging mechanism, for IRC channel logs. To do it right, I think it would be better to create a new project. In my opinion, when a bot logs channel it should have, if possible, the following features:

  • Configurable tasks to schedule flexible timed delivery of existing logs(local filesystem, ftp, samba share, ssh, http put, etc.)
  • Configurable log format(HTML, CSV, TXT) with optional generation of html logs or text logs.
  • Database storage or any other persistence mechanism(Apache Lucene Index vs flat text files, database logs, etc.)
  • Ability to stop/start logging for every channel
  • Optional Web front-end to publish logs(Could be a static HTML pages with Javascript search, JSF, Wicket, GWT, Rest interface + Apache Lucene or a DB for search).
Providing a quick and dirty plugin for channel logs would be trivial but not flexible :-). I started implementing it, but I decided to stop there.

The first draft of the bot manual can be found in the svn repository. Please bear with me for grammar and spelling mistakes, it was a written very quickly at early AM :-)

In JerkBot plugins are provided by OSGI bundles. I learned a lot from my previous experience with JPF when writing XPontus.

For now the bot is sitting on irc.freenode.net in the ##swing channel, running on an old laptop(FreeBSD-CURRENT).


Wednesday, July 22, 2009

Which one is the best?

You've probably heard it many times, in various circumstances. What was your answer?

That trivial question may(or not) have been subject to a long answer with hopefully credible reasons. "The problem is ... Many tools provide XXX ... This tool is the best, in this case, as ...".
But you're the expert! The reasons motivating your choices should be obvious to anybody else without having a long discussion!

There is no best, there are needs and there are constraints to reach particular goals(short, medium or long term). All those variables usually fits in to a vision.

If there were a best, anyone who could afford it, would have it.

No, no why would I want to use crap seriously?? So many tools already suck and people keep providing more crap. Maybe I should suggest that they stop already, as there are many similar great tools out there.

A typical conversation about choosing a Linux distribution
Q: "What's the best Linux distribution? Ubuntu?"
A: "Wut??? Hell no, it's Debian and all the rest is crap including the derivatives."
Q: "Why?"
A: "Because Ubuntu doesn't ... and because I say so :-)"
Q: "But Ubuntu is easy and Debian is not user friendly!"
A: "Really? Not really .... Ah, I guess I just like things when they're complicated, must be the geek feeling."

A tool can meet needs but not all the constraints and vice-versa and what you'll probably be looking for is a balance.

  • Memory usage vs tons of features
  • Usability vs complexity/too much flexibility
  • Easily understood vs require 5 books + certification + hiring a consultant
  • Commercial support vs community support
  • Proven stability and acceptance vs the unknown
  • etc.

There are simple ways to decide :

  • You have a problem to address within constraints(time, budget, etc.)
  • You try looking for tools which are particularly good at solving your specific problem and that integrate perfectly in your custom infrastructure. However, no such tools seem to exist or there's that little thing that you dislike.
  • You then look for compromises and ways to solve the issues that won't get magically fixed by the tools.
  • You don't have time to look at all the existing tools and evaluate them. You'll be selecting few tools and trying them out. Hopefully software vendors will cover the tiniest details which are relevant to your business needs, in their documentation.
  • You decide and you live with it, maybe reevaluate your decision and revise your goals, but you move forward unless you really believe that you're wrong.

It's not easy to decide in the IT world. You might get it right or wrong but you may have the power to correct your mistakes. Whatever the choice, the rational move is trying to select wisely, going forward and take responsibility.

Tuesday, July 14, 2009

Playing with OSGI and JPA

I've been writing an IRC bot for fun, but it's far from being done. My goal is to experiment with JPA in an OSGI environment.

At work, I am using Hibernate, XDoclet to generate the XML and JPA isn't coming soon :-). My last JPA application was a pastebin application, with Wicket, hibernate search, Lucene, etc.

I'm using a friend's library Jerklib with Dynamic JPA. I'm still having some minor issues when deploying but I'll probably find a solution soon.

About the application
Environment
I have a multi-project with Maven and I'm using the maven bundle plugin and I'm developing in Eclipse 3.5 on Debian testing.
I'm using openjpa , dynamic jpa and couple of other dependencies

Design overview
a) Commands implemented as plugins : The bot has a set of factoids(learn, forget, etc...). Each command gets created using a factory.

// message listener //String operation = getOperation();
CommandFactory factory = ServiceFromOSGI.getCommandFactory(operation);

// if the factory is not null, redundancy for the operation parameter
// as a factory can have multiple commands
Command command = factory.createCommand(operation);
ircChannel.say(command.render(ircMessageContext));

b) The command service listens for removal or installation of commands and updates itself.

After writing couple of "users' commands", I would need to implement some administration commands(load/unload plugins, irc specific tasks, etc.).

Problems
The dynamic discovery is failing for now, the persistence provider class is not resolved, it might just be a bundling problem for openjpa. I wrapped it myself.

Conclusion
It's strange that many open source projects still don't provide an OSGI manifest. The maven-bundle plugin is very trivial to use for maven enabled project and there's still bnd.
While OSGI is an interesting technology, I personally don't know anybody using it in the enterprise unless they are an Eclipse shop. I think that it's mostly due to
  • the lack of "OSGI enabled jars"
  • the fear that OSGI might introduce unnecessary complexity
  • the lack of step by step complete examples(if possible with screencasts)

There's plenty of documentation about OSGI and lots of successful applications(Web, Desktop) using OSGI. Hopefully my bot will be one those applications :-)

Saturday, March 21, 2009

Thoughts about JavaFX

JavaFX has the potential to become something interesting. While there are many articles written about JavaFX, I have yet to see a non trivial JavaFX application. When browsing Dzone articles, it almost looks like JavaFX is popular, while it's not.


There's no amazing UI control and I am not sure that I could code an entire JavaFX application without writing few java classes. I am not fond of applets and I haven't written any for years. JavaFX doesn't solve the "applet problem".


I don't know about any cellular phone which is officially supporting JavaFX. I am also not aware of any software vendor distributing desktop applications written with that technology.


In my opinion, JavaFX is not ready for production use. What motivated the release of JavaFX? Maybe they've been advertising it for too long and they had to release something. I'll give JavaFX probably one more year before attempting to use it.



Sunday, January 04, 2009

serialVersionUID in Netbeans

Most of the time, I use Netbeans when I have the choice. What I don't like about Eclipse and is getting me worried time to time is when the IDE freezes for a long time when you're not really doing anything.

Last week, I needed to build a simple Java project (Maven based build), about 50 000 lines of code(from sloccount). The project contains one core project and few sub projects. Eclipse took about 30 minutes to import the project and set up the classpath. That performance was achieved under a Quad Core, 2 GB of RAM, which is amazing. I had only Eclipse, Firefox and a terminal opened. I tried with both q4e and m2eclipse plugins, same results, I could hear my CPU making lots of noise. I had time to start cooking, boil water for coffee and do some other things, before the IDE was ready to use.

One of many missing features in Netbeans is the ability to generate the serial version ID for a serializable class. With Eclipse, you get the warning all the time, and you can choose between:
  • ignoring it
  • adding the annotation @SuppressWarning("serial")
  • generating the serial version id.

Available plugins for Netbeans
There are two plugins available for Netbeans, that I am aware of : UUIDGenerator and serialVersionUID generator. I only have success with UUIDGenerator (most of the time, I am running the latest development build under Linux and Windows and lately Mac OS Leopard).

Enabling Serialization warnings
Under Tools->Options->Editor->Hints->Standard Javac warnings, select Serialization. That way, you'll see a marker notifying you that you're missing the declaration of a serialVersionUID field.




Generate the serial version ID
You can generate the serialVersionUID using the shortcut Control-ALT-Z. You can copy the generated contents to the clipboard and paste it inside your class.