Adding a MouseListener to every row in a JTable

Here’s an code sample:

Main.java:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
 
public class Main extends JFrame {
   public Main() {
      super("TableModel Demonstration");
 
      // create our own custom TableModel
      WineTableModel wineModel = new WineTableModel();
      final JTable table = new JTable(wineModel);
 
      // add rows to our TableModel, each row is represented as a Wine object
      wineModel.addWine(new Wine("Chateau Meyney, St. Estephe", "1994", 18.75f, true));
      wineModel.addWine(new Wine("Chateau Montrose, St. Estephe", "1975", 54.25f, true));
      wineModel.addWine(new Wine("Chateau Gloria, St. Julien", "1993", 22.99f, false));
      wineModel.addWine(new Wine("Chateau Beychevelle, St. Julien", "1970", 61.63f, false));
      wineModel.addWine(new Wine("Chateau La Tour de Mons, Margeaux", "1975", 57.03f, true));
      wineModel.addWine(new Wine("Chateau Brane-Cantenac, Margeaux", "1978", 49.92f, false));
 
      // create the scroll pane and add the table to it. 
      JScrollPane scrollPane = new JScrollPane(table);
 
      // add the scroll pane to this window.
      getContentPane().add(scrollPane, BorderLayout.CENTER);
 
      table.addMouseListener(new MouseAdapter() {
         public void mouseReleased(MouseEvent me) {
            int row = table.rowAtPoint(me.getPoint());
            System.out.println("You clicked at row " + row);
         }
      });
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
   }
 
   public static void main(String[] args) {
      Main main = new Main();
      main.pack();
      main.setVisible(true);
   }
}
 
// a simple object that holds data about a particular wine
class Wine {
   private String  name;
   private String  vintage;
   private float   price;
   private boolean inStock;
 
   public Wine(String name, String vintage, float price, boolean inStock) {
      this.name = name;
      this.vintage = vintage;
      this.price = price;
      this.inStock = inStock;
   }
 
   public String getName()     { return name; }
   public String getVintage()  { return vintage; }
   public float  getPrice()    { return price; } 
   public boolean getInStock() { return inStock; }
 
   public String toString() { 
      return "[" + name + ", " + vintage + ", " + price + ", " + inStock + "]"; }
}
 
class WineTableModel extends AbstractTableModel {
   // holds the strings to be displayed in the column headers of our table
   final String[] columnNames = {"Name", "Vintage", "Price", "In stock?"};
 
   // holds the data types for all our columns
   final Class[] columnClasses = {String.class, String.class, Float.class, Boolean.class};
 
   // holds our data
   final Vector data = new Vector();
  
   // adds a row
   public void addWine(Wine w) {
      data.addElement(w);
      fireTableRowsInserted(data.size()-1, data.size()-1);
   }
 
   public int getColumnCount() {
      return columnNames.length;
   }
         
   public int getRowCount() {
      return data.size();
   }
 
   public String getColumnName(int col) {
      return columnNames[col];
   }
 
   public Class getColumnClass(int c) {
      return columnClasses1;
   }
 
   public Object getValueAt(int row, int col) {
      Wine wine = (Wine) data.elementAt(row);
      if (col == 0)      return wine.getName();
      else if (col == 1) return wine.getVintage();
      else if (col == 2) return new Float(wine.getPrice());
      else if (col == 3) return new Boolean(wine.getInStock());
      else return null;
   }
 
   public boolean isCellEditable(int row, int col) {
      return false;
   }
}

Determining when a page in a JEditorPane has finished loading

Add a PropertyChangeListener and listen for the property page.

   htmlPane.addPropertyChangeListener(new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
         if (!evt.getPropertyName().equals("page")) return;
         System.out.println("Page loaded!");
      }
   });

Main.java:

import javax.swing.text.html.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.net.*;
import java.awt.*;
import java.io.*;
 
public class Main extends JFrame
{
   // need to be final to allow the inner class to access it!
   final JTextField urlTextField = new JTextField();
   final JEditorPane htmlPane = new JEditorPane();
   JButton urlButton = new JButton("Go!");
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
 
