by Mark O. Pendergast, PhD

When to use applets instead of HTML forms: Three easy techniques

how-to
Apr 22, 201329 mins

Using applets for web page menus and database interactions

Web developers are plagued by the inconsistent browser rendering of HTML and JavaScript, yet most continue to use HTML forms to build GUI front-ends. In this article returning JavaWorld contributor Dr. Mark O. Pendergast goes against the grain, suggesting three cases where Java applets are a viable alternative to HTML forms. First learn how to use applets to create complex multi-level menus, then consider what you could gain from replacing HTML GET and POST operations with client- and server-side applet implementations. Note that security concerns are addressed for each of the solutions discussed in this article.

Web developers know too well the pain of trying to make web pages display consistently and scripts respond properly across multiple browsers. The problem is that the HTML/CSS/JavaScript specifications are constantly in flux, and so are their corresponding browser implementations. The W3C controls the specifications, browser developers interpret them, and web developers are stuck in the middle. In just the last year at the university where I teach, I’ve seen a half dozen advisories from our campus IT group about browser incompatibilities with the online learning management system. Close inspection of the code behind many websites reveals complex conditional logic to handle unpredictable variations in browser behavior. There must be a simpler way to display information and process forms.

Unlikely as it may seem to developers swayed by the hype about HTML 5 and JavaScript, I make the case in this article for using Java applets instead of HTML forms. Applets will enable you to create multi-level drop down menus, use a myriad of colors and styles, create forms with user-friendly controls, and communicate with web and database servers. And you can do all of this securely, using your favorite JVM language and IDE.

What about applet security?

The recent zero-day security flaw (discovered in Java 7 update 10 and subsequently patched by Oracle) allowed applets to bypass the Java security sandbox, granting themselves permission to execute arbitrary code. A frenzy of fear about Java security followed.

The truth is that Java is no different from Active X, Flash, and other plugins, in that it poses an occasional security threat. It was always possible for hackers to create self-signed applets, and it is also possible to secure your Java applications against them; not perfectly, but sufficiently. Rather than swearing off applets, I would hope that developers would take the time to educate themselves and strengthen the security of their Java applications. This article offers tips for writing secure applets in real-world development scenarios.

Applets for web development

Every Java programmer has created a Java applet, most of them in the category of simple clocks or calculators. Some of us have even played with fonts and colors and seen that it’s possible to integrate our applets with web pages. But for some reason, developers tend to shy away from applets when it comes to creating serious applications that interact with a database. Most of the time, we choose HTML forms for user interactions involving stored data. It could be that we’re leery of the security limitations placed on applets. Some of us got caught up in the Ajax frenzy; for others, it was just the technique that was taught in school. Whatever the reason the potential of using Java applets to build the GUI interface for web applications tends to be overlooked. With this article I aim to correct that oversight, by demonstrating three useful applications of applets for web development:

Along the way, you’ll learn how to do all of the following with applets:

  • Program an applet to display a URL in the browser
  • Encode user input into the URL so that parameters are passed to the web server
  • Dynamically generate JavaScript to pass data back to the applet from the web server
  • Open a two-way stream connection (HTTPURLConnection) with a servlet in order to transmit entire objects

You can download the source code for this article anytime. The source package consists of three NetBeans projects:

  • The MenuApplet project shows a simple News-Weather-Sports applet-based menu system.
  • Projects in the URLEncoding folder contain an applet that demonstrates search, delete, add, and update functions for records in a database using the get method. The GUI for this applet is a JTabbedPane that holds forms for each function and utilizes JFormattedFields, InputVerifiers, and JTables.
  • Projects in the ServletStream folder have the same interface and perform the same functions as the URLEncoding projects, but they use the post method. All of the applets for these projects are unsigned and do not require any special security options, for reasons that I’ll explain.

Before I get into the mechanics of these examples let’s review some basics of deploying Java applets.

Deploying Java applets with runApplet

Applet display has been a part of the web since the mid 1990s, and is a classic example of the chaos caused by differing browser implementations of the HTML specification. The original Applet tag was deprecated in HTML 4.01, which specified using the Object tag instead. The specification was a bit vague on how the Object tag should be implemented, however, and so support is inconsistent. Internet Explorer works well with the Object tag, but Firefox and Chrome prefer the Embed tag. In response, Oracle offers a script that makes deploying an applet in a mixed-browser environment feasible. The script is based on a single function called runApplet, which accepts three parameters:

  • attributes represents the names and values of the attributes used in the Applet, Object, and Embed tags.
  • parameters represents the names and values of the parameters to be passed to the applet.
  • version represents the minimum version of the JRE software that is required to run the given applet.

