Creating your own JSP exception page

If exceptions occur in JSP pages that are not handled, you can make the engine redirect to an JSP or HTML error page. You can even have access to the exception occurred (the “implicit exception object”) if you set the isErrorPage attribute to true.

A divide by zero JSP:

<%-- Redirect all uncaught exceptions to errorpage.jsp --%>
<%@ page errorPage="errorpage.jsp"%>

<%
   int h = 10 / 0;
%>

errorpage.jsp:

<%-- provides access to the implicit exception object --%>
<%@ page isErrorPage="true" %>
<html>
<body>
   <h3>An error occurred!</h3>
   <%=exception%>
</body>
</html>

Test it out here:
Divide by zero JSP

Dynamically add JARs from an application’s lib directory

This example assumes you have the JDBC mm.mysql driver residing in an ext subdirectory.

Main.java:

import java.util.*;
import java.net.*;
import java.io.*;
import java.sql.*;
 
public class Main
{
   public static void main(String []args) throws Exception {
      ClassLoader cl = loadExt();
      if (cl != null) {
         cl.loadClass("org.gjt.mm.mysql.Driver").newInstance();
         System.out.println("mysql driver successfully loaded!");
         Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/esus", "USER", "PASS");
 
         //. . .
      }
   }
 
   public static URLClassLoader loadExt() {
      try {
         Vector urls = new Vector();
         File file = new File("ext");
         String[] list = file.list();
         for (int i=0; i<list.length; i++) {
            if (list[i].endsWith(".jar")) {
               urls.add(new URL("file:" + file.getName() + "/" + list[i]));
            }
         }
         return new URLClassLoader((URL[]) urls.toArray( new URL[] { } ));
      } catch ( java.net.MalformedURLException me ) { 
         me.printStackTrace();
      }
 
      return null;
   }
}

Canonicalizing an XML file

The canonical form of an XML document is a normalized version of that XML document. Two XML documents that are physically different can still be logically the same. For example, consider an XML tag with two attributes. The order in which the attributes appear is of no importance:

(1)
<tag attrA="123" attrB="456"/>
  
is logically the same to 
 
(2) 
<tag attrB="456" attrA="123"/>

The canonical form of an XML document is important when you look at signing. Signing an XML document consists of calculating a message digest (hash) to ensure message integrity and signing the message and the hash with the private key of the sender. The receiver would then use the public key to verify.

The verification procedure should go successful regardless of the physical representation of the XML document. This is where the problem comes in: the digest of example (1) is different than the digest of example (2), even though the information is the same.

It is important to calculate the message digest on the canonical form of the XML document.

More information about canonical XML can be found here.

The following example uses the Canonicalizer class from the XML Security project at apache.org. Download it here and place the following libraries in your classpath:

bc-jce-jdk13-118.jar   (bouncycastle library)
log4j-1.2.5.jar
xalan.jar
xercesImpl.jar
xml-apis.jar
xmlsec.jar

Main.java:

import org.apache.xml.security.c14n.Canonicalizer;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.*;
 
import java.io.ByteArrayInputStream;
 
public class Main
{
   static String input1 = "<doc><field1 attr1="123" attr2="456"/><field2>abc</field2></doc>";
   static String input2 = "<doc><field1  attr1="123" attr2="456"   /><field2   >abc</field2></doc>";
   static String input3 = "<doc><field1 attr2="456" attr1="123"  /><field2>abc</field2></doc >";
 
   public static void main(String args[]) throws Exception 
   {
      org.apache.xml.security.Init.init();
 
      DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
      docFactory.setNamespaceAware(true);
      docFactory.setValidating(true);
 
      DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
 
      // This is to throw away all validation warnings
      docBuilder.setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler());
 
      System.out.println("Input:");
      System.out.println("  " + input1);
      System.out.println("  " + input2);
      System.out.println("  " + input3);
 
      byte[] output1 = canonicalize(docBuilder, input1);
      byte[] output2 = canonicalize(docBuilder, input2);
      byte[] output3 = canonicalize(docBuilder, input3);
 
      System.out.println("nOutput:");
      System.out.println("  " + new String(output1));
      System.out.println("  " + new String(output2));
      System.out.println("  " + new String(output3));
   }
 
   public static byte[] canonicalize(DocumentBuilder docBuilder, String input) throws Exception {
      byte inputBytes[] = input.getBytes();
      Document doc = docBuilder.parse(new ByteArrayInputStream(inputBytes));
      
      Canonicalizer c14n = Canonicalizer.getInstance(
        "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
 
      return c14n.canonicalizeSubtree(doc);
   }
}

