Download a page in Java when HTTP authentification is required

In your browser, you can type: http://username:password@host.com/securestuff to automatically authenticate if this page is protected. You can’t do this with the URL class, it will come back with an UnknownHostException. But there is a way: create a URLConnection and set the authorization request property (for more information on request properties, check out the link in related links). This example shows you how to retrieve the data on a protected page providing you have the username and password. It makes use of the sun.misc package to do the required Base64 encoding of the concatenated string “username:password”. You may want to replace the use of the “sun.misc” package by your own implementation of Base64 (or another provider) as the availability of sun. classes is not guaranteed in future versions of the JDK.

Main.java:

import sun.misc.*;
import java.net.*;
import java.io.*;
  
public class Main
{
   public static void main(String args[]) 
   {
      try {
         if (args.length != 3) {
            System.err.println("Usage: java Main <URL> <username> <password>");
            System.exit(0);
         }
 
         String authReq = args[1] + ":" + args[2];
         BASE64Encoder B64Encoder = new BASE64Encoder();
         String encodedAuthReq = B64Encoder.encode(authReq.getBytes());
 
         URL url = new URL(args[0]);
         URLConnection connection = url.openConnection();
         connection.setDoInput(true);
         connection.setRequestProperty("Authorization", "basic " + encodedAuthReq);
         connection.connect();
         
         InputStream in = connection.getInputStream();
 
         BufferedReader br = new BufferedReader(new InputStreamReader(in));
   
         String line;
         while ((line = br.readLine()) != null) {
            System.out.println(line);
         }
      }
      catch (MalformedURLException e) {
         System.err.println (e);
      }
      catch (IOException e) {
         System.err.println (e);
      }
   }
}

Get started with RMI

Here’s a simple example that uses localhost for both client and server. It was tested on Win2000 machine running JDK1.3.1.

The purpose is to create an rmi server that contains a remote method listFiles which the client can call with a path to retrieve the list of files in that directory.

- Create a directory c:rmi.
- Create a directory c:rmifileservice.
- Create the following files:

c:rmifileserviceIFileService.java:

package fileservice;
 
import java.rmi.server.*;
import java.util.*;
import java.rmi.*;
 
public interface IFileService extends Remote
{
   public List listFiles(String path) throws RemoteException;
}

c:rmifileserviceFileService.java:

package fileservice;
 
import java.util.*;
import java.rmi.*;
 
public class FileServiceClient
{
   public static void main(String []args) {
      if (System.getSecurityManager() == null) {
         System.setSecurityManager(new RMISecurityManager());
      }
        
      try {
         IFileService fs = FileServiceFactory.getFileService();
 
         List list = fs.listFiles(".");
         for (int i=0; i<list.size(); i++) {
            System.out.println(list.get(i));
         }
      }
 
      // not required to catch (RuntimeExceptions) but we'll do
      // got give hints in case something goes wrong
      catch(java.security.AccessControlException e) {
         e.printStackTrace();
         System.out.println("nHint: did you specify -Djava.security.policy=...policy?");
      }
 
      // required to catch
      catch(RemoteException e) {
         e.printStackTrace();
      }
      catch(Exception e) {
         e.printStackTrace();
      } 
   }
}
 
class FileServiceFactory
{
   public static IFileService getFileService() throws Exception {
      return (IFileService) Naming.lookup(IFileService.class.getName());
   }
}

c:rmifileserviceFileServiceClient.java:

package fileservice;
  
import java.util.*;
import java.rmi.*;
  
public class FileServiceClient
{
   public static void main(String []args) {
      if (System.getSecurityManager() == null) {
         System.setSecurityManager(new RMISecurityManager());
      }
        
      try {
         IFileService fs = FileServiceFactory.getFileService();
 
         List list = fs.listFiles(".");
         for (int i=0; i<list.size(); i++) {
            System.out.println(list.get(i));
         }
      }
 
      // not required to catch (RuntimeExceptions) but we'll do
      // got give hints in case something goes wrong
      catch(java.security.AccessControlException e) {
         e.printStackTrace();
         System.out.println("nHint: did you specify -Djava.security.policy=...policy?");
      }
 
      // required to catch
      catch(RemoteException e) {
         e.printStackTrace();
      }
      catch(Exception e) {
         e.printStackTrace();
      } 
   }
}
 