In order to use runApplet you need to include the following script and then create JavaScript code that sets the values of the three parameters and invokes the function, as shown in Listing 1.

Listing 1. Using deployJava script

<script src="http://www.java.com/js/deployJava.js"></script>

<script>
  var attributes = {id: "AppletID",
              code: "Applet.class",
              archive: "Applet.jar",
              width:"100%", height:"40" };
  var parameters = {param1:"value1", param2:"value2", param3:"value3",
                     , paramn:"valueN"};
  var version = '1.6';
  deployJava.runApplet(attributes, parameters, version);
</script>

You could write your own script to sort out which browser is running and which tag to use, but I prefer letting Oracle manage this headache. Including runApplet gives me some assurance that my applets will work and relieves me of the responsibility of continually checking browser-version and tag combinations.

Note that Oracle’s deployJava script also enables programmers to invoke applets using JNLP and request additional permissions. We don’t need either of those features for the techniques described in this article.

Using applets for web page menus

HTML has a <MENU> tag but it was deprecated in HTML 4.01 and redefined in HTML 5. It is currently not supported by any of the major browsers (if you use it you get buttons arranged in an un-numbered list). Developers who need to create a web page menu typically do so by using CSS to transform HTML lists into menu bars. A savvy developer who has enough faith in browser implementations of CSS can even develop complex drop-down menus using the CSS hover and float attributes (see Resources) — but the key word here is faith. A much simpler and more reliable way to create multi-level menus is to build them using Java applets.

Menus in Java applets work the same that they do in Java desktop applications. You can have multiple levels, with the topmost being based on the JMenuBar class. Submenus and sub-submenus are based on the JMenu class, and the lowest-level menus are based on JMenuItems. You can avoid the boring grays associated with Windows desktop applications by setting custom font colors and background colors for your menus. Java also allows you to define both accelerators and mnemonics, but your browser will likely prevent the keystrokes for these to get through. You can process menu events by implementing an ActionListener, either in your main JApplet class or as anonymous inner classes.

In order to use a menu item to change the URL being displayed by the browser you need to call the showDocument method of the AppletContext. This method is passed as a URL object and a string containing a target (_self, _blank, window name, etc.), as shown in Listing 2. If you encode parameters on the URL then it is important to be sure that they contain only valid characters. (More about this in the next section.)

Listing 2. Code to process a menu item selection

/**
 *
 *  Process the CNN menu item
 *
 */
 private void cnnItemActionPerformed(java.awt.event.ActionEvent evt) {

  try{
      URL link = new URL("http://www.cnn.com");
      getAppletContext().showDocument(link,target);
    }

    catch(MalformedURLException ex) {
        showStatus("Bad URL: http://www.cnn.com");
     }
 }

Figure 1 shows a web page with an applet menu. The applet is sitting along the top of the page with a frame below it that holds the body of the page. This particular applet menu allows the user to select from a set of news, sports, and weather websites. The applet accepts as parameters the font family, font size, foreground, and background colors of the menu components.

Figure 1. MenuApplet (click to enlarge)

The HTML code for displaying the above applet is shown in Listing 3. Note the use of the deployJava.js script provided by Oracle. This script handles the preferences of various browsers for Applet, Object, and Embed tags. The URLs themselves are coded within the applet, but it would not be difficult to generalize the MenuApplet class and pass these as parameters as well.

Listing 3. HTML code used to display MenuApplet

<!DOCTYPE html>
<HTML>

 <HEAD>
      <script src="http://www.java.com/js/deployJava.js"></script>
</HEAD>
<BODY>
<script>
  var attributes = {id: "MenuApplet",
              code: "applets.MenuApplet.class",
              archive: "MenuApplet.jar",
              width:"100%", height:"40" };
  var parameters = {target:"window1", fontfamily:"Arial", fontsize:"28",
                    fontcolor:"4169E1", bgcolor:"FFFFFF"};
  var version = '1.6';
  deployJava.runApplet(attributes, parameters, version);