outputs:

Input:
  <doc><field1 attr1="123" attr2="456"/><field2>abc</field2></doc>
  <doc><field1  attr1="123" attr2="456"   /><field2   >abc</field2></doc>
  <doc><field1 attr2="456" attr1="123"  /><field2>abc</field2></doc >

Output:
  <doc><field1 attr1="123" attr2="456"></field1><field2>abc</field2></doc>
  <doc><field1 attr1="123" attr2="456"></field1><field2>abc</field2></doc>
  <doc><field1 attr1="123" attr2="456"></field1><field2>abc</field2></doc>

Customizing the JavaMail Authenticator

Subclass javax.mail.Authenticator and provide an instance of this class when you create the session. The callback method getPasswordAuthentication is called whenever it is necessary to prompt for username/password.

This example provides an example in Swing using POP3.

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import javax.mail.internet.*;
import javax.mail.*;
import java.util.*;
 
public class Main
{
   public static void main(String []args) {
      try {
         String host = "POP3 HOST HERE";
   
         Properties properties = new Properties();
         properties.put("mail.host", host);
         Authenticator authenticator = new WindowAuthenticator();
         
         Session session = Session.getInstance(properties, authenticator);
  
         Store store = session.getStore("pop3");
         System.out.println("connecting tot POP3 server...");
         store.connect();
  
         // only "INBOX" is supported
         Folder folder = store.getFolder("INBOX");
 
         // open the folder read-only
         folder.open(Folder.READ_ONLY);
 
         System.out.println("Getting messages...");
         // get all the messages and print from and subject field 
         Message messages[] = folder.getMessages();
         for (int i=0; i<messages.length; i++) {
            System.out.print(messages[i].getMessageNumber() + "t");
            System.out.print(messages[i].getSentDate() + "t");
            System.out.print(messages[i].getFrom()[0] + "t");
            System.out.println(messages[i].getSubject());
         }
 
         // close the folder, but do not delete (expunge) the messages
         folder.close(false);
         store.close();
 
         System.exit(0);
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   }
}
 
class WindowAuthenticator extends Authenticator
{
   protected PasswordAuthentication getPasswordAuthentication() {
      WindowAuthenticatorDialog dialog = new WindowAuthenticatorDialog();
      dialog.pack();
      dialog.setResizable(false);
      dialog.setVisible(true);
 
      if (dialog.isCancelled()) {
         return null;
      }
 
      System.out.println("Username supplied: " + dialog.getUsername());
      System.out.println("Password supplied: " + dialog.getPassword());
 
      return new PasswordAuthentication(dialog.getUsername(), dialog.getPassword());
   }
}
 
class WindowAuthenticatorDialog extends JDialog
{
   private JTextField usernameTextField = new JTextField(20);
   private JTextField passwordTextField = new JTextField(20);
   private boolean cancelled = false;
 
   public WindowAuthenticatorDialog() {
      // make modal
      super(new JFrame(), "Supply your POP3 username and password", true);
 
      getContentPane().setLayout(new GridLayout(3, 1, 10, 10));
 
      JPanel panel1 = new JPanel(new FlowLayout());
      panel1.add(new JLabel("Username:"));
      panel1.add(usernameTextField);
      JPanel panel2 = new JPanel(new FlowLayout());
      panel2.add(new JLabel("Password:"));
      panel2.add(passwordTextField);
      JPanel panel3 = new JPanel(new FlowLayout());
      JButton okButton = new JButton("Ok");
      JButton cancelButton = new JButton("Cancel");
      panel3.add(okButton);
      panel3.add(cancelButton);
 
      getContentPane().add(panel1);
      getContentPane().add(panel2);
      getContentPane().add(panel3);
 
      Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
      int x = (int) ((d.getWidth() - getWidth()) / 2);
      int y = (int) ((d.getHeight() - getHeight()) / 2);
      setLocation(x, y);
 
      okButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            setVisible(false);
         }
      });
 
      cancelButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            cancelled = true;
            setVisible(false);
         }
      });
   }
 
   public String getUsername() {
      return usernameTextField.getText();
   }
 
   public String getPassword() {
      return passwordTextField.getText();
   }
 
   public boolean isCancelled() {
      return false;
   }
}

