Wednesday, August 5, 2009

Custom JTable Cell Renderer (Part 2)

While overriding getTableCellRendererComponent() in DefaultTableCellRenderer allows you to render any arbitrary JComponent in a cell, it is unfortunately all it does. If getTableCellRendererComponent() returns a JCheckBox, then JTable will render it in the appropriate cell including its check state. But the rendered checkbox will not be responsive to any mouse click applied, which of course defeats the purpose of displaying a checkbox inside a cell in the first place.

It is relatively easy to make a cell interactive. First, register a MouseListener on the JTable. When a mouseClicked(MouseEvent evt) is called, you can determine the cell picked using:

int row = table.rowAtPoint(evt.getPoint());
int col = table.columnAtPoint(evt.getPoint());

If we determine that the cell at this row and column can respond to a selection, then we need a way to keep track of the state of that cell. For example, a cell rendering a checkbox needs to keep track of its check state. The JCheckBox returned by getTableCellRendererComponent() cannot be used for this purpose because there is only one and is used as a rendering template. Here is where an arbitrary data object comes in handy. For example, if the cell is a checkbox, then data object for that cell can be a Boolean object. Then you can call the JTable's model's setValueAt(row, col) to store the boolean value of the cell clicked, making it true if it were false and vice versa.

This data object will be passed as the argument to getTableCellRenderer()'s value object parameter. Using the checkbox example above, this will be a Boolean object and depending on whether the value is true or false, set the selection state of the JCheckBox template before returning it. The checked state will be used to render the affected cell accordingly.

Tuesday, August 4, 2009

Custom JTable Cell Renderer (Part 1)

If the data is not a supported type, or if not all the cells in a single column is of the same type, then you will need to write a custom renderer for your JTable.

JTable asks the renderer's getTableCellRendererComponent() what kind of display component each cell should look like in the course of painting the table. Note that the JTable does not actually place a JComponent in each cell. Instead, each cell simply visually mimics the JComponent returned by getTableCellRendererComponent() by painting it in the cell.

For example, if getTableCellRendererComponent() returns a JLabel, then the attributes of that JLabel is used to paint the cell so that the cell looks like a JLabel (but is not really one). In other words, the JLabel is simply used like a data structure to pass information. For this reason, it is important that getTableCellRendererComponent() should not create a new component with each call. For example, the default JTable renderer, DefaultTableCellRenderer (an extension of JLabel), always returns itself when its getTableCellRendererComponent() is called.

In order to display a different "component" in each cell, the simplest method is to extend the DefaultTableCellRenderer. Instantiate in advance (say, in the constructor) all the different types of JComponent you will need (only one of each type is needed). Then when getTableCellRendererComponent() is called, determine which JComponent is to be returned, adjusting their attributes if necessary.

public class MyTableCellRenderer extends DefaultTableCellRenderer
{
private JCheckBox checkbox;
private JButton button;

public MyTableCellRenderer()
{
// Create one checkbox and one button. We will always return the same ones.
checkbox = new JCheckBox("Check Box");
button = new JButton("Button");
}

public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
// Render row 0 column 0 as a JCheckBox. Return the pre-created
// JCheckBox after setting the "selected" attribute appropriately
// based on its value in the JTable model.
if (row == 0 && column == 0)
{
checkbox.setSelected(table.getValue(row, column));
return checkbox;
}

// Render row 0 column 2 as a JButton.
if (row == 1 && column == 2)
return button;

// Everywhere else, return the usual DefaultTableCellRenderer.
return this;
}
}

Monday, August 3, 2009

Using Arbitrary Objects as JTable Data

While we normally supply Strings, JTable can actually accept any arbitrary objects as data. To display the data, its toString() method is called for a string that the JTable can display.

If the data is not of the supported type, then its toString() method must be implemented to return something for JTable to display intelligibly. For example, given a class called ArbitraryObject as follows:

public class ArbitraryObject
{
private String name;

public ArbitraryObject(String name)
{
this.name = name;
}

public String toString()
{
return "The number is " + name; // prepend "The number is" to name
}
}
Then you can create a JTable initialized with instances of ArbitraryObject as data:

private ArbitraryObject[][] data =
{ {new ArbitraryObject("1"), new ArbitraryObject("1"), new ArbitraryObject("1")},
{new ArbitraryObject("2"), new ArbitraryObject("2"), new ArbitraryObject("2")},
{new ArbitraryObject("3"), new ArbitraryObject("3"), new ArbitraryObject("3")},
{new ArbitraryObject("4"), new ArbitraryObject("4"), new ArbitraryObject("4")},
{new ArbitraryObject("5"), new ArbitraryObject("5"), new ArbitraryObject("5")},
{new ArbitraryObject("6"), new ArbitraryObject("6"), new ArbitraryObject("6")} };
private String[] headerLabels = { "Column One", "Column Two", "Column Three" }

:
JTable table = new JTable(data, headerLabels);
add(table, BorderLayout.CENTER);
:
Here's the screenshot of this JTable:


The utility of this is that you can easily associate each cell in the JTable with an object it represents. JTable "displays" the object with the value returned by the object's toString(). For example, if you select a cell based on what's displayed in it, a listener registered for the JTable can easily retrieve its associated object using getValueAt(row, col) without going through convolutions to look it up. Think of it as a link from the table back to the data it represents:

table.getSelectionModel().addListSelectionListener(new ListSelectionListener()
{
ublic void valueChanged(ListSelectionEvent event)
{
int row = table.getSelectedRow();
int col = table.getSelectedColumn();
ArbitraryObject o = table.getValueAt(row, col);
}
);

Sunday, August 2, 2009

JTable Cell Display Based on Data Type

JTable is capable of doing some special rendering based on the data type, such as JCheckBox for boolean data. The supported data type are listed in Sun's Tutorial on JTable. The only restriction is that each column has to be uniformly the same type. To enable this, the getColumnClass() of the JTable's model has to return the type of the data to be displayed:
   DefaultTableModel model = new DefaultTableModel()
{
/**
* Override to return the data class.
*/
public Class getColumnClass(int c)
{
return getValueAt(0, c).getClass();
}
};

table.setModel(model);

If getColumnClass() is not overridden, then the returned class is Object. In this case, JTable invokes the toString() method of the Object and displayed it as a JLabel.

Tuesday, July 21, 2009

Showing JTable Header Without Using JScrollPane

Most tutorials and examples about JTable put it within a JScrollPane. If you do not place the JTable inside a JScrollPane, the header is not automatically shown.

However, JTable does create it. To show it, simply call JTable.getTableHeader() and add it to the Container. Just as importantly, you can continue to control the columns (such as changing column width and switching columns) from the header.

For example, you can easily put the header NORTH of a BorderLayout:
setLayout(new BorderLayout());
JTable table = new JTable(data, headerLabels);
add(table.getTableHeader(), BorderLayout.NORTH);
add(table, BorderLayout.CENTER);
Note that you could conceivably put the header in the SOUTH position. However, you can only have one header showing at a time. If you add it in both the NORTH and then the SOUTH location, it will only show up in the SOUTH location.

Friday, July 17, 2009

Writing Custom Java Layout Managers

Why Write Custom Layout Managers?
A Swing application depends on layout managers to intelligently position a collection of GUI components in a window. Swing provides a number of general purpose layout managers for this purpose.
But sometimes it is hard to shoehorn a general purpose layout manager for a specific purpose and the result is often less than satisfactory. Third-party layout managers are available that try to address some of the perceived shortcomings of Swing's own offerings. In addition, GUI layout editors are available that visually assist inprogramming a GUI layout.
Nonetheless, it is often more efficient and more effective to write a custom layout manager designed for a specific layout requirement rather than struggle with the standard layout managers. And it's easier than one may imagine.
LayoutManager and LayoutManager2 API
Java's LayoutManager interface declares the five methods that have to be implemented in a valid layout manager:
  • addLayoutComponent, specifying name
  • removeLayoutComponent
  • layoutContainer
  • minimumLayoutSize
  • preferredLayoutSize
AddLayoutComponent and removeLayoutComponent are called to inform the LayoutManager about Components added to a Container using it. LayoutContainer implements the layout strategy, changing the x and y pixel position and the dimension of the Components as necessary. MinimumLayoutSize and preferredLayoutSize let the Container find out the minimum required and preferred layout size given the Components to be laid out in it.
LayoutManager2 extends LayoutManager with five more methods:
  • addLayoutComponent, specifying constraints object
  • getLayoutAlignmentX
  • getLayoutAlignmentY
  • invalidateLayout
  • maximumLayoutSize
The new addLayoutComponent allows you to pass an object specifying properties to constrain the Component in the layout. GetLayoutAlignmentX and getLayoutAlignmentY specifies the alignment of the Component within the Container. InvalidateLayout tells the LayoutManager to discard cached information about the layout and recalculate. MaximumLayoutSize specifies maximum dimension of the Container.

Example: Grid Layout with Positionable Components
Let's say we need to draw components on a grid, for example, but need to specify the positions of the components arbitrarily at any time. On the first take we'd probably choose Java's GridLayout as the layout manager - that is, until we discover that it will only position components in sequence. Afterwards, the programmer has no control over their positions. The alternative would be to use GridBagLayout, but that's way too complicated and difficult to control for such a simple task. The solution is to write our own LayoutManager.

We call our grid layout with positionable Components the PositionableGridLayout class. The minimumLayoutSize for this case should be the extent of the layout embodying the outermost component. That would be our preferredLayoutSize as well. In other words, minimumLayoutSize is the x grid position of the easternmost Component times the width of each grid and the y grid position of the southernmost Component times the height of each grid. LayoutContainer calculates the pixel location of each Component given its grid position, and relocates it with a call to the Component's setBounds method if necessary. Note that we did not implement addLayoutComponent and removeLayoutComponent because nothing special needs to be done when a Component is added to or removed from the Container.

An automatic LayoutManager - that is, one that would not allow the programmer to control the location and size of each Component - would normally be able to work alone. For a LayoutManager that allows the programmer to individually fix the location and size of the Components, however, an assisting class is required. Such is the case with Java's GridBagLayout, which requires GridBagConstraints to work. In our example we need to be able to position any Component at an arbitrary location at any time. Following the example of GridBagLayout, we implement an assisting class, the PositionableGridConstraints, which allows us to specify the grid position of an added component. The PositionableGridConstraints class is fairly simple to implement. It mainly stores away the grid position of a Component.

/**
* Constructs a PositionableGridConstraints.
*/
public PositionableGridConstraints( int gridx, int gridy, ... )
{

this.gridx = gridx;
this.gridy = gridy;
:
}

We need to assign the grid constraints to the Component, of course. Again, following the example set by Java's GridBagLayout, we implement a setConstraints method in PositionableGridLayout whose purpose is to associate the grid constraints to a Component in a hashtable using the Component as the key.

Example: Row Layout with Proportionally Sized Components
RowLayout lets the programmer specify the space a Component is allowed to occupy horizontally relative to the width of the entire Container. But if the component has a preferred size, its aspect ratio is preserved. RowLayout implements LayoutManager2 so that we can specify the proportion as a constraint.
Again, minimumLayoutSize and also maximumLayoutSize calls preferredLayoutSize, but the calculation of preferred size is slightly more involved. Its width is the width of the Container. Its height is the height of the tallest Component.
AddLayoutComponent and removeLayoutComponent now has a function. They are used to add and remove the proportionality constraints to a component.
Download
Source code for PositionableGridLayout, PositionableGridConstraints and RowLayout.
References
  1. Daniel Dee, Implementing a Grid Layout Manager With Positionable Components, Java Developer's Journal, 1997.
  2. Using Layout Managers, Java Tutorials, Sun.
  3. Patrick Niemeyer and Jonathan Knudsen, Learning Java, 3rd ed., O'Reilly (2005), Chapter 19.


Wednesday, July 8, 2009

JavaScript and Applet Communication

Sometimes it's necessary to make an applet talk to JavaScript in the html page that contains it and vice versa. LiveConnect is the technology that makes this possible. And the best part is that you don't even have to download anything, because the component that enables JavaScript to talk to applet is supported by Firefox, Internet Explorer and Safari, and the component that enables an applet to talk to JavaScript is plugin.jar, which comes with the JRE.

JavaScript to Java Applet

For JavaScript to call methods in a Java applet, the applet must be named in the applet tag and the mayscript attribute set to true. For example, if I have an applet called JSApplet, then the applet tag may look like this:
<applet code="com.avacoda.swing.JSApplet"
mayscript="true" name="jsApplet" width="200" height="100">
If JSApplet has a method called setMessage(), then the JavaScript can access this method like so:
jsApplet.setMessage("Hello");

Java Applet to JavaScript

To perform the converse operation, the Java applet has to import the JSObject class. The JSObject class is a wrapper around JavaScript objects.

For example, the following code gets the JavaScript window object in the page that the applet referred by this resides in. Then, it gets the document object of the window and finally the form object in the document.
JSObject window = JSObject.getWindow(this);
JSObject document = (JSObject) window.getMember("document");
JSObject form = (JSObject) document.getMember("form");

Download
Source Code

Run JSApplet
This sample code contains a JSApplet that, when initialized, calls the JavaScript setMessage() method, which in turn calls back to the JSApplet's setMessage() method. The JSApplet's setMessage() method repaints the screen with the message that is passed from itself to JavaScript and back to itself again.

Note: This sample code works on Firefox and Internet Explorer, but this "closed-loop" program appears to be incompatible with Safari, though it does not appear to fail. Nonetheless, an applet can still communicate with JavaScript and vice versa in Safari.

References
  1. LiveConnect Overview, Mozilla Developer Center.
  2. Talk to JavaScript with Java, NetSpade Web Developer Heaven, 2005.

Thursday, July 2, 2009

Automatically Size to Fit Image in a JLabel

Images inside a Java Swing component do not automatically resize when it's larger than the component it resides in, resulting in a clipped image.

Oftentimes, it is convenient to have an image automatically resize to fit inside a component while preserving the aspect ratio. Thumbnail display is one that comes to mind.

It is actually fairly easy to implement this capability by extending JLabel and overriding the paintComponent() method:

protected void paintComponent(Graphics g)
{
ImageIcon icon = (ImageIcon) getIcon();
int iconWidth = icon.getIconWidth();
int iconHeight = icon.getIconHeight();
double iconAspect = (double) iconHeight / iconWidth;

int w = getWidth();
int h = getHeight();
double canvasAspect = (double) h / w;

int x = 0, y = 0;

// Maintain aspect ratio.
if(iconAspect < canvasAspect)
{
// Drawing space is taller than image.
y = h;
h = (int) (w * iconAspect);
y = (y - h) / 2; // center it along vertical
}
else
{
// Drawing space is wider than image.
x = w;
w = (int) (h / iconAspect);
x = (x - w) / 2; // center it along horizontal
}

Image img = icon.getImage();
g.drawImage(img, x, y, w + x, h + y, 0, 0, iconWidth, iconHeight, null);
}


Download Source Code

ThumbnailLabel.java

Tuesday, June 30, 2009

Moving Offscreen App Back to Primary Workspace

Note: This trick applies to Windows OS only.

Most people using a notebook PC with two monitors will often move some applications off to the external monitor for various reasons. And just as often, when they detach their notebooks, they will forget to move the applications back to the primary monitor as I do.

If not written smartly, those applications will continue to reside in the now illusory monitor when the notebook is re-awaken without the external monitor attached. Rebooting does not always help, thus making those applications inaccessible for use. (Smart applications will detect that the previous location on screen is untenable and will pop back into the main monitor.)

To bring an errant application back to the primary monitor, following these steps:

  1. Alt-tab to the errant application.
  2. Alt-space to bring up the errant application's Windows menu and select Move.
  3. Use left or right cursor as appropriate repeatedly to move the application back to where you can see it.

Monday, June 29, 2009

Remote Debugging with JPDA

For developing Java applications, JPDA (Java Platform Debugger Architecture) is an important toolkit for debugging applications that is failing in a deployment environment. This is particularly useful in situations where the deployment environment does not have a development environment and can only be debugged remotely.
To enable remote debugging, the Java application must be compiled with debugging enabled (-g) and must not be obfuscated or optimized. When launching the Java application, include the following argument:
-agentlib:jdwp=transport=dt_socket,server=y,address=8777
This says that the JVM should listen on the socket transport. Another possibility is to use shared memory as transport (dt_shmem). By default, JVM suspends before the main class loads unless otherwise indicated (suspend=n). In this example, the JVM listens on the specified port (8777) for a debugger to connect before resuming execution. To make the JVM initiate the connection, specify server=n.

Install4j

Make a duplicate of your application launcher (Launcher). Double-click on the duplicate launcher to modify it. Select Java Invocation to configure it. In the VM Parameters text field, add the JPDA arguments show above.
Make a duplicate of your media file (Media) and include the debuggable launcher.
Run the installer. When the debuggable application launch, it will wait for the debugger to connect. If you launch the debuggable application from the command line, you will see a message indicating that it's waiting on the socket transport at port 8777.

Tomcat

Tomcat startup script (startup.sh or startup.bat) has JPDA built in. All you need to do is specify "jpda" when starting Tomcat. By default, it waits on the socket port 8000 until a debugger connects.

WebLogic

In the start WebLogic script, look for JAVA_ARGS and append the JPDA argument shown above. WebLogic will wait for a debugger to connect before proceeding.

Debugging from Eclipse

On the computer where your source code resides and where Eclipse is installed, create a Debugging Configuration. Select the Connection Type and provide the host address and port (e.g., Standard (Socket Attach), localhost and 8777). Click [Debug] to start debugging. The application being debugged will resume. Set a breakpoint somewhere in your source code and watch the remote application stops at your breakpoint.
Other debuggers can be set up similarly.

Reference

  1. Peter V. Mikhalenko, Debug Your Java Code with Ease Using JPDA, TechRepublic, 11/30/2006.
  2. Java Platform Debugger Architecture, Sun.

Sunday, June 28, 2009

Clustering J2EE Web Applications

Clustering refers to the grouping of two or machines (hardware) that externally presents itself as a single unit in order to achieve performance (scalability) and reliability (high availability) goals. For web applications, clustering refers to the grouping of two or more application servers or its components (software), whether running on a single machine or on multiple machines. Clustering is important in a RMI-based architecture to ensure that the failure of one component will not bring down the entire web application.

In designing a cluster, avoid or at least identify single points of failure. A single point of failure has an impact on reliability, which clustering is supposed to achieve. It also translates into varying levels of undesirable end-user experience. An example of a common single point of failure is the application's database. That is because many web applications may have a distributed application tier, but shares a single database.

There are many ways to cluster application servers. The following are some common strategies. Note that a distributed database or SAN (Storage Area Networking) storage can be used on all topologies for better availability.

Saturday, June 27, 2009

Callback vs Listener

The Callback pattern is variation of the Command pattern [Gamma], where the Receiver itself is a concrete expression of the Command (Callback) class and is registered with the Subject. When an event of interest occurred, the Subject "calls back" the Receiver via the registered concrete Callback subclass.

The Listener implements the Observer pattern [Gamma], where the Listener is the Observer and is also registered with the Subject.

A Subject may have multiple Listeners, while it can only have one Callback Receiver. However, multiple Listeners may be implemented as a "callback list".

Java implements Listeners as a callback list. It implements a "push" model of the Observer pattern where additional information is supplied as an Event argument tailored to the Listener.

References


Friday, June 26, 2009

Signing Java Applet - Allowing Applet Full Access to the Local System

There are two ways to grant an applet full access to the local system:
  1. On the receiving side, grant access to the incoming applet by modifying Java's security policy.
  2. On the sending side, have the applet seek access permission from the receiver via signed certificates.
Granting Applet Access by Modifying Java Security Policy

Method 1 requires modifying the java.policy file in jre/lib/security by adding the following lines:
grant codeBase "http://your.url.here" {
permission java.security.AllPermission;
}

As a word of caution, dropping the "codeBase" qualifier grants all applets all permission and is not advisable.

Seeking Applet Access Via Signed Certificate

Method 2 requires creating a trusted certificate and signing the applet.
  1. Write, compile and jar your applet as you normally does.
  2. Use keytool to generate private/public key pairs. This also creates a self-signed certificate.
keytool -genkey -alias alias -keystore keystore -keypass keypass -dname cn=xxxx -storepass storepass
This generates a private/public key pair stored in the keystore protected by storepass. Use the alias and the keypass to access the private key of this generated pair.
  1. This step is optional if you are signing your applet with a self-signed certificate. If you are publishing your applet to the Internet, generate a certificate request (CSR), submit it to a certificate authority (CA) and get a CA-signed trusted certificate back. Replace the self-signed certificate with this trusted certificate.
keytool -certreq -alias alias -keystore keystore -keypass keypass -storepass storepass

keytool -import -alias
alias -file trustedCert.cer -keystore keystore -storepass storepass
  1. Sign your applet: jarsigner
jarsigner -keystore keystore -storepass storepass -keypass keypass -signedjar YourSignedApplet.jar
Reference
  1. keytool - Key and Certificate Management Tool, Sun.
  2. Larry Siden, Signed Applet Tutorial.
  3. Chapter 10: Signed Applets, SDN tutorials, 1994-2009.
  4. How to Create a Self-signed SSL Certificate.
  5. Thawte Code Signing Certificates Enrollment Page.
  6. Verisign Certificate Center Purchase Page.
  7. Java SE Security, Sun.
  8. Lesson: API and Tools Use for Secure Code and File Exchanges, The Java Tutorials, Sun.
  9. Certificate, Java Glossary.
  10. Chris W. Johnson, Java Certificate Parsing, 5/18/2004.
  11. EJBCA User Guide.
  12. CertificateFactory, Java 6 Javadoc, Sun.

Thursday, June 25, 2009

Associations in UML

In UML, an association represents a relationship between classes. The representation varies depending on the specifics.

Association
Represents a simple relationship between classes.

Representation: Solid line (bi-direcitonal); Solid line with arrow (unidirectional).
Implementation: Via member variables.

Aggregation
Also known as weak aggregation. Represents a whole-part relationship.

Representation: Solid line with open diamond (bi-directional); Solid line with open diamond on one end and arrow on the other (unidirectional). Open diamond's side is the whole.
Implementation: Via member variables.

Composition
Also known as strong aggregation. Represents a whole-part relationship where the part's existence is dependent on the whole.

Representation: Solid line with solid diamond (bi-directional); Solid line with solid diamond and arrow (unidirectional). Solid diamond's side is the whole.
Implementation: Via member variable.

Weak Association
Representation: Dash line (bi-directional); Dash line with arrow (unidirectional).
Implementation: Via method arguments.

Wednesday, June 24, 2009

UUID

First and foremost, they have to be 128 bit long.

There are apparently 5 versions. By versions, they mean algorithms with variants.

Version 1 uses a combination of monotonic time, a random number and nodeID, which is either the IP or the MAC address. This guarantees that the UUID is unique across time (from 1582 till around 3400AD) and space. And in case of unforseen reason, it generated the same time and have the same nodeID, the random number decreases the possibility of collision further. The main complain against this is that you can trace the source based on the nodeID.

Version 2 is the OSF Desktop Computing Environment Security version with embedded POSIX UID. Not sure exactly what this means, but apparently not implemented by Apache.

Version 3/5 uses the URL and either MD5 or SHA1 hashing for spatial but not temporal uniqueness.

Version 4 is the same as version 1 but with the nodeID computed using a cryptographically strong random number generator such as Java's SecureRandom and a hashed name (such as that of Version 3/5). This also guarantees spatial and temporal uniqueness. A cryptographically strong random number must produce a non-determinstic output. Apache implements some variation of this. And Sun uses the Leach-Salz variation.

References

  1. P. Leach, M. Nealling, R. Salz, A UUID URN Namespace, Internet Engineering Task Force, 12/2004.
  2. Universal Unique Identifier, The Open Group, 1997.
  3. Java 5 UUID Class Javadoc, Sun Microsystems, Inc., 2004.
  4. Universally Unique Identifier, Wikipedia, 2005.
  5. Commons: Id, The Jakarta Project, Apache Software Foundation, 4/2/2005.

About Computing Notes

I intend this blog to be an emulation of the old-school lab notebooks. Each note contains concise, practical information on computing subjects of varying interests to myself and hopefully to other computing hobbyists and professionals.