</script>

<IFRAME name="window1" height=700 width=100%></IFRAME>
</BODY>
</HTML>

The applet was built with NetBeans and is contained within the project called MenuApplet, which is part of the source file for this article. The code to build the JMenubar and its submenus was generated by NetBeans and isn’t shown below. I could have used NetBeans to set the properties of each menu element, but I chose to make the font family, size, and color choice dynamic by passing the values in from the HTML to the applet via parameters. The init method of the applet retrieves the parameters, parses the font size and colors, creates the font and color objects, then calls a recursive routine to set the font for each JMenuItem and JMenu. I did it this way in order to demonstrate the flexibility of the JApplet’s menu system.

Note that this applet implementation doesn’t need to be signed because no extra permissions are required.

Listing 4. init and setMenuFonts methods

public void init() {

        /* Create and display the applet */
        try {
            java.awt.EventQueue.invokeAndWait(new Runnable() {
                public void run() {
                    initComponents();
                }
            });
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        //
        // get the target of the showDocument calls
        //
        target = this.getParameter("Target");
        if(target == null)
            target="_self";  // assume self if the parameter is missing
        //
        // access the font information from the parameters
        //
        String fontsize = this.getParameter("fontsize");
        String fontfamily = this.getParameter("fontfamily");
        String fontcolor = this.getParameter("fontcolor");
        String bgcolor = this.getParameter("bgcolor");
        //
        // create the font and the colors if all parameters are present
        //
        if(fontsize != null && fontfamily != null && fontcolor != null)
        {
         Font menuFont;
         Color fcolor = Color.BLACK;
         Color bcolor = Color.WHITE;
          try{
            int size = Integer.parseInt(fontsize);
            int colorf = Integer.parseInt(fontcolor,16);
            int colorb = Integer.parseInt(bgcolor,16);
            menuFont = new Font(fontfamily, Font.PLAIN, size);
            fcolor = new Color(colorf);
            bcolor = new Color(colorb);

            synchronized(menuBar.getTreeLock())  // protect the UI
            {
             menuBar.setBackground(bcolor); // set the menu bar background
             Component[] comps = menuBar.getComponents(); // get all the components
             for(int i = 0; i < comps.length; i++)
             {
              setMenuFonts(comps[i],menuFont, fcolor,bcolor);  // recursively set fonts
             }
            }
          }
          catch(NumberFormatException nfex)
          {
            // any parsing errors will cause the default fonts to be used.
          }
        }
    }
/**
 * Recursively set all the fonts and colors for the JMenu or JMenuItem component passed
 *
 * @param c - Component (JMenu or JMenuItem)
 * @param f - font
 * @param fcolor - foreground color
 * @param bcolor - background color
 */
    private void setMenuFonts(Component c, Font f, Color fcolor, Color bcolor)
    {
     //
     // set the properties
     c.setForeground(fcolor);
     c.setBackground(bcolor);
     c.setFont(f);
     //
     // recurse only if it is a JMenu
     //
     if(c instanceof JMenu)
     {
       ((JMenu)c).setOpaque(true);  // force the JMenus to be opaque
       Component[] comps = ((JMenu)c).getMenuComponents();
       for(int i = 0; i < comps.length; i++)
       {
        setMenuFonts(comps[i],f,fcolor,bcolor); // recurse for each sub item
       }
     }
    }

Using applets instead of HTML GET forms

Next I’ll show you how to use the showDocument method of the AppletContext to submit URL-encoded data to server-side form processing pages such as JSPs, ASPs, or servlets. In the process you’ll trade the limited selection of GUI controls available from HTML forms for the richer set present in Java applets. Java offers numerous controls for getting input and displaying search results, and you can use InputVerifier to ensure form data is valid. Here is a short list of available GUI controls:

  • JTable
  • JTree
  • JPopupMenu
  • JSlider
  • JTabbedPane
  • JSpiltPanes
  • JSpinner
  • JDialog
  • JFormatted fields

Another advantage of using applets in place of HTML forms is that one applet can contain many separate forms, each linked to a different server-side script. This makes it easier to preserve the state of a transaction across multiple forms and the user does not have to worry about about what will happen if he or she presses the Back button.

As with an HTML form, each applet form can have a Submit button (JButton). In a typical web form, you would specify the action, method, target for the form, and provide parameter validation code for processing the onSubmit event. The parameter validation code would usually be a JavaScript function, possibly built using a library like JQuery. The browser would then do the work of retrieving the form values and encoding them in the URL before dispatching to the web server for processing.

Applets do require a little more work than that. As with an HTML implementation, you need to validate form values before sending the form to the server. The applet then uses the URLEncoder class to replace any “unsafe” characters (any that aren’t valid in URLS) using an encoding scheme like UTF-8. URLEncoder leaves the alphanumeric characters unchanged, as well as other safe characters such as dots (.), commas (,), en-dashes (-), asterisks (*), and underscores (_). Spaces are converted to plus signs (+) and all other characters are converted to a 3-byte strings beginning with a percentage sign (%) and ending with two hexadecimal digits.

Once all the parameters are encoded they can be appended to the URL using the question-mark and ampersand (? and &) format expected by the web server. Listing 5 shows an example of an applet method that invokes a JSP to add a customer record to a database.

Listing 5. Client side code to process adding a customer

/**
 *
 * Send the add request to the server
 *
 * @param evt
 */
    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:

        try{
            String id = URLEncoder.encode(idField.getText(), "UTF-8");
            String lastName = URLEncoder.encode(lastNameField.getText(), "UTF-8");
            String firstName = URLEncoder.encode(firstNameField.getText(), "UTF-8");
            String addressLine1 = URLEncoder.encode(addressLine1Field.getText(), "UTF-8");
            String addressLine2 = URLEncoder.encode(addressLine2Field.getText(), "UTF-8");
            String city = URLEncoder.encode(cityField.getText(), "UTF-8");
            String state = URLEncoder.encode((String)stateCombo.getSelectedItem(), "UTF-8");
            String zip = URLEncoder.encode(zipField.getText(), "UTF-8");
            String phone = URLEncoder.encode(phoneField.getText(), "UTF-8");

            URL link = new URL(getCodeBase()+"addCustomer.jsp?"+
                "ID="+id+"&" +
                "lastName="+lastName+"&" +
                "firstName="+firstName+"&" +
                "addressLine1="+addressLine1+"&" +
                "addressLine2="+addressLine2+"&" +
                "city="+city+"&" +
                "state="+state+"&" +
                "zip="+zip+"&" +
                "phone="+phone);

            setMessageLabel("Processing request ...");
            getAppletContext().showDocument(link,"AppletOutput");

        }
        catch(UnsupportedEncodingException | MalformedURLException ex)
        {
          setMessageLabel("Unable to process request");
        }

    }


