Saving binary data in XML

You can encode the binary data in base-64 format. The following example Image2XML creates an XML and stores an image, encoded in base-64 format, in one of the tags. XML2Image does the opposite: given the XML, it will convert the base-64 back to binary and save it in a file.

The XML structure it creates looks like this:

<xmlimage>
   <format></format>
   <width></width>
   <height></height>
   <data></data>
</xmlimage>

Image2XML.java:

import org.w3c.dom.*;
import org.w3c.dom.traversal.*;
  
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 javax.swing.*;
import java.awt.*;
import java.io.*;
   
public class Image2XML
{
   public static void main(String []args) {
      if (args.length != 1) {
         System.out.println("Usage: java Image2XML <image>");
         System.exit(1);
      }
 
      // get format, width and height 
      String format = "";
      int findex = args[0].indexOf(".");
      if (findex > -1) {
         format = args[0].substring(findex+1);
      }
   
      ImageIcon imageIcon = new ImageIcon(args[0]);
      Image img = imageIcon.getImage();
 
      double width  = img.getWidth(null);
      double height = img.getHeight(null);       
 
      // get binary data and convert to base64 
      byte[] buffer = null;
      try {
         buffer = readBinaryFile(args[0]);
      }
      catch(Exception e) {
         e.printStackTrace();
         System.exit(1);
      }
 
      String data = new sun.misc.BASE64Encoder().encode(buffer);
  
      // create XML document
      Document doc;
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.newDocument();
  
         Element xmlimageEl = doc.createElement("xmlimage");
         Element formatEl   = doc.createElement("format");
         Element widthEl    = doc.createElement("width");
         Element heightEl   = doc.createElement("height");
         Element dataEl     = doc.createElement("data");
         xmlimageEl.appendChild(formatEl);
         xmlimageEl.appendChild(widthEl);
         xmlimageEl.appendChild(heightEl);
         xmlimageEl.appendChild(dataEl);
 
         formatEl.appendChild(doc.createTextNode(""+format));
         widthEl.appendChild(doc.createTextNode(""+width));
         heightEl.appendChild(doc.createTextNode(""+height));
         dataEl.appendChild(doc.createTextNode(data));
 
         doc.appendChild(xmlimageEl);
  
         TransformerFactory tf = TransformerFactory.newInstance();
         Transformer transformer = tf.newTransformer();
         PrintWriter pw = new PrintWriter(new FileWriter(args[0]+".xml"));
         transformer.transform(new DOMSource(doc), new StreamResult(pw));
      }
      catch(Exception e) {
         e.printStackTrace();
      }
 
      System.exit(0);  // awt thread has been started
   }
 
   public static byte[] readBinaryFile(String filename)
                            throws IOException, FileNotFoundException {
      File f = new File(filename);         
      BufferedInputStream bis = new BufferedInputStream(
                                      new FileInputStream(f));         
      byte[] buffer = new byte[(int) f.length()];         
      bis.read(buffer, 0, buffer.length);         
      bis.close();
 
      return buffer;
   }
}

XML2Image.java:

import org.w3c.dom.*;
import org.w3c.dom.traversal.*;
  
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
  
import javax.swing.*;
import java.awt.*;
import java.io.*;
   
public class XML2Image
{
   public static void main(String []args) {
      if (args.length != 1) {
         System.out.println("Usage: java XML2Image <xml>");
         System.exit(1);
      }
 
      Document doc;
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File(args[0]));
 
         Node root = doc.getFirstChild();  
         NodeList nl = root.getChildNodes();
          
         String format="", width="", height="", data="";
         for (int i=0; i<nl.getLength(); i++) {
            Node item = nl.item(i);
            Node text = item.getFirstChild();
            if (item.getNodeName().equals("format"))      format = text.getNodeValue();
            else if (item.getNodeName().equals("width"))  width  = text.getNodeValue();
            else if (item.getNodeName().equals("height")) height = text.getNodeValue();
            else if (item.getNodeName().equals("data"))   data   = text.getNodeValue();
         }
 
         System.out.println("Image width = " + width + ", height = " + height);
 
         byte[] b = new sun.misc.BASE64Decoder().decodeBuffer(data);
 
         BufferedOutputStream bos = new BufferedOutputStream(
                                           new FileOutputStream(args[0]+"."+format));
         bos.write(b);
         bos.close();
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Using a PreparedStatement

If you need to execute a certain SQL statement a number of times, you can have it optimized by the underlying DBMS by using a PreparedStatement. A PreparedStatement is called a precompiled SQL statement, but can still be parametrized. In other words, it can accept certain input parameters.

So:

   Statement stmt = connection.createStatement();
   stmt.executeUpdate("INSERT INTO products (description, price) " +
                      "VALUES ('Chateau Meyney, St. Estephe', 18.75, 2)");

will have the same result as:

   PreparedStatement insertStmt = connection.prepareStatement("
                                       "INSERT INTO products (description, price) " +
                                       "VALUES (?, ?, ?)";
   insertStmt.setString(1, "Chateau Meyney, St. Estephe");
   insertStmt.setFloat(2, 18.75f);
   insertStmt.setInt(3, 2);
   insertStmt.executeUpdate();

The latter one does take somewhat more time to set up (precompilation), but if you need to insert a lot of rows, it is beneficial cause you can reuse insertStmt and change its parameters.

executeUpdate returns the number of rows that were affected.

You can do the same thing for SELECT statements with executeQuery. It returns a ResultSet containing the rows that match your query.

If you need to clear the parameters that were set, invoke the method clearParameters.

Main.java:

import java.util.*;
import java.sql.*;
  
public class Main {
   public static void main(String []args) {
      try {
         Database db = new Database("org.gjt.mm.mysql.Driver",
                                    "jdbc:mysql://192.168.0.1/esus",
                                    "joris",
                                    "mypass");
         Connection con = db.getConnection();
         ProductDAO prodDAO = new ProductDAO(con);
 
         printCollection(prodDAO.getAllRows()); 
 
         prodDAO.insert(new Product("Chateau Meyney, St. Estephe",       18.75f, 2));
         prodDAO.insert(new Product("Chateau Montrose, St. Estephe",     54.25f, 2));
         prodDAO.insert(new Product("Chateau Gloria, St. Julien",        22.99f, 2));
         prodDAO.insert(new Product("Chateau Beychevelle, St. Julien",   61.63f, 2));
         prodDAO.insert(new Product("Chateau La Tour de Mons, Margeaux", 57.03f, 2));
         prodDAO.insert(new Product("Chateau Brane-Cantenac, Margeaux",  49.92f, 2));
  
         printCollection(prodDAO.getAllRows()); 
         db.close();
      }
      catch(DatabaseException e) {
         e.printStackTrace();
      }
   }
 
   public static void printCollection(Collection c) {
      Iterator iter = c.iterator();
      while (iter.hasNext()) {
         System.out.println(iter.next());
      }
   }
}
 
class Product
{
   private String description;
   private float price;
   private int itemsleft;
 
   public Product() { }
 
   public Product(String description, float price, int itemsleft) {
      setDescription(description);
      setPrice(price);
      setItemsleft(itemsleft);
   }
  
   public void setDescription(String description) {
      this.description = description;
   }
 
   public void setPrice(float price) {
      this.price = price;
   }

   public void setItemsleft(int itemsleft) {
      this.itemsleft = itemsleft;
   }
 
   public String getDescription() {
      return description;
   }
 
   public float getPrice() {
      return price;
   }
  
   public int getItemsleft() {
      return itemsleft;
   }
 
   public String toString() {
      return "Product [description=" + getDescription() + ", price=" + getPrice() + 
             ", itemsleft=" + getItemsleft() + "]";
   }
}
 
class Database
{
   Connection connection = null;
  
   public Database(String driver, String url, String user, String pass) 
                      throws DatabaseException 
   {
      try {
         Class.forName(driver).newInstance();
 
         connection = DriverManager.getConnection(url, user, pass);
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Connection getConnection() {
      return connection;
   }
 
   public void close() throws DatabaseException {
      try {
         connection.close();
      }
      catch(Exception e) {
         throw new DatabaseException(e.getMessage());
      }
   } 
}   
 
class DatabaseException extends Exception {
   public DatabaseException() {
   }
 
   public DatabaseException(String message) {
      super(message);
   }
}
 
class ProductDAO 
{
   Connection connection = null;
   PreparedStatement insertStmt = null;
 
   public ProductDAO(Connection connection) {
      this.connection = connection;
   }
 
   public void insert(Product prod) throws DatabaseException {
      try {
         if (insertStmt == null) {
            insertStmt = connection.prepareStatement(
                            "INSERT INTO products (description, price, itemsleft) " +
                            "VALUES (?, ?, ?)");
         }
 
         insertStmt.setString(1, prod.getDescription());
         insertStmt.setFloat(2, prod.getPrice());
         insertStmt.setInt(3, prod.getItemsleft());
         insertStmt.executeUpdate();  
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
 
   public Collection getAllRows() throws DatabaseException {
      try {
         ArrayList al = new ArrayList();
 
         Statement stmt = connection.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM products");
         while (rs.next()) {
            Product prod = new Product();
            prod.setDescription(""+rs.getString("description"));
            prod.setPrice(rs.getFloat("price"));
            prod.setItemsleft(rs.getInt("itemsleft"));
            al.add(prod);
         }
         
         stmt.close();
 
         return al;
      }
      catch(SQLException e) {
         throw new DatabaseException(e.getMessage());
      }
   }
}

Creating a thread-safe singleton class

The best way is:

public class ExampleSingleton {
 
  private static ExampleSingleton instance;
 
  public static ExampleSingleton getInstance() {
    if( instance == null ) {
      synchronized( ExampleSingleton.class ) {
        if ( instance == null ) {
           instance = new ExampleSingleton();
        }
      }//sync ends
    }
 
    return instance;
  }
}

to make it threadsafe you have to use synchronization. But if you sync the whole method, you will create a tiny unnecessary performance overhead. Watch that the second if-condition is vitally important. Lets say instance is null, at this point two threads are executing the method. one thread goes in the sync block and the other starts waiting. when the second thread gets the lock and enters sync block, the Singleton has already been creates by the first thread. If you ommit the second if-condition, the second thread will create a second instance of the singleton.

Hope it helps.

Creating a formatted textfield that only accepts IP addresses

JDK1.4 introduced the JFormattedTextfield with which you can set a mask on a text field.
This example not only shows you how to set the mask (eg. 255.255.xxx.xxx), but also how to use an InputVerifier to check whether the inputted digits lie in the range [0-255].

Main.java:

import javax.swing.JFormattedTextField.*;
import javax.swing.text.*;
import java.awt.event.*;
import javax.swing.*;
import java.text.*;
import java.util.*;
import java.awt.*;
 
public class Main extends JFrame 
{
   public Main() throws Exception
   {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
 
      MaskFormatter formatter = new MaskFormatter("255.255.###.###");
      formatter.setPlaceholderCharacter('0');
 
      final JFormattedTextField formattedTf = new JFormattedTextField(formatter);
      formattedTf.setInputVerifier(new IPTextFieldVerifier());
 
      final JTextField normalTf = new JTextField(25);
      JButton button = new JButton("Get value");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) { 
            normalTf.setText(""+formattedTf.getValue());
         }
      });
 
      getContentPane().setLayout(new FlowLayout(FlowLayout.LEFT));
      getContentPane().add(formattedTf);
      getContentPane().add(button);
      getContentPane().add(normalTf);
 
      formattedTf.setPreferredSize(normalTf.getPreferredSize());
   }
  
   public static void main(String args[]) throws Exception 
   {
      Main main = new Main();
      main.setSize(300, 150);
      main.setVisible(true);
   }
}
 
class IPTextFieldVerifier extends InputVerifier {
   public boolean verify(JComponent input) {
      if (input instanceof JFormattedTextField) {
         JFormattedTextField ftf = (JFormattedTextField)input;
         AbstractFormatter formatter = ftf.getFormatter();
         if (formatter != null) {
            String text = ftf.getText();
            StringTokenizer st = new StringTokenizer(text, ".");
            while (st.hasMoreTokens()) {
               int value = Integer.parseInt((String) st.nextToken());
               if (value < 0 || value > 255) {
                  // to prevent recursive calling of the 
                  // InputVerifier, set it to null and
                  // restore it after the JOptionPane has
                  // been clicked.
                  input.setInputVerifier(null);
                  JOptionPane.showMessageDialog(new Frame(), "Malformed IP Address!", "Error", 
                                                JOptionPane.ERROR_MESSAGE);
                  input.setInputVerifier(this);  
                  return false;
               }
            }
            return true;
         }
      }
      return true;
   }
 
   public boolean shouldYieldFocus(JComponent input) {
      return verify(input);
   }
}

Running Tomcat with a security manager

Create a web application that contains the following jsp:

<html>
<body>
Trying to shutdown Tomcat, please press reload.
<%
   System.exit(1);
%>
</body>
</html>

Run Catalina (eg. catalina run) and load up the jsp. Notice in the Tomcat console that Tomcat has exited. What happens is that, by default, Tomcat is started without a security manager. The JSP, that was compiled into a servlet, runs in the same Virtual Machine as Tomcat itself, and System.exit causes the currently running VM to exit.

To prevent this from happening, run Tomcat with a Security Manager to not permit web applications to perform these kinds of operations. The security policy file used by Catalina is catalina.policy located in the [TOMCAT-HOME]/conf directory.

If you start Catalina again with the option -security (eg. catalina run -security, or startup -security), catalina.policy is taken into account.

If you then load the jsp, you would get the following error message in your browser window:

java.security.AccessControlException: access denied (java.lang.RuntimePermission exitVM)
	at java.security.AccessControlContext.checkPermission(AccessControlContext.java:272)
	at java.security.AccessController.checkPermission(AccessController.java:399)
	at java.lang.SecurityManager.checkPermission(SecurityManager.java:545)
	at java.lang.SecurityManager.checkExit(SecurityManager.java:765)
	at java.lang.Runtime.exit(Runtime.java:91)
	at java.lang.System.exit(System.java:701)
	at org.apache.jsp.ExitTomcat$jsp._jspService(ExitTomcat$jsp.java:59)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:107)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
. . .

Using a ToggleButton in SWT

Main.java:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Shell;
 
public class Main {
   public static void main(String[] args) {
      Display display = new Display();
      Shell shell = new Shell(display);
 
      // pos x, pos y, width, height
      shell.setBounds(200, 200, 300, 200);
      shell.setText("SWT ToggleButton Demonstration");
      shell.setLayout(new GridLayout());
 
      Group buttonGroup = new Group(shell, SWT.NONE);
      GridLayout gridLayout = new GridLayout();
      gridLayout.numColumns = 3;
      buttonGroup.setLayout(gridLayout);
      buttonGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
      SelectionListener selectionListener = new SelectionAdapter () {
         public void widgetSelected(SelectionEvent event) {
            Button button = ((Button) event.widget);
            System.out.print(button.getText());
            System.out.println(" selected = " + button.getSelection());
         };
      };
      
      Button button1 = new Button(buttonGroup, SWT.TOGGLE);
      button1.setText("orange");
      button1.addSelectionListener(selectionListener);
      Button button2 = new Button(buttonGroup, SWT.TOGGLE);
      button2.setText("pear");
      button2.addSelectionListener(selectionListener);
      Button button3 = new Button(buttonGroup, SWT.TOGGLE);
      button3.setText("apple");
      button3.addSelectionListener(selectionListener);
      
      shell.open();
 
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) {
            display.sleep();
         }
      }
      display.dispose();
   }
}

Creating an SWT PrintDialog

Main.java:

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.printing.PrintDialog;
import org.eclipse.swt.printing.PrinterData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Shell;
 
public class Main { 
   static Display display;
   static Shell shell;
   static Color color;
    
   public static void main(String[] args) {
      display = new Display();
      shell = new Shell(display);
 
      // pos x, pos y, width, height
      shell.setBounds(200, 200, 400, 200);
      shell.setText("SWT PrintDialog Demonstration");
      shell.setLayout(new GridLayout());
 
      final Group buttonGroup = new Group(shell, SWT.NONE);
      GridLayout gridLayout = new GridLayout();
      gridLayout.numColumns = 3;
      buttonGroup.setLayout(gridLayout);
      buttonGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
       
      final Button directoryDialogButton = new Button(buttonGroup, SWT.PUSH);
      directoryDialogButton.setText("Open PrintDialog");
 
      SelectionListener selectionListener = new SelectionAdapter () {
         public void widgetSelected(SelectionEvent event) {
            PrintDialog dialog = new PrintDialog (shell, SWT.MODELESS);
            dialog.setText("Print");
            PrinterData result = dialog.open ();
         };
      };
       
      directoryDialogButton.addSelectionListener(selectionListener);
       
      shell.open();
 
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) {
            display.sleep();
         }
      }
      if (color != null && !color.isDisposed()) {
         color.dispose();
      }
      display.dispose();
   }
}

Creating an SWT Tree

Main.java:

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
 
public class Main {
   public static void main(String[] args) {
      Display display = new Display();
      Shell shell = new Shell(display);
 
      // pos x, pos y, width, height
      shell.setBounds(200, 200, 300, 200);
      shell.setText("SWT Tree Demonstration");
      shell.setLayout(new GridLayout());
 
      Tree tree = new Tree(shell, SWT.BORDER);
       
      TreeItem node1 = new TreeItem (tree, SWT.NULL);
      node1.setText("Java");
       
      TreeItem node2 = new TreeItem(node1, SWT.NULL);
      node2.setText("j2se");
      TreeItem node3 = new TreeItem(node1, SWT.NULL);
      node3.setText("j2ee");
      TreeItem node4 = new TreeItem(node1, SWT.NULL);
      node4.setText("j2me");
       
      TreeItem node5 = new TreeItem(node2, SWT.NULL);
      node5.setText("http://java.sun.com/j2se/");
 
      TreeItem node6 = new TreeItem(node3, SWT.NULL);
      node6.setText("http://java.sun.com/j2se/");
  
      TreeItem node7 = new TreeItem(node4, SWT.NULL);
      node7.setText("http://java.sun.com/j2se/");
       
      tree.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL));
             
      shell.open();
 
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) {
            display.sleep();
         }
      }
       
      display.dispose();
   }
}

Monitoring specific AWT events

The following example monitors Window events and Key events and prints them out.

Main.java:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
class Main extends JFrame
{
   public Main() {
      Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
         public void eventDispatched(AWTEvent e) {
            System.out.println(e);
         }
      }, AWTEvent.KEY_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK );
   }
 
   public static void main(String[] args) {
      Main main = new Main();
      main.setDefaultCloseOperation( EXIT_ON_CLOSE );
      main.setSize(200, 200);
      main.setVisible(true);
   }
}