Java Applets
— print (last updated: Nov 14, 2009) print

Select font size:
The example in this handout, WordSearchApplet, whic is an Applet version of the previous application, WordSearch. It is available for download as WordSearchApplet.zip which is meant to access files on your computers, which also can be downloaded as the SampleFiles.zip archive.

NetBeans considerations

Using NetBeans it turns out to be important to have a Main class (i.e. class with main function) even though the main function is never used. The reason is that NetBeans will then correctly build and add the necessary JAR files to the dist folder needed for running the applet through a browser.

Applets

Java Applets are used for web-based client-side programming in Java. In contrast there is server-side programming effected by Java Servlets and Server Pages. One can also to run Java Applets independent of the browser through the appletviewer tool; however, the default security restrictions are different than what exists for browser execution.

Applets are executed by a specific browser plugin, in a manner similar to the common Flash player. It's relatively automatic to install the latest version of the Java plugin in Windows systems. In Linux systems, you may have to do more work to achieve the plugin installation for the SUN Java versions.

The Java applet classes include the older java.awt.Applet of which the Swing version, javax.swing.JApplet, is an extension. Unlike an application, an applet is not executed directly, but is loaded and executed by the java interpreter built-in to the Java plugin. In particular, a applet has no main function. It is controlled by certain standard functions activated by the plugin (or appletviewer), including these:
public void init();     // the JApplet is loaded
public void start();    // the browser applet is viewed
public void stop();     // the browser leaves the applet page
public void destroy();  // the JApplet is unloaded
An applet is activated through HTML-specific tags, often in a HTML file called as stub, whose sole purpose is to cause the browser/viewer to load the applet. Here is a sample stub file:
<applet code="MyApplet"
        width="300" height="100"
>
</applet>
The width and height attributes are required. In order to run the MyApplet class we would co-locate MyApplet.class along with MyApplet.html in the same directory and then point our browser to MyApplet.html, or, via appletviewer:
appletviewer MyApplet.html
Alternatively, one can use the attribute
       codebase="directory-where-applet-code-is"
to make the HTML stub file's location independent of the code's location.

HtmlConverter

The applet tag is deprecated by HTML standards, and so, even though the applet tag will probably work as is, you are encouraged to convert it to the modern form using the object tag. The Java Development Kit provides a converter operation called HtmlConverter specifically for converting the applet tag usages. From a shell command line, run:
HtmlConverter MyApplet.html
A backup copy of MyApplet.html is made in a separate directory and MyApplet.html is converted to the object form. You can also simply run HtmlConverter without parameters and allow it to choose the target applet stub file.

Applet Security Restrictions

An applet is downloaded from a server an runs in the browser and so the Java plugin in a browser enforces, by default, stark security restrictions over what the applet can do. This is clearly necessary to protect applets from inadvertently (or maliciously) accessing files and client-side services which it shouldn't do. In particular, By default, the only external access permitted an applet is to make a socket connection back to the server from which the applet was downloaded. Therefore, since our MySQL database server is actually a socket connection to port 3306, we can connect to it so long as One can also circumvent the security restrictions by an elaborate mechanism which involves creating a digital certificate and attaching it to a JAR file containing the applet.

Accessing Jar files

The archive attribute in the applet tag is used specify JAR files from which classes are loaded.
<applet
  code="MyApplet"
  archive="JarFile1.jar,JarFile2.jar"
  width="300" height="100"
>
Applet Didn't Load
</applet>
This is particularly useful for accessing the MySQL driver. Furthermore, the class MyApplet.class itself may be part of a JAR file and we can thereby avoid any providing any class files, per se, with the applet.

Run-time parameters

Run-time parameters cannot be delivered though a file since this is prohibited by the applet security mechanism. Instead we can deliver parameters through the HTML stub file as follows:
<applet
  code="MyApplet"
  width="300" height="100"
>
<param name="param_name1" value="param_value1" />
<param name="param_name2" value="param_value2" />
Applet Didn't Load
</applet>
Within the applet itself, these parameters can then be read using the getParameter function as follows:
String value = getParameter("param_name1");
...

Rewriting a Java GUI application as a JApplet