   public Main() { 
      htmlPane.setEditable(false);
      urlTextField.setText("http://www.yahoo.com");
  
      urlButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            loadPage(urlTextField.getText());
         }
      });
 
      htmlPane.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent evt) {
            if (!evt.getPropertyName().equals("page")) return;
            System.out.println("Page loaded!");
         }
      });
 
      htmlPane.addHyperlinkListener(new HyperlinkListener() {
         public void hyperlinkUpdate (HyperlinkEvent event) {
            if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
               urlTextField.setText(event.getURL().toString());

               if (event instanceof HTMLFrameHyperlinkEvent) {
                  HTMLDocument doc = (HTMLDocument) htmlPane.getDocument();
                  doc.processHTMLFrameHyperlinkEvent ((HTMLFrameHyperlinkEvent) event);
               }
               else {
                  loadPage(urlTextField.getText());
               }
            }
         }
      });
 
      getContentPane().setLayout(new BorderLayout());
      JPanel topPanel = new JPanel(new BorderLayout());
      topPanel.add(BorderLayout.CENTER, urlTextField);
      topPanel.add(BorderLayout.EAST, urlButton);
 
      getContentPane().add(BorderLayout.NORTH, topPanel);
      getContentPane().add(BorderLayout.CENTER, new JScrollPane(htmlPane));
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
 
      setSize(400, 400);
   }
 
   public void loadPage(String url) {
      try {
         htmlPane.setPage(new URL(urlTextField.getText()));
      }
      catch(Exception e) {
         System.out.println(e);
      }
   }
}

Dynamically change the Look and Feel of a Swing application