Listing 6 shows the JSP that processes the request.

Listing 6. Server side code to process adding a customer

-----------------------------------------------------------------------------------------------------

<%--
    Document   : addCustomer
    Created on : Feb 25, 2013, 3:52:41 PM
    Author     : Mark Pendergast
--%>

<%@page contentType="text/html" target="_blank" pageEncoding="UTF-8"%>
<%@page import="java.sql.*"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Add Customer</title>
    </head>
    <body>
 <script>
      <%
         int count = 0;
         try{
            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  // load the driver
            Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=Customer;user=AppletTest;password=AppletTest;");
            PreparedStatement add = con.prepareStatement("Insert Into Customers Values (?,?,?,?,?,?,?,?,?)");
            add.setString(1, request.getParameter("ID"));
            add.setString(2, request.getParameter("firstName"));
            add.setString(3, request.getParameter("lastName"));
            add.setString(4, request.getParameter("addressLine1"));
            add.setString(5, request.getParameter("addressLine2"));
            add.setString(6, request.getParameter("city"));
            add.setString(7, request.getParameter("state"));
            add.setString(8, request.getParameter("zip"));
            add.setString(9, request.getParameter("phone"));
            count  = add.executeUpdate();

            add.close();
            con.close();
            %>
             window.parent.document.UrlEncoder.setMessageLabel(<%= count+" " %>+" records added");
            <%
         }
         catch(Exception ex)
         {
            String msg = "Unable to add record, error : "+ex.getMessage();
             %>
              window.parent.document.UrlEncoder.setMessageLabel("<%= msg%>" );
             <%
         }


      %>

    </script>
    </body>
</html>