The rewrite of a Java GUI JFrame-based application to a JApplet is fairly simple. The major difficulty is dealing with the security restrictions. Here are the major rewrite changes that need to be done.
  1. Replace JFrame by JApplet
  2. Eliminate or ignore the main function (it doesn't hurt to keep it in, it's just not used)
  3. Replace the constructor by public void init()
  4. Elminate any calls to super for base-class initialization
  5. Remove statements which control the JFrame GUI such as:
    setDefaultCloseOperation, setSize, setVisible
    
  6. Eliminate any statements which are prohibited by security restrictions. This includes file access, a number of calls such as System.exit(0), etc.
  7. Place any jar files used within the directory holding the stub file and access them in the archive attribute as a comma-separated list. Actually it doesn't have to be right there, it's just that the web server may not permit access to the jar file just anywhere in the system.
  8. Modify the code so that any runtime parameters are delivered by the getParameter function using parameters defined within the applet's HTML stub file.

Digital Signature

You can bypass the default applet security restrictions. To do so, the JAR file containing code which violates these restrictions can be augmented by a cryptographic key called a digital signature. The Java plugin recognizes this signature and gives the user the option to permit this code to bypass the security restrictions.

Generate a keystore and a key

You can generate a keystore which can be used for multiple applets. Open a command shell and navigate to the NetBeansProjects folder (or some other likely place). From the shell we'll run additional executables from the Java Development Toolkit. Type:
keytool -keystore mystore -genkey
This invokes a dialog in which you need to enter two passwords (they can be the same, but we'll make the different to illustrate how they're used). You can make the passwords whatever you want.
Enter keystore password:  keystorePwd        (at least 6 chars)

  Now you are asked for 6 pieces of information of which the default is "Unknown". 
  For simplicity take this default.

Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]:  yes

Enter key password for 
     (RETURN if same as keystore password): keyPwd
This generates a keystore which is a file whose name is mystore containing one digital signature key, which uses the default name mykey. The first password entered, keystorePwd, is needed to unlock the keystore file and the second (keyPwd) grants usage of the individual key.

You can validate the contents of mystore as follows:
keytool -keystore mystore -list
The listing of contents requires the keystore password:
Enter keystore password:  keystorePwd

Keystore type: jks
Keystore provider: SUN
	
Your keystore contains 1 entry

mykey, ...

Signing a JAR file

We use the dedicated JDK executable, jarsigner, to add the key, mykey to the necessary JAR file, SOMETHING.jar. We'll assume that mystore and the target JAR file are in the same folder. Run:
jarsigner -keystore mystore SOMETHING.jar mykey
You're signing the JAR file using the key mykey held in nystore. You'll need both the passwords to do so:
Enter Passphrase for keystore: keystorePwd
Enter key password for mykey: keyPwd
Use the "jar tf" command to observe the contents of the JAR file to see that the signature information is stored in the META-INF directory which is part of every JAR file:
jar tf SOMETHING.jar	

META-INF/MANIFEST.MF
META-INF/MYKEY.SF
META-INF/MYKEY.DSA
META-INF/
...
Afterwards, when you run the applet in a browser it will query you about accepting the signature.

Execution from source

WordSearchApplet

The steps are the just about the same. Eliminate the "MySQL Driver" step since it's not used. In this case we want to digitally sign the WordSearchApplet.jar file, i.e.,
jarsigner -keystore mystore WordSearchApplet.jar mykey
in the dist folder.

In this case we really need to deal with the security restrictions. Running appletviewer probably will not work without extra effort. Try running it wordsearchapplet.html in a browser.

Construction of WordSearchApplet

  1. Create the new Java Application project WordSearchApplet.
  2. Go to the Files window, right-click on WordSearchApplet and create the HTML file wordsearch.html, adding this to the body:
        <applet code="views.Applet"
                codebase="dist"
                archive="WordSearchApplet.jar"
                width="450" height="450" >
        </applet>
    
    Afterwards, go back to the Projects window.
  3. Create a JApplet Form as the class views.Applet.
  4. Set the layout of Applet to be BorderLayout.
  5. Drag a Menu Bar onto the Applet. For some reason (bug??) it doesn't show.
  6. Using the Inspector window, delete the JMenu2 menu.
  7. Using the Inspector window, right-click on JMenu1, select Add From Palette and choose a Menu Item.
  8. Make the variable name of the menu item be open.
  9. Edit the Properties of the open menu item and make the text be "Open" (the change will not be reflected in Inspector).
  10. Drag a Text Area into the Applet (the center).
  11. Set the variable name of the Text Area to be display.
  12. Edit the Properties of display, making it not editable, with linewrap checked.
  13. Drag a Panel into the bottom part.
  14. Drag a Text Field and then a Button onto the Panel (anywhere).
  15. Set the layout of the Panel to be FlowLayout.
  16. Set the variable name of the Text Field to be keyfield.
  17. Edit the Properties of keyfield, making it have 15 columns
  18. Make the Button have text "Search" and make the variable name be search.