Invoke UIManager.setLookAndFeel and provide it with the new Look and Feel class. Force components to reflect this new look by calling SwingUtilities.updateComponentTreeUI. All components in the tree of which you specify the parent component will be asked to use the new Look And Feel. Also do a call to frame.pack to ensure the window to be sized to fit the preferred size and layouts of its subcomponents. Here’s an example:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main implements ActionListener
{ 
   JFrame frame;
   
   public Main() {
      frame = new JFrame("Table one row selection demonstration"); 
      frame.addWindowListener( new WindowAdapter() { 
         public void windowClosing(WindowEvent e) { 
            System.exit(0); 
         } 
      }); 
      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("Look and Feel");
      JMenuItem menuItem1 = new JMenuItem("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
      JMenuItem menuItem2 = new JMenuItem("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
      JMenuItem menuItem3 = new JMenuItem("javax.swing.plaf.metal.MetalLookAndFeel");
      menu.add(menuItem1);
      menu.add(menuItem2);
      menu.add(menuItem3);
      menuItem1.addActionListener(this);
      menuItem2.addActionListener(this);
      menuItem3.addActionListener(this);
      menuBar.add(menu);
      frame.setJMenuBar(menuBar);
 
      JTable table = new JTable(35, 3); 
  
      table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
 
      frame.getContentPane().add(new JScrollPane(table)); 
 
      frame.pack(); 
      frame.show(); 
   } 
 
   public void actionPerformed(ActionEvent ae) {
      try {
         UIManager.setLookAndFeel(ae.getActionCommand());
         SwingUtilities.updateComponentTreeUI(frame);
         frame.pack();
      }
      catch(Exception e) {
         System.out.println(e);
      }
   }
 
   public static void main(String[] args) {
      Main main = new Main();
   }
}

Getting the attributes of an XML Node

Use a NamedNodeMap. The following example shows you how to print out all elements for the tag customer.

customer.xml (!!remove the space between ? and xml):

<? xml version="1.0" encoding="UTF-8"?>
<customers>
   <customer id="C12345" type="prio1">
      <name>Joris Van den Bogaert</name>
      <address>
         <addressline>Handelskaai 3</addressline>
         <zip>1000</zip>
         <location>Brussels</location>
         <country>BELGIUM</country>
      </address>
   </customer>
</customers>

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customer.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("customer");
         Node node = nodeList.item(0);
  
         NamedNodeMap attributes = node.getAttributes();
         for (int i=0; i<attributes.getLength(); i++) {
            Node attribute = attributes.item(i);
            System.out.println(attribute.getNodeName() + " = " + attribute.getNodeValue());
         }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

outputs:

id = C12345
type = prio1

To get a specific attribute, you can use the method getNamedItem.

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customer.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("customer");
         Node node = nodeList.item(0);
  
         NamedNodeMap attributes = node.getAttributes();
 
         Node custId = attributes.getNamedItem("id");
         Node custType = attributes.getNamedItem("type");
         System.out.println("id   = " + custId.getNodeValue());
         System.out.println("type = " + custType.getNodeValue());
         }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Get the IP address of the client connecting to a Servlet

Call the method getRemoteAddr on the HttpServletRequest instance.

MainServlet.java:

import javax.servlet.http.*;
import javax.servlet.*;
 
import java.io.*;
 
public class MainServlet extends HttpServlet
{
   public void doGet (HttpServletRequest request,
                      HttpServletResponse response)
      throws ServletException, IOException
   {
      String ip = request.getRemoteAddr();
      
      response.setContentType("text/html");
      PrintWriter out = response.getWriter();
 
      out.println("<html><body>");
      out.println(ip);
      out.println("</body></html>");
      out.close();
   }
}

Saving binary data (eg. images) in a database table

As an example, I created the following table:

mysql> create table images (imageid int(10) not null auto_increment, 
name varchar(30), data blob, length int(6), primary key(imageid));
Query OK, 0 rows affected (0.12 sec)
 
mysql> desc images;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| imageid | int(10)     |      | PRI | NULL    | auto_increment |
| name    | varchar(30) | YES  |     | NULL    |                |
| length  | int(6)      | YES  |     | NULL    |                |
| data    | blob        | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+

Main.java:

import java.util.*;
import java.text.*;
import java.sql.*;
import java.io.*;  
 
public class Main {
   public static void main(String []args) throws Exception {
      try {
         Class.forName("org.gjt.mm.mysql.Driver").newInstance();
         Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.1/esus", 
                                                       "joris",
                                                       "mypass");
 
         File[] files = new File(".").listFiles(new FilenameFilter() {
            public boolean accept(File dir, String name) {
               if (name.endsWith(".gif")) {
                  return true;
               }
               return false;
            }
         });
 
         for (int i=0; i<files.length; i++) {
            FileInputStream fis=new FileInputStream(files[i]);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte buf[]=new byte[1024];
            int length=-1;
            while((length=fis.read(buf))!=-1) {
               baos.write(buf,0,length);
            }
 
            PreparedStatement insertStmt = conn.prepareStatement(
                                          "INSERT INTO images (name, length, data) " +
                                          "VALUES (?, ?, ?)");
            insertStmt.setString(1, files[i].getName());
            insertStmt.setInt(2, (int) files[i].length());
            insertStmt.setBytes(3, baos.toByteArray());
            insertStmt.execute();
 
            fis.close();
            baos.close();
        }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Getting a list of environment variables

You can’t anymore. There used to be a method called getenv(String) in java.lang.System but it’s been deprecated since
1.1.8. The only thing you can do now is to use the -D properties flag on the command line when you start your program.

java -Dproperty=value myapp.class

Where property is the name of the property and value is the value you want to as sign it.

You can then retrieve the value of the property using:

getProperty("property");

If you still want to allow the user to set environment variables you can always use them as the value for the property in the startup batch file or shell script like this:

Windows:

   SET ENVVVAR=value
   java -Dproperty=%ENV_VAR% myapp.class

Unix:

   ENV_VAR=value
   export ENV_VAR
   java -Dproperty=$ENV_VAR myapp.class

Performance gain of using NIO channels as opposed to regular streams for doing file I/O

To test things out, I wrote a couple small Java programs to copy a file:

CopyFile1.java: uses the old approach using BufferedInput/BufferedOutputStreams with the default buffer size of 2048 bytes
CopyFile2.java: uses the NIO libraries with different buffer sizes
CopyFile3.java: uses the NIO FileChannel method transferTo

CopyFile1.java uses BufferedInputStream and BufferedOutputStream. If you look at the source code for these files, the default buffer is an array of 2048 bytes. The first version of the NIO CopyFile2 program is also set to use an internal buffer of 2048 bytes. Other tests have been done with larger buffer sizes. As expected, the more buffer space allocated, the higher the performance (at a cost of more memory usage).

The result of copying the Java SDK file j2sdk-1_4_0-win.exe(37Meg) using JDK1.2.2, JDK1.3 and JDK1.4 on a Win2000/450Mhz machine is plotted here:


(All numbers are seconds)

CopyFile1.java:

import java.io.*;
 
public class CopyFile1
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile1 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));
      BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));
 
      int k;
      while ((k = bis.read()) != -1) {
         bos.write(k);
      }
   
      bis.close();
      bos.close();
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile2.java:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;
 
