Encrypting/decrypting with Triple-DES

Triple-DES or DESede is an improvement over DES (Data Encryption Standard). It uses three DES keys k1, k2 and k3. A message is encrypted with k1 first, then decrypted with k2 and encrypted again with k3 (DESencryptiondecryptionencryption). This increases security as the key length effectively increases from 56 to 112 or 168 (two or three keys may be used in DESede). As a programmer you don’t have to worry about managing several keys, they are all encoded into one key.

The DESede key size is 128 or 192 bit and block size 64 bit.

Eventually, DES and Triple-DES will be replaced by the Advanced Encryption Standard (AES).

Main.java:

import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
 
public class Main
{
   public static void main(String []args) throws Exception {
      String toEncrypt = "The shorter you live, the longer you're dead!";
 
      System.out.println("Encrypting...");
      byte[] encrypted = encrypt(toEncrypt, "password");
 
      System.out.println("Decrypting...");
      String decrypted = decrypt(encrypted, "password");
    
      System.out.println("Decrypted text: " + decrypted);
   } 
 
   public static byte[] encrypt(String toEncrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance("DESede");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // create an instance of cipher
      Cipher cipher = Cipher.getInstance("DESede");
 
      // initialize the cipher with the key 
      cipher.init(Cipher.ENCRYPT_MODE, sk);
 
      // enctypt!
      byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
 
      return encrypted;
   }
 
   public static String decrypt(byte[] toDecrypt, String key) throws Exception {
      // create a binary key from the argument key (seed)
      SecureRandom sr = new SecureRandom(key.getBytes());
      KeyGenerator kg = KeyGenerator.getInstance("DESede");
      kg.init(sr);
      SecretKey sk = kg.generateKey();
 
      // do the decryption with that key
      Cipher cipher = Cipher.getInstance("DESede");
      cipher.init(Cipher.DECRYPT_MODE, sk);
      byte[] decrypted = cipher.doFinal(toDecrypt);
 
      return new String(decrypted);
   }
}

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

Writing a client/server app that makes use of SSL

To create a client and a server that exchange encrypted messages, you can use the JSSE package that can be downloaded as an optional package or comes standard with JDK1.4. I’ll assume your have correctly downloaded and installed the package or are using JDK1.4.

SSL stands for Secure Socket Layer. It contains a handshake protocol where two parties exchange a series of messages to agree on a symmetric key that will be used to encrypt the rest of the messages that are exchanged throughout the session. The problem is how to let the other party know what key to use. There can always be someone spying on the messages that are sent over the network.

The solution is to use public/private key cryptography. A message encrypted with a private key can be decrypted with the associated public key and vice versa. Only one party holds his own private key and can distribute his public key to anyone, even the spy. The other party encrypts the message with the public key and sends it to the other party, which is the only one that can decrypt the message as he, and only he, holds the private key.

Party A could encrypt the symmetric key information using the public key of party B and sends him this info. Party B decrypts it and obtaines that symmetric key which they both will use during the session.

To ensure that the public key of the Party B actually belongs to him, and is not something made up of a spy claiming he is party B, he can use a public-key certificate. A public-key certificate is issued by a certification authority (CA) which you typically have to pay a couple hundred dollars and provide proof of identity in order to obtain it.