At this point it's worthwhile to validate the menus are really showing in the Applet. Do a "Build Clean", navigate to the NetBeans WordSearchApplet folder and run the wordsearchapplet.html file.
  1. Edit Applet in source mode. Add these imports:
    import java.awt.event.*;
    import javax.swing.text.Highlighter;
    
    and these member functions:
      public String getKeyFieldText() {
        return keyfield.getText();
      }
    
      public void addSearchActionListener(ActionListener al) {
        search.addActionListener(al);      // Search button pressed
        keyfield.addActionListener(al);    // return typed in textfield
      }
    
      public Highlighter getDisplayHighlighter() {
        return display.getHighlighter();
      }
    
      public String getDisplayText() {
        return display.getText();
      }
    
      public void setDisplayText(String text) {
        display.setText(text);
        display.setCaretPosition(0);
      }
    
      public void addOpenActionListener(ActionListener al) {
        open.addActionListener(al);
      }
    
    and add these lines to the init function:
          final Applet gui = this;
          java.awt.EventQueue.invokeAndWait(new Runnable() {
            public void run() {
              initComponents();
              new wordsearchapplet.Main(gui);
            }
          });
    
    
  2. Edit Main, making the code be this:
    package wordsearchapplet;
    
    import views.*;
    import javax.swing.*;
    import java.awt.event.*;
    
    import java.io.*;
    
    import java.util.regex.*;
    import javax.swing.text.*;
    import java.awt.Color;
    
    public class Main {
      private JFileChooser fc = new JFileChooser();
      private Applet frame;
    
      private String readTextFile(File f) throws Exception {
        FileInputStream istr = new FileInputStream(f);
        InputStreamReader irdr = new InputStreamReader(istr); // promote
    
        int size = (int) f.length();  // get the file size (in bytes)
        char[] data = new char[size]; // allocate char array of right size
        irdr.read(data, 0, size);     // read into char array
        irdr.close();
    
        String contents = new String(data);
        return contents;
      }
    
      private void highlightWord(String keyword) {
        String patternStr = "\\b" + keyword + "\\b";
    
        Pattern pattern = Pattern.compile(patternStr, Pattern.CASE_INSENSITIVE);
    
        Matcher matcher = pattern.matcher(frame.getDisplayText());
    
        Highlighter.HighlightPainter myPainter
          = new DefaultHighlighter.DefaultHighlightPainter(Color.yellow);
    
        Highlighter displayHighlighter = frame.getDisplayHighlighter();
    
        displayHighlighter.removeAllHighlights();
    
        while (matcher.find()) {
          int start = matcher.start(), end = matcher.end();
          try {
            displayHighlighter.addHighlight(start, end, myPainter);
          } catch (Exception x) {
            x.printStackTrace(); // we did something wrong!
          }
        }
      }
    
      public Main(Applet gui) {
        this.frame = gui;
    
        frame.addOpenActionListener(
          new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
              int status = fc.showOpenDialog(frame);
              if (status != JFileChooser.APPROVE_OPTION) {
                return;
              }
              try {
                frame.setDisplayText(readTextFile(fc.getSelectedFile()));
              } catch (Exception x) {
                JOptionPane.showMessageDialog(frame, x);
              }
            }
          });
    
        frame.addSearchActionListener(
          new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
              String keyword = frame.getKeyFieldText().trim();
              if (!keyword.matches("\\w+")) {
                JOptionPane.showMessageDialog(frame, "illegal keyword");
              } else {
                highlightWord(keyword);
              }
            }
          });
      }
    
      public static void main(String[] args) {
      }
    }
    
    


© Robert M. Kline