Get a list of messages from a POP server in Java

Main.java:

import javax.mail.internet.*;
import javax.mail.*;
import java.util.*;
 
public class Main
{
   public static void main(String []args) {
      try {
         String host = "FILL IN POP3 SERVER HERE";
         String user = "FILL IN UN HERE";
         String pass = "FILL IN PW HERE";
  
         Session session = Session.getInstance(System.getProperties(), null);
  
         Store store = session.getStore("pop3");
         store.connect(host, user, pass);
  
         // only "INBOX" is supported
         Folder folder = store.getFolder("INBOX");
 
         // open the folder read-only
         folder.open(Folder.READ_ONLY);
 
         // get all the messages and print from and subject field 
         Message messages[] = folder.getMessages();
         for (int i=0; i<messages.length; i++) {
            System.out.print(messages[i].getMessageNumber() + "t");
            System.out.print(messages[i].getSentDate() + "t");
            System.out.print(messages[i].getFrom()[0] + "t");
            System.out.println(messages[i].getSubject());
         }
 
         // close the folder, but do not delete (expunge) the messages
         folder.close(false);
         store.close();
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   }
}

Using a DigestOutputStream

With a DigestOutputStream, you can calculate a digest (SHA, MD5) while you are passing data through the stream. The process of calculating the digest can be turned off and on with the method DigestOutputStream.on(boolean).

In the following example, Main.java is read in and written to Main.java.digest. In the process, every other byte is taken into account to update the digest. In the end, the digest is appended to Main.java.digest.

Main.java:

import java.security.*;
import java.io.*;
 
public class Main
{
   public static void main(String []args) {
      try {
         FileInputStream fis = new FileInputStream("Main.java");
         FileOutputStream fos = new FileOutputStream("Main.java.digest");
 
         MessageDigest md = MessageDigest.getInstance("SHA");
         DigestOutputStream dos = new DigestOutputStream(fos, md);
 
         int b;
         boolean state = true;
         while ((b = fis.read()) != -1) {
            dos.write(b);
 
            state = !state;
            dos.on(state);
         }
 
         // turn of digest calculation
         // and write digest to end of file
         dos.on(false);
         byte[] buffer = md.digest();
         dos.write(buffer, 0, buffer.length);
         dos.close();
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   }
} 

Programmatically selecting a JTable column

columnSelectionAllowed must be true and rowSelectionAllowed must be false.

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();
      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.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
      table.setRowSelectionAllowed(false);
      table.setColumnSelectionAllowed(true);
 
      table.setColumnSelectionInterval(0, 0);
      table.addColumnSelectionInterval(2, 2);
 
      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;
   }
}

Catching an event when a form SUBMIT button has been clicked on a JTextPane

Set a custom HTMLEditorKit on your JTextPane. In the example below, this is MyHTMLEditorKit. It contains a factory that is responsible for returning a custom FormView. In MyFormView, you can override the method submitData that is called when the submit button is pressed. The form data is passed to this method in a escaped form.

Main.java:

import javax.swing.text.html.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.*;
import java.awt.*;
import java.io.*;
 
public class Main extends JFrame
{
   final JTextField urlTextField = new JTextField();
   final JEditorPane htmlPane = new JEditorPane();
   JButton urlButton = new JButton("Go!");
 
   public Main() {
      htmlPane.setEditable(false);
      urlTextField.setText("file:c:\test.html");
 
      urlButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            loadPage(urlTextField.getText());
         }
      });
 
      htmlPane.setEditorKit(new MyHTMLEditorKit());
 
      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);
      }
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setVisible(true);
   }
}

MyHTMLEditorKit.java:

import javax.swing.text.html.*;
import javax.swing.text.*;
 
public class MyHTMLEditorKit extends HTMLEditorKit {
   private static final ViewFactory customFactory = new MyHTMLFactory();
 
   public ViewFactory getViewFactory() {
      return customFactory;
   }
 
   public static class MyHTMLFactory extends HTMLEditorKit.HTMLFactory
   {
      public View create(Element elem) {
         Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
 
         if (o instanceof HTML.Tag) {
            HTML.Tag kind = (HTML.Tag) o;
            if (kind == HTML.Tag.INPUT || kind == HTML.Tag.SELECT || kind == HTML.Tag.TEXTAREA) {
               return new MyFormView(elem);
            }
            else return super.create(elem);
         }
 
         return super.create(elem);
      }
   }
}