public class CopyFile2
{
   public static void main(String []args) throws IOException {
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile2 source dest");
         System.exit(1);
      }
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);
      FileOutputStream fos = new FileOutputStream(dest);
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      ByteBuffer buffer = ByteBuffer.allocateDirect(2048); 
 
      int n = channelIn.read(buffer);
      while (n > -1) {
         buffer.flip();
         channelOut.write(buffer);
         buffer.clear();
  
         n = channelIn.read(buffer);
      }      
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }
}

CopyFile3.java:

import java.nio.*;    
import java.nio.channels.*;    
import java.io.*;        
 
public class CopyFile3 
{        
   public static void main(String args[]) throws IOException {                
      if (args.length != 2) {
         System.err.println("Usage: java CopyFile3 source dest");
         System.exit(1);
      }             
 
      String source = args[0];
      String dest = args[1];
 
      long start = System.currentTimeMillis();
 
      FileInputStream fis = new FileInputStream(source);            
      FileOutputStream fos = new FileOutputStream(dest);            
      
      FileChannel channelIn = fis.getChannel();
      FileChannel channelOut = fos.getChannel();
 
      channelIn.transferTo(0, channelIn.size(), channelOut);                
 
      channelIn.close();            
      channelOut.close();            
 
      long stop = System.currentTimeMillis();
 
      System.out.println("Total time it took to copy: " + (stop - start) + "ms.");
   }    
}

Underlining a cell in a JTable

The easiest way is to use HTML in your text, check How do I create a JLabel with the text underlined?

But here’s a code sample that does not make use of the HTML feature. It underlines all Integers in the JTable whose values are between 1970 and 1980.

Main.java:

import javax.swing.table.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame 
{
   public Main() {
      super("Table example, Wines from Bordeaux");
 
      Object[][] tabledata = {
            { "Chateau Meyney, St. Estephe", 	   new Integer(1994), "$18.75"},
            { "Chateau Montrose, St. Estephe", 	   new Integer(1975), "$54.25" },
            { "Chateau Gloria, St. Julien", 	   new Integer(1993), "$22.99" },
            { "Chateau Beychevelle, St. Julien",   new Integer(1970), "$61.63" },
            { "Chateau La Tour de Mons, Margeaux", new Integer(1975), "$57.03" },
            { "Chateau Brane-Cantenac, Margeaux",  new Integer(1978), "$49.92" },
      };
 
      String columnheaders[] = { "Wine", "Vintage", "Price" };
 
      JTable table = new JTable(tabledata, columnheaders);
      table.setPreferredScrollableViewportSize(new Dimension(500, 70));
 
      UnderlineTableCellRenderer renderer = new UnderlineTableCellRenderer();
      table.setDefaultRenderer(Object.class, renderer);
      table.setRowHeight(30);
 
      JScrollPane scrollPane = new JScrollPane(table);
      getContentPane().add(scrollPane);
 
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(0);
         }
      });
 
      pack();
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
}
 
class UnderlineTableCellRenderer extends DefaultTableCellRenderer 
{
   public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                  boolean hasFocus, int row, int column) {
      if (value instanceof Integer) {
         Integer amount = (Integer) value;
         if (amount.intValue() > 1970 && amount.intValue() < 1980) {
            return new UnderlinedJLabel("" + amount.intValue());
         }
      }
 
      return super.getTableCellRendererComponent
                      (table, value, isSelected, hasFocus, row, column);
   }
}
 