The resulting form is displayed in Figure 2. Each field of the form has an instance of an InputVerifier to ensure proper data entry. The code for the Add button just needs to access each value, encode them all in UTF-8 format, then build the URL. A question-mark separates the JSP address from the parameter list and an ampersand separates the parameters. In this example the applet and JSP files reside in the same directory on the same server, so the value returned by getCodeBase() is used to designate the location. The showDocument() call also specifies a target frame within the web page called AppletOutput. All output of AddCustomer.jsp will be directed there.

Figure 2.Add Customer form (click to enlarge)

This technique works well to get data from the applet to the web server; but what about going in the other direction? There are two easy ways for the web server to push data back to the applet. The first is by generating output that includes JavaScript calls to methods in the applet, the second is by sending data from applet to servlet and back again using streams. We’ll look at both.

Using JavaScript to pass data from web server to applet

JavaScript has the capability of calling public methods in your applet. First, make sure that you specify an ID for the applet when you deploy it. As shown in Listing 7, I’ve set the Applet’s id to URLEncoder. To call an applet’s methods from JavaScript, just preface it with document.AppletID, for example:

document.URLEncoder.methodName(parameters…)

Figure 3 depicts the complete sequence:

Figure 3. Applet to JSP and Back Data Flow (click to enlarge)

The sequence works as follows:

  1. The applet is deployed from an HTML page that contains an IFRAME for the applet’s output, as shown in Listing 7.
  2. The applet retrieves and encodes all the user input using URLEncoder.
  3. The complete link is built and issued using the showDocument method of the AppletContext, where an internal frame is specified as the target (see Listing 8).
  4. The web server receives the request and generates output that is sent back to the browser for display in the internal frame (see Listing 9).
  5. The output contains JavaScript-to-applet method calls that pass the data to the applet (see Listing 10).

In the following HTML code, the applet is given an ID of URLEncoder and an internal frame with a name of AppletOutput is added as a place to receive the JSP page results. These results consist of JavaScript calls to the applet’s methods; the frame is hidden because the results have nothing that user needs to see.

Listing 7. HTML page holding the applet

<%@page contentType="text/html" target="_blank" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>URL Encoding Demo</title>
        <script src="http://www.java.com/js/deployJava.js"></script>
    </head>
    <body>
       <table class="legacyTable">
            <tr>
            <td>
              <script>
               var attributes = {id: "URLEncoder",
                      code: "applets.DatabaseApplet.class",
                      archive: "Applet.jar",
                      width:"800", height:"400" };
               var parameters = {param1:16, param2:22};
               var version = '1.6';
               deployJava.runApplet(attributes, parameters, version);

           </script>
             </td>
            </tr>
            <tr>
            <td>
             <iframe name="AppletOutput" width="700" height="25" hidden="true" /></IFRAME>
            </td>
         </tr>
         </table>

    </body>
</html>

The findCustomer method in Listing 8 retrieves the last name entered by the user, encodes it with UTF-8, and then invokes the findCustomer.jsp page with a target frame of AppletOutput. AppletOutput will receive the results from the findCustomer.jsp, which consists of calls to the addToResultTable and setMessageLabel methods. The argument sent to AddToResultTable is composed of a comma-delimited string containing the data for one Customer record. addToResultTable splits the string, then adds it to the JTable for the user to see.

Listing 8. Processing the Find Customer button and JavaScript callback methods

/**
 *
 *  Find customers based on partial last name entered by the user
 * @param evt
 */
    private void findCustomerButtonActionPerformed(java.awt.event.ActionEvent evt) {
    try{
      String lastName = URLEncoder.encode(searchField.getText(), "UTF-8");
      URL link = new URL(getCodeBase()+"findCustomer.jsp?"+ "lastName="+lastName);
      clearResults();
      setMessageLabel("Processing request ...");
      getAppletContext().showDocument(link,"AppletOutput");
    }
    catch(UnsupportedEncodingException | MalformedURLException ex)
    {
      setMessageLabel("Error processing request");
    }
   }

    /**
     * add a row to the result table,  columns are separated by commas
     * @param row row to be added, csv format
     */
    public void addToResultTable(String row)
    {
      DefaultTableModel tm = (DefaultTableModel)resultsTable.getModel();
      Object[] data = row.split(","); // split the fields
      if(data.length <= tm.getColumnCount()) // make sure there aren't too many columns
          tm.addRow(data);
    }
/**
 * setMessageLabel
 *
 * changes the text in the message label at the bottom of the applet.
 *
 * @param msg String to be placed in the message label
 */
    public void setMessageLabel(String msg)
    {
      messageLabel.setText(msg);
    }

In Listing 9, findCustomer.jsp connects to a MS SQLServer database and issues a SQL Select statement to retrieve the desired records. As it processes the ResultSet, it builds comma-delimited strings containing the customer data. These strings are then embedded into JavaScript calls to the applet’s addToResultTable method. Calls to the applet setMessageLabel method are also added to report the total number of records found and any exceptions. Listing 10 shows the output of this JSP.

Listing 9. Searching the Customer table for matching records

<%@page contentType="text/html" target="_blank" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<%@page import="java.sql.*"%>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Find Customer</title>
    </head>
    <body>
     <script>
      <%
         int count = 0;
         try{
            String lastName = request.getParameter("lastName");
            if(lastName == null)
                lastName = "";  // default to all

            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  // load the driver
            Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=Customer;user=AppletTest;password=AppletTest;");
            PreparedStatement find = con.prepareStatement("select * from Customers where Last_Name like ?");
            find.setString(1, lastName+"%");
            ResultSet rs = find.executeQuery();
            while(rs.next())
            {
              String row = "'"+rs.getString(1)+","+rs.getString(2)+","+rs.getString(3)+","+rs.getString(4) +
                        ","+rs.getString(5) +","+rs.getString(6) +","+rs.getString(7) +","+rs.getString(8) +","+rs.getString(9)+"'";
             %>
            window.parent.document.URLEncoder.addToResultTable(<%= row %>);
             <%
             count++;
            }
            rs.close();
            find.close();
            con.close();
            %>
             window.parent.document.URLEncoder.setMessageLabel(<%= count+" " %>+" records found");
            <%
         }
         catch(Exception ex)
         {
            String msg = "Unable to perform search, error : "+ex.getMessage();
             %>
              window.parent.document.URLEncoder.setMessageLabel("<%= msg%>" );
             <%
         }

      %>
     </script>
    </body>
</html>

Listing 10. Output of findCustmer.jsp

<!DOCTYPE html>

<html>
  <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Find Customer</title>
  </head>
  <body>
   <script>

    window.parent.document.URLEncoder.addToResultTable('1,Jane,Doe,123 N Main,Apt 303,Cleveland,OH ,12345,111-222-4444');
    window.parent.document.URLEncoder.addToResultTable('3,Hank,Armstrong,3434 Maple Ave,Suite A,Tampa,FL,44444,333-333-3333');
    window.parent.document.URLEncoder.addToResultTable('4,Sally,Fields,123 South 4th Place,Penthouse,HollyWood,CA - California,33333-3333,(222) 222-2222');
    window.parent.document.URLEncoder.addToResultTable('5,Holmes,Karen,123 Sunset Blvd,Suite 444,Los Angeles,CA,44444-4444,(222) 222-2222');

    window.parent.document.URLEncoder.setMessageLabel(4 +" records found");

  </script>
 </body>
 </html>

Note that because this output is placed into an IFrame and the applet is contained in the parent of the IFrame, the call to the applet’s methods must be prefaced with window.parent.

Figure 4 shows the returned results from a customer search.

Figure 4. A search panel displaying results passed from JavaScript (click to enlarge)

With this technique we can contain an entire application in one applet. Applet controls trigger server-side JSP pages which access the database and return results via JavaScript method calls. The applet shown in Figure 4 consists of a JTabbedPane and its included forms. The Customer Search tab has a JTable to display the results. The user fills in all or part of a last name and presses the Find button. The results are displayed back into the JTable without leaving the current web page. Users can sort and resize the columns of the JTable. Other tabs have forms for adding and updating customer records. The entire application is contained in two NetBeans projects (one for the applet, the other for the web application) in the URLEncoding folder of the attached code. Note that this application does not require any special privileges and does not need to be signed.

Using applets instead of HTML POST forms

The method described in the previous section performs the equivalent of an HTML GET operation. All data is encoded in the URL. Using the get method is not appropriate for all applications, however. Applications that have sensitive data or ones that would result in an encoded URL longer than 2048 characters (that is, the maximum length supported by some browsers) must be implemented using the post method. Communication between an applet and a servlet requires that the applet create an HTTPURLConnection with the web server. The process of creating the connection causes the web server to run the servlet. The HTTPURLConnection contains both an input and an output stream. These streams can then be used by the applet to transmit data to the servlet and receive data back from it.

To open a connection with a servlet, an applet first creates a URL, and then asks the URL to open the connection:

URL link = new URL(getCodeBase()+"FindCustomer"); // url of a servlet
HttpURLConnection urlconnection = (HttpURLConnection) link.openConnection();
Once the connection is open you should set its properties to provide two-way communications in binary mode.
urlconnection.setDoOutput(true);   // turn on output
urlconnection.setDoInput(true);     // turn on input
urlconnection.setUseCaches (false);   // turn off caching
urlconnection.setDefaultUseCaches (false);
// set to binary transmission
urlconnection.setRequestProperty ("Content-Type", "application/octet-stream");

At this point a standard input and output stream are available to the applet for communication with the servlet. Simply call the urlConnection.getOutputStream() or urlConnection.getInputStream() methods to access them. Depending on the needs of the applet, these streams can then be converted to ObjectInput/OutputStreams for object-oriented communication or DataInput/OutputStreams for transmitting primitives. I generally use ObjectInput/OutputStreams since they can perform all the functions of DataInput/OutputStreams:

ObjectOutputStream oos = new ObjectOutputStream(urlconnection.getOutputStream());
  ObjectInputStream ois = new ObjectInputStream(urlconnection.getInputStream());

Once the conversion is complete, the applet can use the output stream to transmit request parameters to the servlet and the input stream to read the data back. All data is transmitted directly between the applet and the servlet. No JavaScript or IFrames are required. Applet signing or special privileges are also not required because the applet is communicating with a servlet residing on its own web server.

The applet-side code presented in Listing 11 is invoked when the user presses the Find button on the Customer Search tab (shown in Figure 4).

Listing 11. Applet Find Customer method

/**
 *
 *  Find customers based on partial last name entered by the user
 * @param evt
 */
    private void findCustomerButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:


     try{
       DefaultTableModel tm = (DefaultTableModel)resultsTable.getModel();
       String lastName = searchField.getText();
       URL link = new URL(getCodeBase()+"FindCustomer");
       clearResults();
       setMessageLabel("Processing request ...");
       HttpURLConnection urlconnection = (HttpURLConnection) link.openConnection();

       urlconnection.setDoOutput(true);
       urlconnection.setDoInput(true);
       urlconnection.setUseCaches (false);
       urlconnection.setDefaultUseCaches (false);

       // Specify the content type that we will send binary data
       urlconnection.setRequestProperty ("Content-Type", "application/octet-stream");

       ObjectOutputStream oos = new ObjectOutputStream(urlconnection.getOutputStream());
       oos.writeObject(lastName);

       ObjectInputStream ois = new ObjectInputStream(urlconnection.getInputStream());
       while(true)
       {
        Customer c = (Customer)ois.readObject();
        if(c.id.length() == 0)  // empty id indicates last customer
             break;
        else
        {
         Object[] row = {c.id,c.firstName,c.lastName,c.address1,c.address2,c.city,c.state,c.zip,c.phone};
         tm.addRow(row);
        }
       }
       oos.close();
       ois.close();
       setMessageLabel(tm.getRowCount()+" records found");
     }
     catch(Exception ex)
     {
      setMessageLabel("Error processing request : "+ex.toString());
     }

}

With this method we create an HttpURLConnection and set it up for two-way binary communication. The connection is then turned into separate ObjectInputStream and ObjectOutputStreams. The applet method transmits the search text that the user had entered into a searchField. On the server side, the servlet sets the content type to binary and converts the streams to ObjectInputStream and ObjectOutputStream types. The search text is read in, an SQL Select operation is performed, and the resulting data is sent back one record at a time, encapsulated in a Customer object, as shown in Listing 12. Once the last record has been sent the servlet sends a Customer object with a 0 length ID, signaling the end of the data. The stream is then flushed and closed.

Listing 12. FindCustomer Servlet

/**
 *
 * @author Mark Pendergast
 */
@WebServlet(urlPatterns = {"/FindCustomer"})
public class FindCustomer extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * GET and
     * POST methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                   response.setContentType("application/octet-stream");

         InputStream in = request.getInputStream();
         ObjectInputStream inputFromApplet = new ObjectInputStream(in);
         OutputStream outstr = response.getOutputStream();
         ObjectOutputStream oos = new ObjectOutputStream(outstr);

         try {
           // response.setContentType("application/x-java-serialized-object");
             String lastName = (String)inputFromApplet.readObject();
            if(lastName == null)
                lastName = "";  // default to all

            Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  // load the driver
            Connection con = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=Customer;user=AppletTest;password=AppletTest;");
            PreparedStatement find = con.prepareStatement("select * from Customers where Last_Name like ?");
            find.setString(1, lastName+"%");
            ResultSet rs = find.executeQuery();
            while(rs.next())
            {
             Customer c = new Customer(rs.getString(1), rs.getString(3),rs.getString(2),rs.getString(4),
                               rs.getString(5),rs.getString(6),rs.getString(7),rs.getString(8), rs.getString(9));
             oos.writeObject(c);
            }
            rs.close();
            find.close();
            con.close();
          }
         catch(Exception ex)
         {
           System.out.println(ex.toString());
         }
         finally{
            Customer last = new Customer();
            oos.writeObject(last);  // customer with a blank id indicates the last one

            oos.flush();
        oos.close();

         }

    }

This approach should be appealing to hard-core Java programmers who prefer to avoid mixing Java, JavaScript, HTML, and CSS to create their applications, and to those of us who are frustrated with inconsistent implementations of JavaScript and HTML. Note that you may need to flush the streams to be sure data is sent in a timely manner.

What about directly accessing the database server?

The get and post techniques I’ve demonstrated do all of their database processing on the server side. It is also possible to build an applet that connects directly with a database server, in which case you could sidestep the web server altogether. Directly accessing a database server requires making a connection to a host other than the one the applet originated from. It also requires special permissions and/or JAR signing, something many users are (advisedly) wary of.

Another drawback of connecting an applet directly to a database server is access to the driver library files. The MS SQLServer driver (sqljdbc4.jar) is over 500K in size and is unlikely to have been installed on all the clients that access your applet. The choice is to either incorporate this JAR into your applets .jar, or force any visitors to your site to download the file and change their classpath to incorporate it. You might be able to make this work for an intranet application, but not for an internet application. Finally, Java bytecode in JAR files can be decompiled and viewed by any visitor to your site. This approach risks giving away too much information about the structure and access protocols of your database. If your goal is to eliminate the web server as middleman, then it is best to just create a standard Java desktop application and make it available via the web.

In conclusion

In this article I have demonstrated three useful applications of applets for web development. First I showed you how to use applets to create a multi-level menu system, then I demonstrated techniques for using applets in place of HTML forms for get and post operations. My examples included discussion about three Java classes — URLEncoder, AppletContext, and HTTPURLConnections — and their capabilities. All of the techniques demonstrated in this article are relatively secure; that is, none of them require that the applet be signed because none directly accesses a database. While I’ve walked through the examples, you’ll learn much more by studying the code in the article’s source file, which contains the following NetBeans projects:

  • MenuApplet demonstrates a simple News-Weather-Sports menu.
  • URLEncoding-Applet is a client-side applet demonstrating the URL encoding (Get) method
  • URLEncoding-JspPages uses server-side JSP pages to demonstrate the URL encoding (Get) method
  • ServletStreams-Applet is a client-side applet demonstrating the HTTPURLConnection (Post) method
  • ServletStreams-ServletPages uses servlets for the HTTPURLConnection (Post) method

Dr. Mark Pendergast is an associate professor at Florida Gulf Coast University and a returning JavaWorld contributor (see Resources). He received an MS and PhD from the University of Arizona and a BSE in electrical computer engineering from the University of Michigan. He has worked as an engineer for Control Data Corporation, Harris Corporation, Ventana Corporation, and taught at the University of Florida and Washington State University. His works have appeared in books and journals and he has presented his work at numerous conferences. He is a member of the ACM (Association for Computer Machinery) and IEEE (Institute of Electrical and Electronics Engineers) computer societies.