MyFormView.java:

import javax.swing.text.html.*;
import javax.swing.text.*;
import java.awt.event.*;
import java.util.*;
 
public class MyFormView extends FormView
{
   public MyFormView(Element elem) {
      super(elem);
   }
 
   public void actionPerformed(ActionEvent event) {
      super.actionPerformed(event);
   }
 
   public void submitData(String data) {
      System.out.println("Escaped data: " + data);
   }
}

A simple HTML file to test it with: test.html:

<html>
<body>
 
<form METHOD=POST ACTION="performyourownaction">
 
   <i>Subcategory:</i><br>
   <SELECT NAME="subcat">
      <OPTION> J2SE </OPTION>
      <OPTION> J2EE </OPTION>
      <OPTION> J2ME </OPTION>
      <OPTION> Other </OPTION>
   </SELECT>
   <p>
   <i>Subject:</i><br>
      <input type=text size=80 maxsize=200 name="subject"><p>
   <i>Question:</i><br>
      <textarea name="question" cols=60 rows=4></textarea><p>
 
   <br><br>
 
   <input TYPE=SUBMIT VALUE=" Submit Question! ">
</form>
 
</body>
</html>

Get versioning information about a Java package

The following example creates a JAR file containing one class in the package com.esus.test with extra versioning information in the manifest file. The Main program prints out this info.

com/esus/test/TestClass.java:

package com.esus.test;
 
public class TestClass
{
   public void testMethod() {
      System.out.println("Hello world!");
   }
}

MANIFEST.MF:

Manifest-Version: 1.0
  
Name: com/esus/test/
Specification-Title: Test Specification
Specification-Vendor: Esus, Inc.
Specification-Version: 1.0
Implementation-Vendor: Esus, Inc.
Implementation-Title: Test Reference Implementation
Implementation-Version: 1.5

Note that you can specify this versioning information not only on package level (com/esus/test) but also on the top of the file. If no version information is found about a specific package, this general version information is returned.

To create this JAR file:

C:\myjars>dir
 Volume in drive C has no label.
 Volume Serial Number is 3C7A-79F5
 
 Directory of C:myjars
 
01/19/2003  06:55 PM    <DIR>          .
01/19/2003  06:55 PM    <DIR>          ..
01/19/2003  05:13 PM    <DIR>          com
01/19/2003  06:41 PM               268 MANIFEST.MF
               1 File(s)            268 bytes
               3 Dir(s)  34,651,611,136 bytes free
  
C:\myjars>jar cfm test.jar MANIFEST.MF com

Add test.jar to your classpath and run the following program to retrieve version information.

Main.java:

import com.esus.test.*;
 
public class Main
{
   public static void main(String []args) {
      Package pckg = TestClass.class.getPackage();
 
      System.out.println(pckg.getSpecificationTitle());
      System.out.println(pckg.getSpecificationVendor());
      System.out.println(pckg.getSpecificationVersion());
      System.out.println(pckg.getImplementationTitle());
      System.out.println(pckg.getImplementationVendor());
      System.out.println(pckg.getImplementationVersion());
   }
}

outputs:

Test Specification
Esus, Inc.
1.0
Test Reference Implementation
Esus, Inc.
1.5

Modifying the elements in an private array from another class?

An example:

import java.lang.reflect.*;
 
public class Main
{
   public static void main(String []args) throws Exception {
      PrivateClass pc = new PrivateClass();
 
      pc.printArray();
 
      Class clazz = pc.getClass();
      Field field = clazz.getDeclaredField("privateArray");
      field.setAccessible(true);
      int []array = (int[]) field.get(pc);
 
      array[0] = 3;
      array[1] = 2;
      array[2] = 1;
 
      pc.printArray();
   }
}
 
class PrivateClass
{
   private int[] privateArray = { 1, 2, 3 };
 
   public void printArray() {
      System.out.print("[ ");
      for (int i=0; i<privateArray.length; i++) {
         System.out.print(privateArray[i] + " ");
      }
      System.out.println("]");
   }
}

outputs:

[ 1 2 3 ]
[ 3 2 1 ]