Don’t change filename textfield when a directory is selected in a JFileChooser

Here’s some code that solves that problem.

Main.java:

import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.io.*;
 
public class Main extends JFrame
{
   private String fileSelected = "autoexec.bat";
 
   public static void main(String []args) {
      Main main = new Main();
      main.show();
   }
  
   public Main() {
      JButton fileButton = new JButton("Select File");
      fileButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            File file = getFileFromUser();
            if (file != null)
               System.out.println(file.getName());
         }
      });
      getContentPane().add(fileButton);
  
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
 
      pack();
   }
  
   public File getFileFromUser() {
      JFileChooser fc = new JFileChooser();
 
      // use current directory
      fc.setCurrentDirectory(new File("c:\"));
 
      // set default name
      fc.setSelectedFile(new File(fileSelected));
 
      fc.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent pce) {
            String property = pce.getPropertyName();
            if (property.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
               File dir = (File) pce.getNewValue();
               if (dir.isDirectory()) {
                  ((JFileChooser) pce.getSource()).setSelectedFile(new File(dir, fileSelected));
               }
               else {
                  fileSelected = ((JFileChooser) pce.getSource()).getSelectedFile().getName();
               }
            }
            else if (property.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
               File dir = (File) pce.getNewValue();
               ((JFileChooser) pce.getSource()).setSelectedFile(new File(dir, fileSelected));
            }
         }
      });
 
      // show dialog for opening files
      int result = fc.showSaveDialog(this);
 
      if (result != fc.APPROVE_OPTION) 
         return null;
       
      return fc.getSelectedFile();
   }
}

Creating an SWT DirectoryDialog

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.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.ColorDialog;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
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 DirectoryDialog 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 DirectoryDialog");
      Label label1 = new Label(buttonGroup, SWT.NONE);
      label1.setText("Selected:");
      final Label label2 = new Label(buttonGroup, SWT.NONE);      
      label2.setText("");
 
      SelectionListener selectionListener = new SelectionAdapter () {
         public void widgetSelected(SelectionEvent event) {
            DirectoryDialog dialog = new DirectoryDialog (shell, SWT.MODELESS);
            dialog.setMessage ("Please select the desired directory.  Notice network neighborhood!");
            dialog.setText("Select the desired directory");
            String result = dialog.open();
            label2.setText("" + result);
            buttonGroup.layout();
         };
      };   
       
      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 table with the lines visible

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.Group;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
  
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 Table Demonstration");
      shell.setLayout(new GridLayout());
  
      Table table;
      String[] columnTitles = { "Wine", "Vintage", "Price" };
 
      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" },
      };
  
      Group tableGroup = new Group(shell, SWT.NULL);
      GridLayout gridLayout = new GridLayout();
      gridLayout.numColumns = 1;
      tableGroup.setLayout(gridLayout);
      tableGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
      tableGroup.setText("Table");
  
      table = new Table(tableGroup, SWT.FULL_SELECTION);
      table.setHeaderVisible(true);
      table.setLinesVisible(true);
        
      for (int i=0; i<columnTitles.length; i++) {
         TableColumn tableColumn = new TableColumn(table, SWT.NULL);
         tableColumn.setText(columnTitles[i]);
      }  
        
      for (int i=0; i<tabledata.length; i++) {
         TableItem tableItem = new TableItem (table, SWT.NULL);
         for (int j=0; j<columnTitles.length; j++) {
            tableItem.setText(j, ""+tabledata[i][j]);
         }
      }
  
      for (int i=0; i<columnTitles.length; i++) {
         TableColumn tableColumn = table.getColumn(i);
         tableColumn.pack();
      }      
        
      shell.open();
  
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch()) {
            display.sleep();
         }
      }
      display.dispose();
   }
}

Creating a scale in SWT

Main.java:

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
 
public class Main {
   public static void main (String [] args) {
      Display display = new Display ();
      Shell shell = new Shell (display);
   
      shell.setBounds(200, 200, 250, 250);   
       
      final Scale scale = new Scale (shell, SWT.VERTICAL);
      scale.setMinimum(100);
      scale.setMaximum(200);
      scale.setBounds(10, 10, 30, 200);
      final StyledText styledText = new StyledText(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.WRAP);
      styledText.setBounds(50, 10, 180, 200);
       
      scale.addListener(SWT.Selection, new Listener () {
         public void handleEvent(Event event) {
            styledText.append(scale.getSelection() + "n");
            int offset = styledText.getOffsetAtLine(styledText.getLineCount()-1);
            styledText.setCaretOffset(offset);
            styledText.showSelection();
         }
      });
 
      shell.open ();
      while (!shell.isDisposed()) {
         if (!display.readAndDispatch ()) display.sleep ();
      }
   }
} 

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>

Get a private key from a keystore