In short, the whole process goes like this.
Assume Party B is the server and party A the client.

  1. Party A and Party B agree on an SSL version and a set of encryption algorithms.
  2. Party B sends Party B the public key/certificate.
  3. Party B may also request Party A to send his public key/certificate if he wants
    to authenticate the client (eg. in banking applications).

  • Party A generates information to create a symmetric key and sends it to Party B,
    but encrypted with the public key of Party B.
  • Party A may also send Party B his public key information if Party B requested for it.
  • Now both parties have received the symmetric key and can start exchanging actual data.

    One more thing: even though messages are send encrypted, a spy may still tamper with the data that flows between A and B. To ensure data integrity, messages are appended with an HMAC before being encrypted. The result of an HMAC (Message Authentication Code) is a small series of bytes that can be used to detect the slightest change in data, even if it’s only one bit. The whole shebang (message + HMAC) are encrypted with the secret symmetric key and is send over. The receiver then decrypts the message, calculates the HMAC again, and compares it with the one that was send to him.

    Writing the server

    Instead of creating a ServerSocket using ServerSocket ss = new ServerSocket(port), we would use the SSLServerSocketFactory that creates a ServerSocket that supports SSL. This SSL ServerSocket takes care of all the gory details

    For more information, check out the excellent JSSE Sun’s User’s Guide here.

    Start of by creating a self-signed certificate that is needed by the server to send back
    to the client during the SSL handshake.

    C:securityssl>keytool -v -genkey -keyalg RSA -keystore .keystore
    Enter keystore password:  esuspass
    What is your first and last name?
      [Unknown]:  Joris Van den Bogaert
    What is the name of your organizational unit?
      [Unknown]:  Esus Team
    What is the name of your organization?
      [Unknown]:  Esus, Inc
    What is the name of your City or Locality?
      [Unknown]:  Meerbeek
    What is the name of your State or Province?
      [Unknown]:
    What is the two-letter country code for this unit?
      [Unknown]:  BE
    Is <CN=Joris Van den Bogaert, OU=Esus Team, O="Esus, Inc", L=Meerbeek, ST=Unkno
    n, C=BE> correct?
      [no]:  yes
    
    Generating 1024 bit RSA key pair and self-signed certificate (MD5WithRSA)
            for: CN=Joris Van den Bogaert, OU=Esus Team, O="Esus, Inc", L=Meerbeek,
    ST=Unknown, C=BE
    Enter key password for <mykey>
            (RETURN if same as keystore password):
    [Saving .keystore]
    
    C:securityssl>dir .keystore
    
     Volume in drive C has no label
     Volume Serial Number is 1380-0FE3
     Directory of C:securityssl
    
    KEYSTO~1             1,379  07-24-01  3:53p .keystore
             1 file(s)          1,379 bytes
             0 dir(s)     146,989,056 bytes free
    

    Here’s the code for SecureServer.java and SecureClient.java:

    SecureServer.java:

    import javax.net.ssl.*;
    import java.net.*;
    import java.io.*;
     
    public class SecureServer {
       private static final int port = 4321;
     
       public static void main(String []args) throws Exception {
          SSLServerSocketFactory ssf = (SSLServerSocketFactory)
                                          SSLServerSocketFactory.getDefault();
          ServerSocket ss = ssf.createServerSocket(port);
     
          System.out.println("Ready to accept messages!");
          Socket s = ss.accept();
     
          System.out.println("A client has connected!");
          DataInputStream dis = new DataInputStream(s.getInputStream());
          DataOutputStream dos = new DataOutputStream(s.getOutputStream());
          String line = null;
          try {
             while (true) {
                line = dis.readUTF();
                System.out.println("Client sent: " + line);
                dos.writeUTF("You send: " + line);
             } 
          }
          finally {
             dis.close();
             dos.close();
             s.close();
          }
       }
    }

    SecureClient.java:

    import javax.net.ssl.*;
    import java.net.*;
    import java.io.*;
     
    public class SecureClient 
    {
       private static final String host = "127.0.0.1";
       private static int port = 4321;
     
       public static void main(String []args) throws Exception {
          SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
          Socket s = sf.createSocket(host, port); 
     
          DataInputStream dis = new DataInputStream(s.getInputStream());
          DataOutputStream dos = new DataOutputStream(s.getOutputStream());
     
          System.out.println("Connected.n");
          System.out.println("Type messages to send to server, exit to end!");
    
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
          String line;
          while ((line = br.readLine()) != null) {
             if (line.equals("exit")) break;
     
             dos.writeUTF(line);
             dos.flush();
     
             String reply = dis.readUTF();
             System.out.println("Server reply: " + reply);
          }
     
          dis.close();
          dos.close(); 
          s.close();
       }
    }
    

    Note: change the IP address (127.0.0.1) in SecureClient.java to the IP address where your server is deployed. To test it, we’ll run it all on the same machine.

    The file .keystore containing the self-signed certificate should be located on the server’s machine. Put both the files SecureServer.class and .keystore in the directory c:\security\ssl\server and SecureClient.class in c:\securitysslclient.
    The server should know where it can find its private key. The keystore can be specified at runtime along with the password in order to access it.
    The client needs to have access to the certificate in order to check it. Certain certificates, issued by a Certificate Authority (CA) are automatically trusted (they are saved in the file /lib/security/cacerts. You can export the certificate from the server’s .keystore into a file and specify its location at the command line when running the client (trustStore). If your key is signed by a CA, then you don’t need to specify it at command line as it is contained in the file /lib/security/cacerts. This is the order in which trustStores are checked:

       1) a trustStore specified in the javax.net.ssl.trustStore property
       2) <i><JRE_HOME>/lib/security/jssecacerts</i>
       3) <i><JRE_HOME>/lib/security/cacerst</i>
    

    I’ll show you how to run the example by specifying the trustStore at command line, and by adding the certificate to the cacerts file.

    First we need to export the certificate:

    C:\security\ssl\server> keytool -export -keystore .keystore -file ssltest.cer
    Enter keystore password:  esuspass
    Certificate stored in file <ssltest.cer>
    

    Running SecureServer and SecureClient by specifying the trustStore

    On the client side, create a truststore .trustStore and import certificate contained in the file ssltest.cer:

    C:\security\ssl\client>copy ..\server ssltest.cer
            1 file(s) copied
    
    C:\security\ssl\client>keytool -import -keystore .trustStore -file ssltest.cer
    Enter keystore password:  esuspass
    Owner: CN=Joris Van den Bogaert, OU=Esus Team, O="Esus, Inc", L=Meerbeek, ST=Unk
    nown, C=BE
    Issuer: CN=Joris Van den Bogaert, OU=Esus Team, O="Esus, Inc", L=Meerbeek, ST=Un
    known, C=BE
    Serial number: 3b5d7dd7
    Valid from: Tue Jul 24 15:53:27 CEST 2001 until: Mon Oct 22 15:53:27 CEST 2001
    Certificate fingerprints:
             MD5:  07:DE:52:94:15:1D:53:88:C5:C5:51:48:0F:AF:83:76
             SHA1: A7:92:CF:29:EF:B9:74:05:6F:05:E5:75:4B:78:42:D1:35:8B:D7:55
    Trust this certificate? [no]:  yes
    Certificate was added to keystore
    

    Open another terminal to start running the server:

    C:\security\ssl\server> c:\jdk1.4\bin\java -Djavax.net.ssl.keyStore=.keystore -Dj
    avax.net.ssl.keyStorePassword=esuspass SecureServer
    

    Now wait a couple seconds until the server shows up Ready to accept messages!.

    Run the client by specifying the trustStore:

    C:\security\ssl\client>c:\jdk1.4\bin\java -Djavax.net.ssl.trustStore=.trustStore SecureClient
    

    This is the result at the server’s side:

    C:\security\ssl\server> c:\jdk1.4\bin\java -Djavax.net.ssl.keyStore=.keystore -Djavax.net.ssl.keyStorePassword=esuspass SecureServer
    Ready to accept messages!
    A client has connected!
    Client sent: whoever spies on this connection
    Client sent: can't see crap
    Client sent: or should i say... only crap
    EOF!

    and the result at the client’s side:

    C:\security\ssl\client> c:\jdk1.4\bin\java -Djavax.net.ssl.trustStore=.trustStore SecureClient
    Connected.
    
    Type messages to send to server, exit to end!
    whoever spies on this connection
    Server reply: You send: whoever spies on this connection
    can't see crap
    Server reply: You send: can't see crap
    or should i say... only crap
    Server reply: You send: or should i say... only crap
    exit
    

    To include our self-signed certificate in the default cacerts file:

    C:\jdk1.4\jre\lib\security> copy c:\securitysslserver ssltest.cer
            1 file(s) copied
     
    C:\jdk1.4\jre\lib\security> keytool -import -keystore cacerts -file ssltest.cer
    Enter keystore password:  changeit
    Owner: CN=Joris Van den Bogaert, OU=Esus Team, O="Esus, Inc", L=Meerbeek, ST=Unk
    nown, C=BE
    Issuer: CN=Joris Van den Bogaert, OU=Esus Team, O="Esus, Inc", L=Meerbeek, ST=Un
    known, C=BE
    Serial number: 3b5d7dd7
    Valid from: Tue Jul 24 15:53:27 CEST 2001 until: Mon Oct 22 15:53:27 CEST 2001
    Certificate fingerprints:
             MD5:  07:DE:52:94:15:1D:53:88:C5:C5:51:48:0F:AF:83:76
             SHA1: A7:92:CF:29:EF:B9:74:05:6F:05:E5:75:4B:78:42:D1:35:8B:D7:55
    Trust this certificate? [no]:  yes
    

    Run the server again. Now run the client without specifying the trustStore and see what happens!

  • Using a BitSet

    The BitSet allows you to work with bits (0 and 1). You can not only get and set bits individually but also perform bitwise operations like and and or. The size of the BitSet may vary. For example, if you initialy set the first bit to 1, 64 bits will be used. Then if you set the bit 100 to 1, the BitSet will grow to 128. The 64 alignment may be different in future implementations.

    Operations:

    and:   result of (a and b) is 1 if only a and b have the value of 1
    or:    result of (a or b) is 1 if at least a or b has the value of 1
    xor:   result of (a xor b) is 1 if a or b has the value of 1, but not both
    

    Main.java:

    import java.util.*;
     
    public class Main {
       public static void main(String args[]) {
          BitSet bs1 = new BitSet();
     
          bs1.set(7);               // sets the 7th bit   00000001000... (64)
          System.out.println(bs1);  // outputs {7}
          bs1.set(5);	        // sets the 5th bit   00000101000... (64)
          System.out.println(bs1);  // outputs {5, 7}
          bs1.clear(7);             //                    00000100000... (64)
          System.out.println(bs1);  // outputs {5}
          
          BitSet bs2 = new BitSet();
          bs2.set(1);               //                    01000000000... (64)
          bs2.set(5);               //                    01000100000... (64)
     
          bs1.and(bs2);             //                    00000100000... (64)
          System.out.println(bs1);  // outputs {5}
     
          bs1.xor(bs2);             //                    01000000000... (64)
          System.out.println(bs1);  // outputs {1}
     
          bs1.or(bs2);              //                    01000100000... (64)
          System.out.println(bs1);  // outputs {1, 5}
       }
    }
    

    outputs:

    {7}
    {5, 7}
    {5}
    {5}
    {1}
    {1, 5}
    

    Determining the number of days in a month of a particular year

    This small example looks only at the days of february of the last 20 years.

    Main.java:

    import java.util.*;
     
    public class Main
    {
       public static void main(String []args) {
          for (int i=1980; i<2010; i++) {
             Calendar calendar = new GregorianCalendar(i, Calendar.FEBRUARY, 1);
     
             int numberOfDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
     
             System.out.println("February " + i + ": " + numberOfDays + " days");
          }
       }
    } 
    

    outputs:

    February 1980: 29 days
    February 1981: 28 days
    February 1982: 28 days
    February 1983: 28 days
    February 1984: 29 days
    February 1985: 28 days
    February 1986: 28 days
    February 1987: 28 days
    February 1988: 29 days
    February 1989: 28 days
    February 1990: 28 days
    February 1991: 28 days
    February 1992: 29 days
    February 1993: 28 days
    February 1994: 28 days
    February 1995: 28 days
    February 1996: 29 days
    February 1997: 28 days
    February 1998: 28 days
    February 1999: 28 days
    February 2000: 29 days
    February 2001: 28 days
    February 2002: 28 days
    February 2003: 28 days
    February 2004: 29 days
    February 2005: 28 days
    February 2006: 28 days
    February 2007: 28 days
    February 2008: 29 days
    February 2009: 28 days
    

    Getting a list of the available locales

    import java.util.Locale;
     
    public class Main
    {
       public static void main(String[] args) {
          Locale[] locales = Locale.getAvailableLocales();
     
          printInColumn("DisplayName", 20);
          printInColumn("DisplayCountry", 15);
          printInColumn("DispLang", 11);
          printInColumn("ISO3L", 6);
          printInColumn("Lang", 5);
          printInColumn("ISO3C", 6);
          printInColumn("Variant", 6);
          printInColumn("DispVariant", 10);
          System.out.println();
          System.out.println();
     
          for (int i=0; i<locales.length; i++) {
             printInColumn(locales[i].getDisplayName(), 20);
             printInColumn(locales[i].getDisplayCountry(), 15);
             printInColumn(locales[i].getDisplayLanguage(), 11);
             printInColumn(locales[i].getISO3Language(), 6);
             printInColumn(locales[i].getLanguage(), 5);
             printInColumn(locales[i].getISO3Country(), 6);
             printInColumn(locales[i].getVariant(), 6);
             printInColumn(locales[i].getDisplayVariant(), 10);
             System.out.println();
          }
       }
     
       public static void printInColumn(String s, int col) {
          if (s.length() > col-2) s = s.substring(0, col-2);
          System.out.print(s);
          for (int i=s.length(); i<col; ++i)
             System.out.print(" ");
       }
    }
    

    outputs:

    DisplayName         DisplayCountr  DispLang   ISO3  Lan  ISO3  Vari  DispVari  
    
    English                            English    eng   en                         
    English (United St  United States  English    eng   en   USA                   
    Arabic                             Arabic     ara   ar                         
    Arabic (United Ara  United Arab E  Arabic     ara   ar   ARE                   
    Arabic (Bahrain)    Bahrain        Arabic     ara   ar   BHR                   
    Arabic (Algeria)    Algeria        Arabic     ara   ar   DZA                   
    Arabic (Egypt)      Egypt          Arabic     ara   ar   EGY                   
    Arabic (Iraq)       Iraq           Arabic     ara   ar   IRQ                   
    Arabic (Jordan)     Jordan         Arabic     ara   ar   JOR                   
    Arabic (Kuwait)     Kuwait         Arabic     ara   ar   KWT                   
    Arabic (Lebanon)    Lebanon        Arabic     ara   ar   LBN                   
    Arabic (Libya)      Libya          Arabic     ara   ar   LBY                   
    Arabic (Morocco)    Morocco        Arabic     ara   ar   MAR                   
    Arabic (Oman)       Oman           Arabic     ara   ar   OMN                   
    Arabic (Qatar)      Qatar          Arabic     ara   ar   QAT                   
    Arabic (Saudi Arab  Saudi Arabia   Arabic     ara   ar   SAU                   
    Arabic (Sudan)      Sudan          Arabic     ara   ar   SDN                   
    Arabic (Syria)      Syria          Arabic     ara   ar   SYR                   
    Arabic (Tunisia)    Tunisia        Arabic     ara   ar   TUN                   
    Arabic (Yemen)      Yemen          Arabic     ara   ar   YEM                   
    Byelorussian                       Byeloruss  bel   be                         
    Byelorussian (Bela  Belarus        Byeloruss  bel   be   BLR                   
    Bulgarian                          Bulgarian  bul   bg                         
    Bulgarian (Bulgari  Bulgaria       Bulgarian  bul   bg   BGR                   
    Catalan                            Catalan    cat   ca                         
    Catalan (Spain)     Spain          Catalan    cat   ca   ESP                   
    Czech                              Czech      ces   cs                         
    Czech (Czech Repub  Czech Republi  Czech      ces   cs   CZE                   
    Danish                             Danish     dan   da                         
    Danish (Denmark)    Denmark        Danish     dan   da   DNK                   
    German                             German     deu   de                         
    German (Austria)    Austria        German     deu   de   AUT                   
    German (Austria,Eu  Austria        German     deu   de   AUT   EURO  Euro      
    German (Switzerlan  Switzerland    German     deu   de   CHE                   
    German (Germany)    Germany        German     deu   de   DEU                   
    German (Germany,Eu  Germany        German     deu   de   DEU   EURO  Euro      
    German (Luxembourg  Luxembourg     German     deu   de   LUX                   
    German (Luxembourg  Luxembourg     German     deu   de   LUX   EURO  Euro      
    Greek                              Greek      ell   el                         
    Greek (Greece)      Greece         Greek      ell   el   GRC                   
    English (Australia  Australia      English    eng   en   AUS                   
    English (Canada)    Canada         English    eng   en   CAN                   
    English (United Ki  United Kingdo  English    eng   en   GBR                   
    English (Ireland)   Ireland        English    eng   en   IRL                   
    English (Ireland,E  Ireland        English    eng   en   IRL   EURO  Euro      
    English (New Zeala  New Zealand    English    eng   en   NZL                   
    English (South Afr  South Africa   English    eng   en   ZAF                   
    Spanish                            Spanish    spa   es                         
    Spanish (Bolivia)   Bolivia        Spanish    spa   es   BOL                   
    Spanish (Argentina  Argentina      Spanish    spa   es   ARG                   
    Spanish (Chile)     Chile          Spanish    spa   es   CHL                   
    Spanish (Colombia)  Colombia       Spanish    spa   es   COL                   
    Spanish (Costa Ric  Costa Rica     Spanish    spa   es   CRI                   
    Spanish (Dominican  Dominican Rep  Spanish    spa   es   DOM                   
    Spanish (Ecuador)   Ecuador        Spanish    spa   es   ECU                   
    Spanish (Spain)     Spain          Spanish    spa   es   ESP                   
    Spanish (Spain,Eur  Spain          Spanish    spa   es   ESP   EURO  Euro      
    Spanish (Guatemala  Guatemala      Spanish    spa   es   GTM                   
    Spanish (Honduras)  Honduras       Spanish    spa   es   HND                   
    Spanish (Mexico)    Mexico         Spanish    spa   es   MEX                   
    Spanish (Nicaragua  Nicaragua      Spanish    spa   es   NIC                   
    Spanish (Panama)    Panama         Spanish    spa   es   PAN                   
    Spanish (Peru)      Peru           Spanish    spa   es   PER                   
    Spanish (Puerto Ri  Puerto Rico    Spanish    spa   es   PRI                   
    Spanish (Paraguay)  Paraguay       Spanish    spa   es   PRY                   
    Spanish (El Salvad  El Salvador    Spanish    spa   es   SLV                   
    Spanish (Uruguay)   Uruguay        Spanish    spa   es   URY                   
    Spanish (Venezuela  Venezuela      Spanish    spa   es   VEN                   
    Estonian                           Estonian   est   et                         
    Estonian (Estonia)  Estonia        Estonian   est   et   EST                   
    Finnish                            Finnish    fin   fi                         
    Finnish (Finland)   Finland        Finnish    fin   fi   FIN                   
    Finnish (Finland,E  Finland        Finnish    fin   fi   FIN   EURO  Euro      
    French                             French     fra   fr                         
    French (Belgium)    Belgium        French     fra   fr   BEL                   
    French (Belgium,Eu  Belgium        French     fra   fr   BEL   EURO  Euro      
    French (Canada)     Canada         French     fra   fr   CAN                   
    French (Switzerlan  Switzerland    French     fra   fr   CHE                   
    French (France)     France         French     fra   fr   FRA                   
    French (France,Eur  France         French     fra   fr   FRA   EURO  Euro      
    French (Luxembourg  Luxembourg     French     fra   fr   LUX                   
    French (Luxembourg  Luxembourg     French     fra   fr   LUX   EURO  Euro      
    Croatian                           Croatian   hrv   hr                         
    Croatian (Croatia)  Croatia        Croatian   hrv   hr   HRV                   
    Hungarian                          Hungarian  hun   hu                         
    Hungarian (Hungary  Hungary        Hungarian  hun   hu   HUN                   
    Icelandic                          Icelandic  isl   is                         
    Icelandic (Iceland  Iceland        Icelandic  isl   is   ISL                   
    Italian                            Italian    ita   it                         
    Italian (Switzerla  Switzerland    Italian    ita   it   CHE                   
    Italian (Italy)     Italy          Italian    ita   it   ITA                   
    Italian (Italy,Eur  Italy          Italian    ita   it   ITA   EURO  Euro      
    Hebrew                             Hebrew     heb   iw                         
    Hebrew (Israel)     Israel         Hebrew     heb   iw   ISR                   
    Japanese                           Japanese   jpn   ja                         
    Japanese (Japan)    Japan          Japanese   jpn   ja   JPN                   
    Korean                             Korean     kor   ko                         
    Korean (South Kore  South Korea    Korean     kor   ko   KOR                   
    Lithuanian                         Lithuania  lit   lt                         
    Lithuanian (Lithua  Lithuania      Lithuania  lit   lt   LTU                   
    Latvian (Lettish)                  Latvian (  lav   lv                         
    Latvian (Lettish)   Latvia         Latvian (  lav   lv   LVA                   
    Macedonian                         Macedonia  mkd   mk                         
    Macedonian (Macedo  Macedonia      Macedonia  mkd   mk   MKD                   
    Dutch                              Dutch      nld   nl                         
    Dutch (Belgium)     Belgium        Dutch      nld   nl   BEL                   
    Dutch (Belgium,Eur  Belgium        Dutch      nld   nl   BEL   EURO  Euro      
    Dutch (Netherlands  Netherlands    Dutch      nld   nl   NLD                   
    Dutch (Netherlands  Netherlands    Dutch      nld   nl   NLD   EURO  Euro      
    Norwegian                          Norwegian  nor   no                         
    Norwegian (Norway)  Norway         Norwegian  nor   no   NOR                   
    Norwegian (Norway,  Norway         Norwegian  nor   no   NOR   NY    Nynorsk   
    Polish                             Polish     pol   pl                         
    Polish (Poland)     Poland         Polish     pol   pl   POL                   
    Portuguese                         Portugues  por   pt                         
    Portuguese (Brazil  Brazil         Portugues  por   pt   BRA                   
    Portuguese (Portug  Portugal       Portugues  por   pt   PRT                   
    Portuguese (Portug  Portugal       Portugues  por   pt   PRT   EURO  Euro      
    Romanian                           Romanian   ron   ro                         
    Romanian (Romania)  Romania        Romanian   ron   ro   ROM                   
    Russian                            Russian    rus   ru                         
    Russian (Russia)    Russia         Russian    rus   ru   RUS                   
    Serbo-Croatian                     Serbo-Cro  srp   sh                         
    Serbo-Croatian (Yu  Yugoslavia     Serbo-Cro  srp   sh   YUG                   
    Slovak                             Slovak     slk   sk                         
    Slovak (Slovakia)   Slovakia       Slovak     slk   sk   SVK                   
    Slovenian                          Slovenian  slv   sl                         
    Slovenian (Sloveni  Slovenia       Slovenian  slv   sl   SVN                   
    Albanian                           Albanian   sqi   sq                         
    Albanian (Albania)  Albania        Albanian   sqi   sq   ALB                   
    Serbian                            Serbian    srp   sr                         
    Swedish                            Swedish    swe   sv                         
    Serbian (Yugoslavi  Yugoslavia     Serbian    srp   sr   YUG                   
    Swedish (Sweden)    Sweden         Swedish    swe   sv   SWE                   
    Thai                               Thai       tha   th                         
    Thai (Thailand)     Thailand       Thai       tha   th   THA                   
    Turkish                            Turkish    tur   tr                         
    Turkish (Turkey)    Turkey         Turkish    tur   tr   TUR                   
    Ukrainian                          Ukrainian  ukr   uk                         
    Ukrainian (Ukraine  Ukraine        Ukrainian  ukr   uk   UKR                   
    Chinese                            Chinese    zho   zh                         
    Chinese (China)     China          Chinese    zho   zh   CHN                   
    Chinese (Hong Kong  Hong Kong      Chinese    zho   zh   HKG                   
    Chinese (Taiwan)    Taiwan         Chinese    zho   zh   TWN                   
    

    Using the Properties class

    The Properties class is able to contain key/value pairs, just like a Hashtable (in fact, Properties extends from Hashtable). An example of where the Properties class is used is in the System class, that uses this class to store its system properties (like java.version, …). Properties allows its key/value pairs to be loaded and stored and through the methods load and store.

    This following example stores the system properties in a file. The store method allows you to save an extra header comment for identification purposes.

    Main.java:

    import java.util.*;
    import java.io.*;
     
    public class Main {   
       public static void main(String[] args) throws Exception {
          if (args.length != 1) {
             System.out.println("Usage: java Main <filename>");
             System.exit(1);
          }
     
          BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(args[0]));
          Properties p = System.getProperties();
          p.store(bos, "Our stored System properties");     
       }
    }
    

    stores in a specified file:

    #Our stored System properties
    #Wed Jun 27 17:21:15 CEST 2001
    java.specification.name=Java Platform API Specification
    awt.toolkit=sun.awt.windows.WToolkit
    java.version=1.2.2
    java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
    user.timezone=Europe/Paris
    java.specification.version=1.2
    java.vm.vendor=Sun Microsystems Inc.
    java.vm.specification.version=1.0
    user.home=C:\WINDOWS
    os.arch=x86
    java.awt.fonts=
    java.vendor.url=http://java.sun.com/
    file.encoding.pkg=sun.io
    user.region=US
    java.home=C:\JDK1.2.2\JRE
    java.class.path=c:\jdk1.2.2\jre\lib\rt.jar;C:\PRO
    GRA~1\JMF2.1\LIB\SOUND.JAR;C:\PROGRA~1\JMF2.1\LIB\
    JMF.JAR;c:\jakarta-log4j-1.0.4\log4j-core.jar;
    line.separator=rn
    java.ext.dirs=C:\JDK1.2.2\JRE\lib\ext
    java.io.tmpdir=c:\windows\TEMP\
    os.name=Windows 95
    java.vendor=Sun Microsystems Inc.
    java.awt.printerjob=sun.awt.windows.WPrinterJob
    java.library.path=C:\JDK1.2.2\BIN;.;C:\WINDOWS\SYSTEM;C:\WINDOWS;C:\JIKES\BIN
    ;C:\ANT\BIN\;C:\JDK1.2.2\BIN;C:\WINDOWS;C:\WIN
    DOWS;C:\WINDOWS\COMMAND;;C:\WN16\BIN;C:\PROGRA~1
    NETWOR~1\PGP;C:\VIM\VIM55
    java.vm.specification.vendor=Sun Microsystems Inc.
    sun.io.unicode.encoding=UnicodeLittle
    file.encoding=Cp1252
    java.specification.vendor=Sun Microsystems Inc.
    user.name=esus
    user.language=en
    java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi
    java.vm.name=Classic VM
    java.vm.specification.name=Java Virtual Machine Specification
    java.class.version=46.0
    sun.boot.library.path=C:\JDK1.2.2\JRE\bin
    os.version=4.10
    java.vm.info=build JDK-1.2.2_005, native threads, symcjit
    java.vm.version=1.2.2
    java.compiler=symcjit
    path.separator=;
    user.dir=C:\
    file.separator=\
    sun.boot.class.path=C:\JDK1.2.2\JRE\lib\rt.jar;C:\
    JDK1.2.2\JRE\lib\i18n.jar;C:\JDK1.2.2\JRE\classes
    

    You can create your own properties object as follows:

    import java.util.*;
    import java.io.*;
     
    public class Main {   
       public static void main(String[] args) throws Exception {
          // creating a properties object
          Properties p = new Properties();
          p.put("lastlogin", "crazycow");
          p.put("lastpassword", "j23js09zz");
          
          // storing our properties in the file test.prop 
          BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.prop"));
          p.store(bos, "Our own properties");     
     
          // loading our properties in another Properties object and 
          // printing its values out.
          Properties p2 = new Properties();
          p2.load(new BufferedInputStream(new FileInputStream("test.prop")));
          p2.list(System.out);
       }
    }

    Notice that Properties extends from Hashtable, so you can put elements in there that are not Strings. In this case, the load and save methods won’t work properly. A better way of implementating Properties is to have it contain a Hashtable instead of extending from it.

    Tokenizing text with a StringTokenizer

    First determine what characters delimit your text tokens, for example if you’re parsing a comma-separated values file (csv), your delimiter character would probably be the comma. Then create an instance of StringTokenizer with the String you want to split up into tokens and pass it your set of delimiter characters. You can also use the default set of delimiter characters which is ” tnrf”, the space character, the tab character, the newline character, the carriage-return character and the form-feed character.

    Then continually call the method hasMoreTokens and nextToken until there are no more tokens. The StringTokenizer will keep track of the current position and nextToken will return the set of characters that appear before the next delimiter character. You can change the delimiter character(s) anytime by calling nextToken(String delim).

    Here’s an example that reads in a csv and prints out its tokens.

    csv.txt:

     "Mike",1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,9,8,7,6,5,4  
     "George",3,6,4,2,3,5,2,3,4  
     "Anne",7,4,3,2,8,5,4,1,,3,4,5  
    

    Main.java:

    import java.util.*;
    import java.io.*;
     
    public class Main
    {
       public static void main(String []args) throws IOException {
          if (args.length != 1) {
             System.out.println("Usage: java Main <textfile>");
             System.exit(1);
          }
     
          String text = readFile(args[0]);
     
          String lineSep = System.getProperty("line.separator");
          StringTokenizer st = new StringTokenizer(text, " ," + lineSep);
          while (st.hasMoreTokens()) {
             String token = st.nextToken();
             if (token.charAt(0) == '"') {
                System.out.println();
             }
             System.out.print(token + "/");
          }
       }
     
       public static String readFile(String filename) throws IOException {
          BufferedReader br = new BufferedReader(new FileReader(filename));
          StringBuffer total = new StringBuffer();
          String lineSep = System.getProperty("line.separator");
          String line;
          while ((line = br.readLine()) != null) {
             total.append(line + lineSep);
          }
     
          br.close();
          return total.toString();
       }      
    }
    

    outputs:

    
    "Mike"/1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/9/8/7/6/5/4/
    "George"/3/6/4/2/3/5/2/3/4/
    "Anne"/7/4/3/2/8/5/4/1/3/4/5/
    

    Putting a component in a TitledBorder?

    Courtesy of Nobuo Tamemasa (http://www2.gol.com/users/tame/swing/examples/JTableExamples5.html)

    CompTitledPaneExample1.java:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.border.*;
     
    /**
     * @version 1.0 08/12/99
     */  
    public class CompTitledPaneExample1 extends JFrame {
     
      String title = "<html>Title (" 
                   + "<font color="#ffffff"><i>JLabel</i></font>"
                   + ")";
     
      public CompTitledPaneExample1() {
        super("CompTitledPaneExample1");
        JLabel titleLabel = new JLabel(title);
        CompTitledPane p1 = new CompTitledPane(titleLabel);
        JPanel p = p1.getContentPane();
        p.setLayout(new BorderLayout());
        p.add(new SwitchPanel(p1), BorderLayout.CENTER);
        getContentPane().add(p1, BorderLayout.CENTER);
      }
      
      class SwitchPanel extends JPanel implements ActionListener {
        String[] posStr = {"", "ABOVE_TOP"   , "TOP"   , "BELOW_TOP"
                             , "ABOVE_BOTTOM", "BOTTOM", "BELOW_BOTTOM"};
        String[] jusStr = {"", "LEFT"        , "CENTER", "RIGHT"};
        TitledBorder border;
        CompTitledPane panel;
        
        SwitchPanel(CompTitledPane panel) {
          this.panel = panel;
          this.border = (TitledBorder)panel.getBorder();
          add(createPanel("Position"     ,posStr, 2));
          add(createPanel("Justification",jusStr, 1));
        }
        
        JPanel createPanel(String str, String[] strs, int selectPos) {
          JPanel p = new JPanel();
          p.setLayout(new GridLayout(strs.length, 1));
          p.add(new JLabel(str));
          ButtonGroup g = new ButtonGroup();
          for (int i=1;i<strs.length;i++) {
            JRadioButton b = new JRadioButton(strs[i]);
            if (i == selectPos) {
              b.setSelected(true);
            }
            p.add( b );
            g.add( b );
            b.addActionListener(this);
          }
          return p;
        }
        
        public void actionPerformed(ActionEvent e) {
          JRadioButton b = (JRadioButton)e.getSource();
          String label = b.getText();
          for (int i=1; i<posStr.length; i++) {
            if (label.equals(posStr[i])) {
              border.setTitlePosition(i);
              panel.revalidate();
              panel.repaint();
              return;
            }    
          }
          for (int i=1; i<jusStr.length; i++) {
            if (label.equals(jusStr[i])) {
              border.setTitleJustification(i);
              panel.revalidate();
              panel.repaint();
              return;
            }    
          }
        }   
      }
     
      public static void main (String args[]) {
        CompTitledPaneExample1 frame = new CompTitledPaneExample1();
        frame.addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
    	System.exit(0);
          }
        });
        frame.setSize(280, 230);
        frame.setVisible(true);
      }
    }
    

    CompTitledPane.java:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
        
    /**
     * @version 1.0 08/12/99
     */
    public class CompTitledPane extends JPanel {
      protected CompTitledBorder border;
      protected JComponent component;
      protected JPanel panel;
      protected boolean transmittingAllowed;
      protected StateTransmitter transmitter;
      
      public CompTitledPane() {
        this(new JLabel("Title"));
        // debug
        // JLabel label = (JLabel)getTitleComponent();
        // label.setOpaque(true);
        // label.setBackground(Color.yellow);
      }
      
      public CompTitledPane(JComponent component) {
        this.component = component;
        border = new CompTitledBorder(component);
        setBorder(border);
        panel = new JPanel();
        setLayout(null);
        add(component);
        add(panel); 
        transmittingAllowed = false;
        transmitter = null;
      }
      
      public JComponent getTitleComponent() {
        return component;
      }
      
      public void setTitleComponent(JComponent newComponent) {
        remove(component);
        add(newComponent);
        border.setTitleComponent(newComponent);
        component = newComponent;
      }
      
      public JPanel getContentPane() {
        return panel;
      }
      
      public void doLayout() {
        Insets insets = getInsets();
        Rectangle rect = getBounds();
        rect.x = 0;
        rect.y = 0;
     
        Rectangle compR = border.getComponentRect(rect,insets);
        component.setBounds(compR);
        rect.x += insets.left;
        rect.y += insets.top;
        rect.width  -= insets.left + insets.right;
        rect.height -= insets.top  + insets.bottom;
        panel.setBounds(rect);   
      }
       
      public void setTransmittingAllowed(boolean enable) {
        transmittingAllowed = enable;
      }
      
      public boolean getTransmittingAllowed() {
        return transmittingAllowed;
      }
      
      public void setTransmitter(StateTransmitter transmitter) {
        this.transmitter = transmitter;
      }
      
      public StateTransmitter getTransmitter() {
        return transmitter;
      }
      
      public void setEnabled(boolean enable) {
        super.setEnabled(enable);
        if (transmittingAllowed && transmitter != null) {
          transmitter.setChildrenEnabled(enable);
        }
      } 
        
    }
    

    StateTransmitter.java:

    /**
     * @version 1.0 08/12/99
     */
    public interface StateTransmitter {
    
      public void setChildrenEnabled(boolean enable);
      
    }
    
    // sample
    //
    //  public void setChildrenEnabled(boolean enable) {
    //    
    //    Component[] children = panel.getComponents();
    //    for(int i=0; i<children.length; i++) { 
    //      System.out.println(" " + i + 
    //                         " " + children[i].getClass().getName() +
    //                         " " + enable);
    //      children[i].setEnabled(enable); 
    //    }
    //  }
    //
    

    CompTitledBorder.java:

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
      
    /**
     * @version 1.0 08/12/99
     */
    public class CompTitledBorder extends TitledBorder { 
      protected JComponent component;
      
      public CompTitledBorder(JComponent component) {
        this(null, component, LEFT, TOP);
      }
      
      public CompTitledBorder(Border border) {
        this(border, null, LEFT, TOP);
      }
      
      public CompTitledBorder(Border border, JComponent component) {
        this(border, component, LEFT, TOP);
      }
        
      public CompTitledBorder(Border     border,
                              JComponent component,
                              int        titleJustification,
                              int        titlePosition)      {
        super(border, null, titleJustification,
                            titlePosition, null, null);
        this.component = component;
        if (border == null) {
          this.border = super.getBorder();
        }
      }
      
      
      public void paintBorder(Component c, Graphics g,
                              int x, int y, int width, int height) {
        Rectangle borderR = new Rectangle(x      +  EDGE_SPACING,
                                          y      +  EDGE_SPACING,
                                          width  - (EDGE_SPACING * 2),
                                          height - (EDGE_SPACING * 2));
        Insets borderInsets;
        if (border != null) {
          borderInsets = border.getBorderInsets(c);
        } else {
          borderInsets = new Insets(0, 0, 0, 0);
        }
        
        Rectangle rect = new Rectangle(x,y,width,height);
        Insets insets = getBorderInsets(c);
        Rectangle compR = getComponentRect(rect, insets);
        int diff;
        switch (titlePosition) {
          case ABOVE_TOP:
            diff = compR.height + TEXT_SPACING;
            borderR.y += diff;
            borderR.height -= diff;
            break;
          case TOP:
          case DEFAULT_POSITION:
            diff = insets.top/2 - borderInsets.top - EDGE_SPACING;
            borderR.y += diff;
            borderR.height -= diff;
            break;
          case BELOW_TOP:
          case ABOVE_BOTTOM:
            break;
          case BOTTOM:
            diff = insets.bottom/2 - borderInsets.bottom - EDGE_SPACING;
            borderR.height -= diff;
            break;
          case BELOW_BOTTOM:
            diff = compR.height + TEXT_SPACING;
            borderR.height -= diff;
            break;
        }
        border.paintBorder(c, g, borderR.x,     borderR.y, 
                                 borderR.width, borderR.height);    
        Color col = g.getColor();
        g.setColor(c.getBackground());
        g.fillRect(compR.x, compR.y, compR.width, compR.height);
        g.setColor(col);
        component.repaint();
      }
       
      public Insets getBorderInsets(Component c, Insets insets) {
        Insets borderInsets;
        if (border != null) {
          borderInsets  = border.getBorderInsets(c);
        } else {
          borderInsets  = new Insets(0,0,0,0);
        }
        insets.top    = EDGE_SPACING + TEXT_SPACING + borderInsets.top;
        insets.right  = EDGE_SPACING + TEXT_SPACING + borderInsets.right;
        insets.bottom = EDGE_SPACING + TEXT_SPACING + borderInsets.bottom;
        insets.left   = EDGE_SPACING + TEXT_SPACING + borderInsets.left;
     
        if (c == null || component == null) {
          return insets;
        }
     
        int compHeight = 0;
        if (component != null) {
          compHeight = component.getPreferredSize().height;
        }
     
        switch (titlePosition) {
          case ABOVE_TOP:
            insets.top    += compHeight + TEXT_SPACING;
            break;
          case TOP:
          case DEFAULT_POSITION:
            insets.top    += Math.max(compHeight,borderInsets.top) - borderInsets.top;
            break;
          case BELOW_TOP:
            insets.top    += compHeight + TEXT_SPACING;
            break;
          case ABOVE_BOTTOM:
            insets.bottom += compHeight + TEXT_SPACING;
            break;
          case BOTTOM:
            insets.bottom += Math.max(compHeight,borderInsets.bottom) - borderInsets.bottom;
            break;
          case BELOW_BOTTOM:
            insets.bottom += compHeight + TEXT_SPACING;
            break;
        }
        return insets;
      }
      
      public JComponent getTitleComponent() {
        return component;
      }
      
      public void setTitleComponent(JComponent component) {
        this.component = component;
      }
      
      
      public Rectangle getComponentRect(Rectangle rect,Insets borderInsets) {
        Dimension compD = component.getPreferredSize();
        Rectangle compR = new Rectangle(0,0,compD.width,compD.height);
        switch (titlePosition) {
          case ABOVE_TOP:
            compR.y = EDGE_SPACING;
            break;
          case TOP:
          case DEFAULT_POSITION:
            compR.y = EDGE_SPACING + 
                     (borderInsets.top -EDGE_SPACING -TEXT_SPACING -compD.height)/2;
            break;
          case BELOW_TOP:
            compR.y = borderInsets.top - compD.height - TEXT_SPACING;
            break;
          case ABOVE_BOTTOM:
            compR.y = rect.height - borderInsets.bottom + TEXT_SPACING;
            break;
          case BOTTOM:
            compR.y = rect.height - borderInsets.bottom + TEXT_SPACING +
                     (borderInsets.bottom -EDGE_SPACING -TEXT_SPACING -compD.height)/2;
            break;
          case BELOW_BOTTOM:
            compR.y = rect.height - compD.height - EDGE_SPACING;
            break;
        }
        switch (titleJustification) {
          case LEFT:
          case DEFAULT_JUSTIFICATION:
            compR.x = TEXT_INSET_H + borderInsets.left;
            break;
          case RIGHT:
            compR.x = rect.width - borderInsets.right -TEXT_INSET_H -compR.width;
            break;
          case CENTER:
            compR.x = (rect.width - compR.width) / 2;
            break;
        }
        return compR;
      }
     
    }
    

    Disabling the maximize-icon in a JFrame

    First thing you can try is changing the resizable property from the Frame class:

     
    import javax.swing.*;
    import java.awt.*;
      
    public class DisableMax extends JFrame {
     
       public DisableMax() {
          setSize(100, 100);
    
          setResizable(false);
       }
     
       public static void main(String args[]) {
          new DisableMax().setVisible(true);     
       }
    }
    

    However, in this example the maximize icons will still be there. Moreover, the frame will not be resizable anymore (might not be the functionality you want!).
    Extend from a JDialog instead and your window will only have the X icon visible.

     
    import javax.swing.*;
    import java.awt.*;
       
    public class DisableMax2 extends JDialog {
     
       public DisableMax2() {
          setSize(100, 100);
     
          setResizable(false);
       }
     
       public static void main(String args[]) {
          new DisableMax2().setVisible(true);     
       }
    }
    

    Force the JScrollPane to scroll to the next JTextField when I press the TAB-Key

    There are three steps to this:

    1. Listen for focus events coming from the components that you want to scroll to. (This works for most component classes, not just JTextField.)

    2. In the event listener, find the location of the component that now has focus with getBounds().

    3. Ask the scrolled component to make that location visible with scrollRectToVisible(). NOTE! The obvious thing to call scrollRectToVisible on is the JScrollPane, which will compile fine but won’t do what you want. You must call scrollRectToVisible on the object contained in viewport of the scrollpane.

    This Forte-generated example shows how this works for a simple panel containing a number of JTextFields. Notice that scrollRectToVisible is called on the JPanel containing the text fields.

    TestFocus.java:

    public class TestFocus extends javax.swing.JFrame {
     
        /** Creates new form TestFocus */
        public TestFocus() {
            initComponents();
        }
     
        /** This method is called from within the constructor to
         * initialize the form.
         * WARNING: Do NOT modify this code. The content of this method is
         * always regenerated by the Form Editor.
         */
        private void initComponents() {
            scrollPane = new javax.swing.JScrollPane();
            panel = new javax.swing.JPanel();
            jTextField1 = new javax.swing.JTextField();
            jTextField2 = new javax.swing.JTextField();
            jTextField3 = new javax.swing.JTextField();
            jTextField4 = new javax.swing.JTextField();
             
            addWindowListener(new java.awt.event.WindowAdapter() {
                public void windowClosing(java.awt.event.WindowEvent evt) {
                    exitForm(evt);
                }
            });
            
            scrollPane.setPreferredSize(new java.awt.Dimension(120, 80));
            panel.setLayout(new java.awt.GridLayout(0, 1, 0, 15));
            
            jTextField1.setFont(new java.awt.Font("Dialog", 0, 18));
            jTextField1.setText("jTextField1");
            jTextField1.addFocusListener(new java.awt.event.FocusAdapter() {
                public void focusGained(java.awt.event.FocusEvent evt) {
                    jTextFieldFocusGained(evt);
                }
            });
             
            panel.add(jTextField1);
            
            jTextField2.setFont(new java.awt.Font("Dialog", 0, 18));
            jTextField2.setText("jTextField2");
            jTextField2.addFocusListener(new java.awt.event.FocusAdapter() {
                public void focusGained(java.awt.event.FocusEvent evt) {
                    jTextFieldFocusGained(evt);
                }
            });
            
            panel.add(jTextField2);
            
            jTextField3.setFont(new java.awt.Font("Dialog", 0, 18));
            jTextField3.setText("jTextField3");
            jTextField3.addFocusListener(new java.awt.event.FocusAdapter() {
                public void focusGained(java.awt.event.FocusEvent evt) {
                    jTextFieldFocusGained(evt);
                }
            });
            
            panel.add(jTextField3);
            
            jTextField4.setFont(new java.awt.Font("Dialog", 0, 18));
            jTextField4.setText("jTextField4");
            jTextField4.addFocusListener(new java.awt.event.FocusAdapter() {
                public void focusGained(java.awt.event.FocusEvent evt) {
                    jTextFieldFocusGained(evt);
                }
            });
            
            panel.add(jTextField4);
            
            scrollPane.setViewportView(panel);
            
            getContentPane().add(scrollPane, java.awt.BorderLayout.CENTER);
            
            pack();
        }
     
        private void jTextFieldFocusGained(java.awt.event.FocusEvent evt) {
            java.awt.Component focusedComponent = evt.getComponent();
            panel.scrollRectToVisible(focusedComponent.getBounds(null));
            repaint();
        }
     
        /** Exit the Application */
        private void exitForm(java.awt.event.WindowEvent evt) {
            System.exit(0);
        }
     
        /**
        * @param args the command line arguments
        */
        public static void main(String args[]) {
            new TestFocus().show();
        }
     
        // Variables declaration - do not modify
        private javax.swing.JScrollPane scrollPane;
        private javax.swing.JPanel panel;
        private javax.swing.JTextField jTextField1;
        private javax.swing.JTextField jTextField2;
        private javax.swing.JTextField jTextField3;
        private javax.swing.JTextField jTextField4;
        // End of variables declaration
    
    }
    

    If your panel of components contains a JTextArea, or another JTextComponent subclass, then be aware that those components will absorb TABs into themselves instead of allowing the TAB to change focus. You can disable this behavior by creating a subclass that overrides isManagingFocus() to always return false.