class FileServiceFactory
{
   public static IFileService getFileService() throws Exception {
      return (IFileService) Naming.lookup(IFileService.class.getName());
   }
} 

c:rmifileservicepolicy.txt:

grant {
   permission java.security.AllPermission;
};

- Compile all classes:

   c:rmi> javac fileservice*.java

- Generate the stubs with rmic:

   c:rmi> rmic fileservice.FileService

- Run rmiregistry:

   c:rmi> start rmiregistry

- Start the server:

   C:rmi> java -Djava.security.policy=c:rmifileservicepolicy.txt  
             fileservice.FileService

- Start the client:

C:rmi>java -Djava.security.policy=c:rmifileservicepolicy.txt
             fileservice.FileServiceClient

For more information on the internals of RMI, check the Trail: RMI in Sun’s Java Tutorial.

Using cryptography in Java

To use cryptography in Java, you will need to download the Java Cryptography
Extension (JCE) API and the reference implementation by Sun (only available for
US and Canada due to export restrictions) or another implementation by a
so-called cryptography service provider.

Steps in installing/configuring the JCE1.2:

  1. For US/CAN users: download JCE 1.2 from java.sun.com
  2. Unzip the file (eg. to c:java) and add jce1_2-do.jar to your classpath:
    set classpath=%classpath%;c:javajce1.2libjce1_2-do.jar
  3. Register the SunJCE provider:
    Statically: edit the security properties file, located in libsecurityjava.security
    and add the following line to it:
    security.provider.n=com.sun.crypto.provider.SunJCE
    where n is the preference order (you could have other providers!)
    Dynamically: you can also add the provider at runtime:
     
            Security.addProvider(new com.sun.crypto.provider.SunJCE());
         

    Make sure jce1_2-do.jar is added to your classpath, in order for this to compile.

Steps in installing/configuring another service provider, eg. Cryptix:

  1. Cryptix is available from servers located around the world: download Cryptix_bin_3-1-1.zip (or a newer version) from www.cryptix.org
  2. Unzip the file (eg. to c:javacryptix) and add the installed jar files (in C:javacryptixclasses) to your classpath: set classpath=%classpath%;c:javacryptixclassesSPT_0-1-1.jar; …
  3. Register the Cryptix provider:
    Statically: edit the security properties file, located in libsecurityjava.security
    and add the following line to it:
    security.provider.n=cryptix.provider.Cryptix
    where n is the preference order (you could have other providers!)
    Cryptix provides a program that does this for you. Assuming you have changed your classpath, you can invoke
    the following installation script:
     
            java cryptix.provider.Install
         

    Dynamically: you can also add the provider at runtime:

     
            Security.addProvider(new cryptix.provider.Cryptix());
         