This example extracts a private key from a keystore and prints it out in PEM format.

Main.java:

import sun.misc.BASE64Encoder;
import java.security.cert.Certificate;
import java.security.*;
import java.io.File;
import java.io.FileInputStream;
 
class Main {
   public static void main(String args[]) throws Exception{
      if (args.length != 3) {
         System.out.println("Extracts private key in PEM format from a JKS keystore");
         System.out.println("Usage: java Main <keystore> <alias> <passphrase>");
         System.exit(1);
      }
 
      String keystore = args[0];
      String alias = args[1];
      String password = args[2];      
 
      KeyStore ks = KeyStore.getInstance("JKS");
      char[] passphrase = password.toCharArray();
      BASE64Encoder base64Encoder = new BASE64Encoder();
 
      ks.load(new FileInputStream(keystore), passphrase);
 
      PrivateKey privateKey = getPrivateKey(ks, alias, passphrase);
 
      String sPrivateKey = base64Encoder.encode(privateKey.getEncoded());
 
      System.out.println("-----BEGIN PRIVATE KEY-----");
      System.out.println(sPrivateKey);
      System.out.println("-----END PRIVATE KEY-----");
   }
 
   public static PrivateKey getPrivateKey(KeyStore keystore, String alias, char[] password) {
      try {
         Key key = keystore.getKey(alias, password);
         if (key instanceof PrivateKey) {
            Certificate cert = keystore.getCertificate(alias);
            PublicKey publicKey = cert.getPublicKey();
 
            KeyPair kp = new KeyPair(publicKey, (PrivateKey)key);
 
            return kp.getPrivate();
         }
      } catch (UnrecoverableKeyException e) {
         e.printStackTrace();
      } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
      } catch (KeyStoreException e) {
         e.printStackTrace();
      }
 
      return null;
   }
}

Pinging a host in JDK1.5

JDK1.5 provides the functionality to test the reachability of a host. Before JDK 1.5, you had to implement this yourself (for example by sending UDP packets to the echo port (7) of the target machine).

Actually, the strategy of the implementation of isReachable is to try to use ICMP if it is available, or else to try to connect to the echo port.

This example shows you how the test the reachability of a host:

import java.net.*;

public class Main
{
   public static void main(String []args) throws Exception {
      if (args.length != 1) {
         System.out.println("Usage: java Main <host or ipaddress>");
         System.exit(1);
      }
      
      InetAddress inetAddress = InetAddress.getByName(args[0]);
      System.out.println(inetAddress);
      
      System.out.println(args[0] + " is reachable? " + inetAddress.isReachable(5000));
   }  
}

Using the ClassFileTransformer in JDK 1.5

The package java.lang.instrument allows you to modify class classfiles as they are loaded. On the command line, you register your own implementation of the ClassFileTransformer and this will be called by the VM every time a class is loaded.

On this page, you’ll find a working example of a ClassFileTransformer that will add a log statement to every method of every class that is about to be loaded. To perform the bytecode manipulation, I used the well-known Jakarta BCEL library.

Two related Q&A’s to achieve this kind of functionality are
How do I get started with writing a dynamic proxy class?
How do I get started with AspectJ?

MethodInstrument.java:

import java.lang.instrument.Instrumentation;
import java.security.*;
  
import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;
 
import java.io.*;
import java.lang.reflect.*;
 
public class MethodInstrument 
{
   public static void premain(String options, Instrumentation instrumentation) {
      instrumentation.addTransformer(new EntryExitMethodTransformer());
   }
   
   public static class EntryExitMethodTransformer implements ClassFileTransformer 
   {
      public byte[] transform(ClassLoader loader, String cn, Class classBeingRedefined, 
                              ProtectionDomain protectionDomain, byte[] classfileBuffer) 
                                  throws IllegalClassFormatException
      {
         //System.out.println("Transforming class " + cn);
         if (cn.startsWith("java") || cn.startsWith("javax") || cn.startsWith("sun")) {
            return classfileBuffer;
         }
         try {
            ByteArrayInputStream bais = new ByteArrayInputStream(classfileBuffer);
             
            ClassParser parser = new ClassParser(bais, cn);
            JavaClass clazz = parser.parse();
        
            ClassGen classGen = new ClassGen(clazz);
        
            Method[] methods = clazz.getMethods();
            for (int i=0; i<methods.length; i++) {
               InstructionFactory instructionFactory = new InstructionFactory(classGen);
               InstructionList instructionList = new InstructionList();
               ConstantPoolGen constantPoolGen = classGen.getConstantPool();
               String className = classGen.getClassName();            
  
               Method method = methods[i];
               MethodGen wrapGen = new MethodGen(method, className, constantPoolGen);
               instructionList = wrapGen.getInstructionList();
                
               String text = "Call to method " + cn + "." + method.getName();
               instructionList.insert(instructionFactory.createInvoke(
                        "java.io.PrintStream", "println"
                        , Type.VOID, new Type[] { Type.STRING }
                        , Constants.INVOKEVIRTUAL
                      ));
               instructionList.insert(new PUSH(constantPoolGen, text));
               instructionList.insert(instructionFactory.createFieldAccess(
                        "java.lang.System", "out", new ObjectType("java.io.PrintStream")
                        , Constants.GETSTATIC
                      ));
   
               wrapGen.stripAttributes(true);
               wrapGen.setMaxStack();
               wrapGen.setMaxLocals();
      
               classGen.removeMethod(method);
               classGen.addMethod(wrapGen.getMethod());
            }
    
            return classGen.getJavaClass().getBytes();
         }
         catch(Exception e) {
            throw new IllegalClassFormatException(e.getMessage());
         }
      }
   }
}