class UnderlinedJLabel extends JLabel
{
   public UnderlinedJLabel() {
   }
 
   public UnderlinedJLabel(Icon image) {
      super(image);
   }
 
   public UnderlinedJLabel(Icon image, int horizontalAlignment) {
      super(image, horizontalAlignment);
   }
 
   public UnderlinedJLabel(String text) {
      super(text);
   }
 
   public UnderlinedJLabel(String text, Icon icon, int horizontalAlignment) {
      super(text, icon, horizontalAlignment);
   }
 
   public UnderlinedJLabel(String text, int horizontalAlignment) {
      super(text, horizontalAlignment);
   }
 
   public void paint(Graphics g) {
      super.paint(g);
      underline(g);
   }
 
   protected void underline(Graphics g) {
      Insets insets = getInsets();
      FontMetrics fm = g.getFontMetrics();
      Rectangle textR = new Rectangle();
      Rectangle viewR = new Rectangle(
                                  insets.left, 
                                  insets.top, 
                                  getWidth() - (insets.right + insets.left), 
                                  getHeight() - (insets.bottom + insets.top));
  
      // compute and return location of the icons origin,
      // the location of the text baseline, and a possibly clipped
      // version of the compound label string.  Locations are computed 
      // relative to the viewR rectangle.
      String text = SwingUtilities.layoutCompoundLabel(
                         this,                        // this JLabel
                         fm,                          // current FontMetrics
                         getText(),                   // text
                         getIcon(),                   // icon
                         getVerticalAlignment(),      
                         getHorizontalAlignment(),
                         getVerticalTextPosition(),
                         getHorizontalTextPosition(), 
                         viewR,                       
                         new Rectangle(),             // don't care about icon rectangle
                         textR,                       // resulting text locations
                         getText() == null ? 0 : ((Integer)UIManager.get("Button.textIconGap")).intValue());
 
      // draw line
      int textShiftOffset = ((Integer) UIManager.get("Button.textShiftOffset")).intValue();
      g.fillRect(textR.x +
                 textShiftOffset - 4,
                 textR.y + fm.getAscent() + textShiftOffset + 2,
                 textR.width, 
                 1);
   }
}

Writing your own Tomcat Valve

You can extend from org.apache.catalina.valves.ValveBase and implement the method invoke. The following example just prints out is has been called and invokes the next Valve.

MyValve.java:

import javax.servlet.http.*;
import javax.servlet.*;
import java.util.*;
import java.io.*;
import org.apache.catalina.valves.*;
import org.apache.catalina.*;
 
public class MyValve extends ValveBase
{
   /**
    * The descriptive information related to this implementation.
    */
   private static final String info = "MyValve/1.0";
 
   /**
    * Return descriptive information about this Valve implementation.
    */
   public String getInfo() {
      return (info);
   }
 
   public void invoke(Request request, Response response, ValveContext context)
                             throws IOException, ServletException {
      // Skip logging for non-HTTP requests and responses
      if (!(request instanceof HttpRequest) ||
          !(response instanceof HttpResponse)) {
         context.invokeNext(request, response);
         return;
      }
 
      HttpRequest httpRequest   = (HttpRequest) request;
      HttpResponse httpResponse = (HttpResponse) response;
      HttpServletRequest httpServletRequest   = (HttpServletRequest) httpRequest.getRequest();
      HttpServletResponse httpServletResponse = (HttpServletResponse) httpResponse.getResponse();
 
      System.out.println("nnnMyValve invokednnn");
 
      // continue processing the request
      context.invokeNext(request, response);
   }
 
   public String toString() {
      StringBuffer sb = new StringBuffer();
      sb.append("MyValve[");
      if (container != null) {
         sb.append(container);
      }
      sb.append("]");
      return sb.toString();
   }
}

Compile it with catalina.jar and servlet.jar in your classpath and place it in /server/classes.