Cipher modes for symmetric encryption

  • Electronic Code Book Mode (ECB) (http://www.rsasecurity.com/rsalabs/faq/2-1-4-2.html)
    This mode encrypts all plaintext blocks independently. This means that two identical plaintext blocks are encrypted the same way. It’s a very fast mode (encryption can be done in parallel) but it is not as secure because certain patterns can be discovered in the resulting encrypted text. For example, I encrypted the message “aaaaaaaaeeeeeeeeaaaaaaaaaaaaaaaa” with DES/ECB. This is the encrypted text in an array of byte values:
    -74 -36 103 -124 95 62 54 -117
    70 -70 -61 -9 17 95 54 -114
    -74 -36 103 -124 95 62 54 -117
    -74 -36 103 -124 95 62 54 -117
    -88 109 -8 8 -14 -108 19 122 
  • Cipher Block Chaining Mode (CBC) ( http://www.rsasecurity.com/rsalabs/faq/2-1-4-3.html)
    This mode solves the problem of ECB by XOR’ring the result of the encryption of the previous block with the next block before encrypting the next block. It’s slower as it cannot be done in parallel. The method also uses an initialization vector (IV) as a seed. The first plaintext block is XOR’red with that seed. This ensures that two identical plaintext messages are not encrypted identically.
  • Cipher Feedback Mode (CFB) (http://www.rsasecurity.com/rsalabs/faq/2-1-4-4.html)
    This mode is similar to CBC except that it allows for processing smaller increments of plaintext instead of an entire block. It uses a “register” that has the size of a block and initally contains the seed (initialization vector). Everytime x number of bits are to be encrypted, they are XOR’red with the leftmost x bits in the register. The register is shifted left by x bits and the encrypted bits are appended to it. Since you can encrypt bytes at a time, it is useful for transmission of small chunks of data, eg. chat. But incorrectly transmitting one bit would result in a propagation of the error.
  • Output Feedback Mode (OFB) ( http://www.rsasecurity.com/rsalabs/faq/2-1-4-5.html )
    This mode is similar to CFB except that bit errors that occur during transmission are not propagated to affect the decryption of subsequent blocks.

Encrypting/decrypting a message using a hybrid encryption method

The following code demonstrates using a hybrid encryption method to send a message from a producer to a consumer. This example uses RSA for asymmetric encryption and AES (Rijndael) for symmetric encryption.

The process on the producer side is as follows:

  1. Generate a random symmetric key that will be used
    for this message only.

  2. Encrypt the message to be sent using the symmetric algorithm
    and the random key.

  3. Encrypt the random key using the asymmetric algorithm and
    the consumer’s public key.

  4. Send both the encrypted key and the encrypted message to
    the consumer.

At this point the producer can erase the random symmetric key; it will never be needed again. The ability to utilize a session-only secret key is an important advantage of this technique.

The consumer first decrypts the asymmetric key using his/her private key,
and then uses that key to decrypt the message itself.

HybridTest.java:

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.* ;
  
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.* ;
 
public class HybridTest {
 
    // asymmetric algorithms used
    public static String asymKeyAlgorithm = "RSA" ;
    public static String asymAlgorithm = "RSA/OAEP" ;
    public static int asymKeyAlgorithmStrength = 1024 ;
    public static String signatureAlgorithm = "SHA1WithRSAEncryption" ;
 
    // symmetric algorithms used
    public static String symKeyAlgorithm = "RIJNDAEL" ;
    public static String symAlgorithm = "RIJNDAEL" ;
    //public static String symAlgorithm = "BLOWFISH" ;
    //public static String symAlgorithm = "TWOFISH" ;
    public static int symAlgorithmStrength = 256 ;
 
    static public void main(String[] args) {
 
	String testData = "You can't have your kayak and heat it, too." ;
 
	Base64 b64 = new Base64() ;
 
	try {
	    // make sure the BC provider is registered.
	    Security.addProvider(new BouncyCastleProvider());
 
	    SecureRandom sr = new SecureRandom() ;
 
	    System.out.println("Original message byte count: " + testData.getBytes().length) ;
 
    /***
     * Generate consumer keys for test purposes.  In Real Life(TM) the
     * producer would need to know only the consumer's public key.
     ***/
	    KeyPairGenerator gen = KeyPairGenerator.getInstance(asymKeyAlgorithm, "BC");
	    gen.initialize(asymKeyAlgorithmStrength, sr);

	    System.out.println("Generating key . . .") ;
	    KeyPair consumerPair = gen.generateKeyPair();
 
    /***
     * on the producer side:
     * 1. Generate a secret key.
     * 2. Use asymmetric algorithm to encrypt the secret key for consumer
     * 3. Use symmetric algorithm to encrypt message using the secret key
     ***/
	    // generate a random secret key
	    KeyGenerator kg = KeyGenerator.getInstance(symKeyAlgorithm) ;
	    kg.init(symAlgorithmStrength, sr) ;
	    SecretKey cipherKey = kg.generateKey() ;
	    System.out.println("Generated cipher key, proceeding: " + cipherKey.getAlgorithm()) ;
  
	    // encrypt the secret key using the consumer's public key
	    byte[] encryptedSecretKey = encrypt(cipherKey.getEncoded(), consumerPair.getPublic()) ;
  
	    // encrypt the testData using the secret key
	    byte[] encryptedData = encrypt(testData.getBytes(), cipherKey) ;
 	    
	    System.out.println("Encrypted byte count: " + encryptedData.length) ;
	    System.out.println("Encrypted message: [" + new String(b64.encode(encryptedData)) + "]") ;
 
    /***
     * uncomment to befoul the encrypted data for testing purposes
     ***/
	    //encryptedData[8] = 0 ;
 	    
    /***
     * and now on the consumer side:
     * 1. Use asymmetric algorithm and consumer's private key to decrypt the secret key
     * 2. Use symmetric algorithm and secret key to decrypt message.
     ***/
	    // first get the secret key back with the consumer's private key
	    byte[] encodedSecretKey = decrypt(encryptedSecretKey, consumerPair.getPrivate()) ;
	    SecretKey sKey = new SecretKeySpec(encodedSecretKey, symAlgorithm) ;
	    System.out.println("Secret key decoded.") ;
 
	    // decrypt the message using the secret key
	    byte[] clearData = decrypt(encryptedData, sKey) ;
	    System.out.println("Data decoded, byte count: " + clearData.length) ;
	    System.out.println("Decrypted message: [" + new String(clearData) + "]") ;
	    }
	catch ( Exception ex ) {
	    ex.printStackTrace() ;
	    }
 	    
	System.exit(0);
	}
 
    public static byte[] encrypt(byte[] toEncrypt, SecretKey key)
				    throws GeneralSecurityException {
 
	Cipher cipher = Cipher.getInstance(symAlgorithm) ;
	System.out.println("got cipher, blocksize = " + cipher.getBlockSize()) ;
	cipher.init(Cipher.ENCRYPT_MODE, key) ;
 
	byte[] result = cipher.doFinal(toEncrypt) ;
	return result ;
	}
 
    public static byte[] encrypt(byte[] toEncrypt, PublicKey key)
				    throws GeneralSecurityException {

	Cipher cipher = Cipher.getInstance(asymAlgorithm) ;
	cipher.init(Cipher.ENCRYPT_MODE, key) ;
 
	byte[] result = cipher.doFinal(toEncrypt) ;
	return result ;
	}
 
    public static byte[] decrypt(byte[] toDecrypt, SecretKey key)
				    throws GeneralSecurityException {
 
	Cipher deCipher = Cipher.getInstance(symAlgorithm) ;
	deCipher.init(Cipher.DECRYPT_MODE, key) ;
 
	byte[] result = deCipher.doFinal(toDecrypt) ;
	return result ;
	}
 
    public static byte[] decrypt(byte[] toDecrypt, PrivateKey key)
				    throws GeneralSecurityException {
 
	Cipher deCipher = Cipher.getInstance(asymAlgorithm) ;
	deCipher.init(Cipher.DECRYPT_MODE, key) ;
 
	byte[] result = deCipher.doFinal(toDecrypt) ;
	return result ;
	}
    }

(tested with the BouncyCastle JCE provider, http://www.bouncycastle.org)

Parsing all the numbers from a textfile

Here are three examples of how to remove digits from a String.

  • RemoveDigits. Removes the digits using the StringTokenizer class. This will work for all versions of Java.

  • FilterDigitsReader. Removes the digits as the stream is read. This filters a Reader‘s stream. This will work for Java 1.1 and beyond.
  • RemoveDigitsRegex. Removes the digits using the java.util.regex.Pattern and java.util.regex.Matcher classes. This will work for versions of Java 1.4 and beyond.

    Each class has its own main() which takes in two files:

    1. The first file in the file to read and “filter”

  • The second file in the output file (will be overwritten)

    RemoveDigits.java:

    //
    // RemoveDigits
    //
    import java.util.StringTokenizer;
     
    /**
     *  This implementation is very inefficient. It copies an entire file into a
     *  single String using BufferedReader (BR) .readLine(). The newlines are
     *  appended, since they are "eaten" by the BR. The method <tt>removeNumbers
     *  </tt> is with a String and StringTokenizer is used to remove each number.
     */
    public class RemoveDigits {
       public static void main(String[] args) {
          if (args.length != 2) {
             System.out.println();
             System.out.println("Usage: java RemoveDigits infile-name outfile-name");
             System.out.println("outfile will be overwritten");
             System.out.println();
             System.exit(-1);
          }
     
          String infileName = args[0];
          String outfileName = args[1];
     
          try {
             java.io.File infile = new java.io.File(infileName);
     
             if (infile.exists() == false) {
                System.out.println();
                System.out.println("input file does not exist");
                System.out.println();
                System.exit(-1);
             }
     
             java.io.File outfile = new java.io.File(outfileName);
     
             java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(infile));
     
             StringBuffer buf = new StringBuffer();
             String line;
             while ((line = br.readLine()) != null) {
                buf.append(line);
                buf.append('n');
                // br.readLine() removes the newlines
             }
             br.close();
     
             String cleaned = new RemoveDigits().clean(buf.toString());
             java.io.BufferedWriter bw = new java.io.BufferedWriter(new java.io.FileWriter(outfile));
             bw.write(cleaned);
             bw.close();
          } catch (java.io.IOException ex) {
          }
       }
       // main
     
       public RemoveDigits() { }
     
       public String clean(String s) {
     
          StringBuffer buf = new StringBuffer(s.length());
     
          StringTokenizer st = new StringTokenizer(s, "0123456789");
          while (st.hasMoreTokens()) {
             buf.append(st.nextToken());
          }
     
          return buf.toString();
       }
    }
    // RemoveDigits
    

    FilterDigitsReader.java:

    //
    // FilterDigitsReader
    //
    import java.io.Reader;
    import java.io.FilterReader;
    import java.io.IOException;
     
    /**
     *  Class for filtering all digits from character streams.
     */
    public class FilterDigitsReader extends FilterReader {
     
       public static void main(String[] args) {
          if (args.length != 2) {
             System.out.println();
             System.out.println("Usage: java FilterDigitsReader infile-name outfile-name");
             System.out.println("outfile will be overwritten");
             System.out.println();
             System.exit(-1);
          }
     
          String infileName = args[0];
          String outfileName = args[1];
     
          try {
             java.io.File infile = new java.io.File(infileName);
     
             if (infile.exists() == false) {
                System.out.println();
                System.out.println("input file does not exist");
                System.out.println();
                System.exit(-1);
             }
     
             java.io.File outfile = new java.io.File(outfileName);
     
             java.io.BufferedReader br = new java.io.BufferedReader(new FilterDigitsReader(
                                           new java.io.FileReader(infile)));
     
             StringBuffer buf = new StringBuffer();
             String line;
             while ((line = br.readLine()) != null) {
                buf.append(line);
                buf.append('n');
                // br.readLine() removes the newline
             }
             br.close();
     
             // at this point...buf should be filtered...
     
             java.io.BufferedWriter bw = new java.io.BufferedWriter(new java.io.FileWriter(outfile));
             bw.write(buf.toString());
             bw.close();
          } catch (IOException ex) {
          }
       }
       // main
     
       /**
        *  Create a new filtered reader.
        *
        *@param  in  a Reader object providing the underlying stream.
        */
       public FilterDigitsReader(Reader in) {
          super(in);
       }
     
       /**
        *  Read a single character.
        *
        *@return                  Description of the Return Value
        *@exception  IOException  If an I/O error occurs
        */
       public int read() throws IOException {
          int ch = -1;
          do {
             ch = super.read();
          } while (ch != -1 && Character.isDigit((char) ch));
          return ch;
       }
     
       /**
        *  Read characters into a portion of an array.
        *
        *@param  cbuf             Description of the Parameter
        *@param  off              Description of the Parameter
        *@param  len              Description of the Parameter
        *@return                  Description of the Return Value
        *@exception  IOException  If an I/O error occurs
        */
       public int read(char cbuf[], int off, int len) throws IOException {
          //
          // this might not be the most efficient implementation...
          //
     
          // get a single character...if not a digit...add to cbuf (at appr. index)
     
          // will read up to 'len' characters
          int charactersReadCount = 0;
          Read_Loop :
          for (int cbufIdx = 0; cbufIdx < len; cbufIdx++) {
             int ch = read();
             if (ch == -1) {
                // done!
                break Read_Loop;
             } else {
                cbuf[cbufIdx + off] = (char) ch;
                charactersReadCount++;
             }
          }
          return (charactersReadCount == 0 ? -1 : charactersReadCount);
       }
    }
    // FilterDigitsReader
    

    RemoveDigitsRegex.java:

    
    //
    // RemoveDigitsRegex
    //
    import java.util.StringTokenizer;
     
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
     
    /**
     *  Remove the digits using the new 1.4 regular expression package.
     */
    public class RemoveDigitsRegex {
       public static void main(String[] args) {
          if (args.length != 2) {
             System.out.println();
             System.out.println("Usage: java RemoveDigitsRegex infile-name outfile-name");
             System.out.println("outfile will be overwritten");
             System.out.println();
             System.exit(-1);
          }
     
          String infileName = args[0];
          String outfileName = args[1];
     
          try {
             java.io.File infile = new java.io.File(infileName);
     
             if (infile.exists() == false) {
                System.out.println();
                System.out.println("input file does not exist");
                System.out.println();
                System.exit(-1);
             }
     
             java.io.File outfile = new java.io.File(outfileName);
     
             java.io.BufferedReader br = new java.io.BufferedReader(new java.io.FileReader(infile));
     
             StringBuffer buf = new StringBuffer();
             String line;
             while ((line = br.readLine()) != null) {
                buf.append(line);
                buf.append('n');
                // br.readLine() removes the newlines
             }
             br.close();
     
             String cleaned = new RemoveDigits().clean(buf.toString());
             java.io.BufferedWriter bw = new java.io.BufferedWriter(new java.io.FileWriter(outfile));
             bw.write(cleaned);
             bw.close();
          } catch (java.io.IOException ex) {
          }
       }
       // main
     
       public RemoveDigitsRegex() { }
     
       public String clean(String s) {
          Pattern pattern = Pattern.compile("\d");
          Matcher matcher = pattern.matcher(s);
          return matcher.replaceAll("");
       }
    }
    // RemoveDigitsRegex
    

  • Getting the current time in Java

    A number of ways:

    Main.java:

    import java.util.*;
     
    public class Main
    {
       public static void main(String []args) {
          Calendar cal = Calendar.getInstance();
          cal.setTime(new Date());
          int hour    = cal.get(Calendar.HOUR); 
          int minutes = cal.get(Calendar.MINUTE);
          int seconds = cal.get(Calendar.SECOND);
          System.out.println("Currently, it's " + hour + ":" + minutes + ":" + seconds);
       }
    }
    

    Main.java:

    import java.util.*;
    import java.text.*;
     
    public class Main
    {
       public static void main(String []args) {
          SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
          String currentTime = formatter.format(new Date());
          System.out.println("Currently, it's " + currentTime);
       }
    }
    

    Getting the country of the current locale in Java

    Main.java:

    import java.util.*;
     
    public class Main {
       public static void main(String []args) {
          // for default locale 
          Locale locale = Locale.getDefault();
          System.out.println(locale);  
          System.out.println("Country          " + locale.getCountry());
          System.out.println("Country          " + locale.getDisplayCountry());
     
          // for specific locale
          locale = new Locale("nl", "BE");
          System.out.println(locale);  
          System.out.println("Country          " + locale.getCountry());
          System.out.println("Country          " + locale.getDisplayCountry());
       }
    }
    

    outputs:

    en_US
    Country          US
    Country          United States
    nl_BE
    Country          BE
    Country          Belgium
    

    Exporting/importing Java preferences data to/from XML

    You can export the whole preferences tree or just a node. Use exportSubtree (or exportNode to export a node without its descendants) and importPreferences.

    ExportPrefs.java:

    import java.util.prefs.*;
    import java.io.*; 
     
    public class ExportPrefs
    {
       public static final String APPLICATIONPATH = "applicationpath";
       public static final String USERFONT        = "userfont";
       public static final String LASTUSERLOGIN   = "lastuserlogin";
       public static final String LDAPURL         = "ldapurl";
      
       public void go() throws BackingStoreException {
          try {
             Preferences preferences = Preferences.userNodeForPackage(this.getClass());
     
             preferences.put(APPLICATIONPATH, "c:\application");
             preferences.put(USERFONT,        "Courier New");
             preferences.put(LASTUSERLOGIN,   "Joris Van den Bogaert");
             preferences.put(LDAPURL,         "ldap://127.0.0.1:389/");
             preferences.flush();
     
             preferences.exportSubtree(new BufferedOutputStream(
                                       new FileOutputStream("preferences.xml")));
          }
          catch(BackingStoreException e) {
             e.printStackTrace();
          }
          catch(IOException e) {
             e.printStackTrace();
          }
       }
     
       public static void main(String []args) throws Exception {
          ExportPrefs exportPrefs = new ExportPrefs();
          exportPrefs.go();
       }
    }
    

    Creates the file preferences.xml:

    < ?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
    
    <preferences EXTERNAL_XML_VERSION="1.0">
      <root type="user">
        <map />
        <node name="&lt;unnamed&gt;">
          <map>
            <entry key="applicationpath" value="c:application" />
            <entry key="userfont" value="Courier New" />
            <entry key="lastuserlogin" value="Joris Van den Bogaert" />
            <entry key="ldapurl" value="ldap://127.0.0.1:389/" />
          </map>
        </node>
      </root>
    </preferences>
    

    (the DTD for this XML can be found in the Preferences JavaDoc)

    You can import it back.

    ImportPrefs.java:

    import java.util.prefs.*;
    import java.io.*; 
     
    public class ImportPrefs
    {
       public void go() throws BackingStoreException {
          try {
             Preferences preferences = Preferences.userNodeForPackage(this.getClass());
        
             InputStream is = new BufferedInputStream(new FileInputStream("preferences.xml"));
             preferences.importPreferences(is);
             is.close();
             preferences.flush();
          }
          catch(BackingStoreException e) {
             e.printStackTrace();
          }
          catch(InvalidPreferencesFormatException e) {
             e.printStackTrace();
          }
          catch(IOException e) {
             e.printStackTrace();
          }
       }
     
       public static void main(String []args) throws Exception {
          ImportPrefs importPrefs = new ImportPrefs();
          importPrefs.go();
       }
    }
    

    Locating ResourceBundles

    Suppose we have a .properties file called LabelsBundle_nl_BE.properties and assume also our default locale is en_US. To get access to that bundle, you can invoke ResourceBundle.getBundle(“LabelsBundle”, “nl”, “BE”). Notice that a resource bundle consists of two parts: a family name and a locale part. The locale part contains a language code, a country code and an optional variant code. In our example, it will try to locate the bundle in the following way:

    	class LabelsBundle_nl_BE			NOTFOUND
    	file LabelsBundle_nl_BE.properties		OK
    	class LabelsBundle_nl				NOTFOUND
    	file LabelsBundle_nl.properties		NOTFOUND
    	class LabelsBundle				NOTFOUND
    	file LabelsBundle.properties			NOTFOUND
    

    Notice that once the .propreties file has been located, it will still continue to look for parent resourcebundles by shortening the locale part delimited by an underscore.

    Now assume we only have a .properties file called LabelsBundle_en and we invoke ResourceBundle.getBundle(“LabelsBundle”, “nl”, “BE”). Notice here that it will start from our desired locale and build its way up the tree, including searching for a match with the default locale.

    	class LabelsBundle_nl_BE			NOTFOUND
    	file LabelsBundle_nl_BE.properties		NOTFOUND
    	class LabelsBundle_nl				NOTFOUND
    	file LabelsBundle_nl.properties		NOTFOUND
    	class LabelsBundle_en_US			NOTFOUND
    	file LabelsBundle_en_US.properties		NOTFOUND
    	class LabelsBundle_en				NOTFOUND
    	file LabelsBundle_en.propertes		OK
    	class LabelsBundle				NOTFOUND
    	file LabelsBundle.properties			NOTFOUND
    

    Assume we have a .properties file called LabelsBundle_nl_BE.properties and a .properties file called LabelsBundle.properties.

    	class LabelsBundle_nl_BE			NOTFOUND
    	file LabelsBundle_nl_BE.properties		OK
    	class LabelsBundle_nl				NOTFOUND
    	file LabelsBundle_nl.properties		NOTFOUND
    	class LabelsBundle				NOTFOUND
    	file LabelsBundle.properties			OK
    

    In this example, LabelsBundle.properties has become a parent resource bundle of LabelsBundle_nl_BE. You can use the property keys from both these files through the instance that you get back from invoking ResourceBundle.getBundle(…). Also notice that if the resource bundle has been found using the desired locale, the default locale will not be used in looking for a parent. The default locale is only used if locating a bundle with the desired locale failed.

    As a last note, you must specify the fully qualified name for the family name (or baseclass) when requesting a resource bundle object. For example, if LabelsBundle_nl_BE.properties is in the package mypackage, you will have to say:

    	ResourceBundle.getBundle("mypackage.LabelsBundle", "nl", "BE");