Be sure to include the BCEL library in your classpath (eg. bcel-5.1.jar).

A simple program to test our EntryMethodTransformer:

Test.java:

public class Test
{
   public static void main(String []args) {
      a();
   }
   
   public static void a() {
      b();
   }
   
   public static void b() {
      c();
   }
   
   public static void c() {
      System.out.println("C reached!");
   }
}

Now run Test, but provide the MethodInstrument agent on the command line:

java -javaagent:MethodInstrument Test

outputs:

Call to method Test.main
Call to method Test.a
Call to method Test.b
Call to method Test.c
C reached!

Error message “Bad Magic Number”

Each class file starts with special 4 bytes equal to the hexadecimal value of 0xCAFEBABE – this number identifies the class file format and is humorously named “Magic Number”. When you get an error from the JVM saying “Bad Magic Number”, it simply means the class file it is trying to load is corrupt.

The solution is usually to recompile all your classes.

Drawing a rotated image

Work directly on the class Graphics2D or use the class AffineTransform that allows you to create your own transformation matrixes.

Directly on Graphics2D

Main.java:

import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame {
   private Image image;
   private boolean firstTime = true;
   private int degrees = 0;
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
 
      image = Toolkit.getDefaultToolkit().getImage("c:\djkrush.jpg");
      waitForImage(image);
 
      getContentPane().setLayout(new BorderLayout());
      JButton button = new JButton("rotate by 10 degrees");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            degrees += 10;
            repaint();
         }
      });
 
      getContentPane().add(BorderLayout.SOUTH, button);
   }
 
   public void paint(Graphics g) {
      super.paint(g);
 
      Graphics2D g2d = (Graphics2D) g;
 
      double radians = degrees * (Math.PI / 180);
      g2d.translate(getSize().width/2, getSize().height/2);
      g2d.rotate(radians); 
      g2d.drawImage(image, 0, 0, this);
   }
 
   public void waitForImage(Image image) {
      MediaTracker mt = new MediaTracker(this);
 
      int id = 0;
      mt.addImage(image, id);
 
      try {
         mt.waitForID(id);
      }
      catch(InterruptedException e) {
         System.out.println("Image loading interrupted : " + e);
      }
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(400, 400);
      main.setVisible(true);
   }
}

Using AffineTransform

Main.java:

import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.awt.*;
 
public class Main extends JFrame {
   private Image image;
   private boolean firstTime = true;
   private int degrees = 0;
 
   public Main() {
      addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent we) {
            System.exit(1);
         }
      });
 
      image = Toolkit.getDefaultToolkit().getImage("c:\djkrush.jpg");
      waitForImage(image);
 
      getContentPane().setLayout(new BorderLayout());
      JButton button = new JButton("rotate by 10 degrees");
      button.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent ae) {
            degrees += 10;
            repaint();
         }
      });
 
      getContentPane().add(BorderLayout.SOUTH, button);
   }
 
   public void paint(Graphics g) {
      super.paint(g);
 
      if (degrees == 0) {
         g.drawImage(image, getSize().width/2, getSize().height/2, this);
      }
      else {  
         Graphics2D g2d = (Graphics2D) g;
 
         double radians = degrees * (Math.PI / 180);
         AffineTransform at = new AffineTransform();
         at.translate(getSize().width/2, getSize().height/2);
         at.rotate(radians);
         g2d.drawImage(image, at, this);
      }
   }
 
   public void waitForImage(Image image) {
      MediaTracker mt = new MediaTracker(this);
 
      int id = 0;
      mt.addImage(image, id);
 
      try {
         mt.waitForID(id);
      }
      catch(InterruptedException e) {
         System.out.println("Image loading interrupted : " + e);
      }
   }
 
   public static void main(String []args) {
      Main main = new Main();
      main.setSize(400, 400);
      main.setVisible(true);
   }
}

image used: