Article

Turning an Applet into a Standalone Application

 
 

Articles Index


Have you ever asked, "What is the difference between an applet and an application?" Or, "How do you turn an applet into a standalone application?" If so, then you are by no means alone; these questions are often asked, and the intention of this article is to help dispel the confusion behind these questions.

If you want to turn an applet into a standalone application, it helps to understand that there are two main differences between an applet and a full-blown application, and these differences are:

  • The Java language's applet class provides two major functions: a panel to contain other user interface components, and a set of APIs for accessing various resources. In a standalone application, you typically have a top-level Frame in which your main user-interface components reside; but with an applet, the top-level Frame is the browser.


  • Applets typically use a fairly restrictive security policy as implemented by the browser's Java Virtual Machine1 (JVM) Security Manager. In a standalone application, however, the security policy is usually more relaxed. This difference can get you into trouble when you attempt to create an applet from an existing application. If your application writes to the file system, for example, the applet's security policy will likely disallow this operation. This kind of security policy difference can many times break an application that is run as an applet. For a detailed explanation of applet security policies, see Frequently Asked Questions - Java Security. But, when running an applet as a standalone application, the Security Manager usually doesn't present as many obstacles.

So how do you go about converting an applet into a standalone application? For example, say you've written a nifty applet and you want users within your organization to be able to run it from outside a browser. The process is fairly simple.

You have two choices for making your applet run standalone: one is a design change and the other is a configuration change.

Redesigning or Rearchitecting?

Typically, an applet can avoid having too much of the program's logic and user interface components within your extended applet class. If you've written your program in such a way that the applet class is used as a wrapper for another class that does most of the work, then it's fairly easy to run the program standalone. Just create your own 'standalone wrapper'.

For example, in the following applet, the logic and user interface components are part of the applet.


public class MyApplet extends Applet {   
  private Button _myButton;

  public void init() {     
    _myButton = new Button (getParameter (
                        "label"));     
    _myButton.addActionListener ( 
      new AbstractAction () {         
        public void actionPerformed (
                      ActionEvent event) {
          Frame f = new Frame("Frame");           
          f.pack();           
          f.show();         
        }       
      }     
    );     
    add (_myButton);   
  } 
}

If you remove the logic and components from the applet and put them into some other class, you've got a program that is much easier to run standalone.


public class MyA
public class MyUI extends Panel {   
  private Button _myButton;

  public MyUI (String label)   {     
    _myButton = new Button (label);     
    _myButton.addActionListener (       
      new AbstractAction () {         
        public void actionPerformed (
                  ActionEvent event) {           
          Frame f = 
           new Frame("Frame");           
          f.pack();           
          f.show();         
        }     
      }
    );     
    add (_myButton);   
  } 
}

To make the program into an applet, just provide an applet wrapper as shown below:


public class MyApplet extends Applet {   
  private MyUI _ui;

  public void init() {     
    _ui = new MyUI ("Push Me");     
    add (_ui);   
  } 
}

To make the program run standalone, you simply create a different wrapper, as in the following example:



public class MyApplication extends Frame {   
  private MyUI _ui;

  private MyApplication(String label) {
    _ui = new MyUI (label);     
    add ("Center", _ui);   
  }

  static public void main (String argv[]) {     
    MyApplication a = new MyApplication (
                      "Push Me");
    a.pack();     
    a.show();   
  } 
}

This technique is great to use especially if you're just starting your project and haven't created an applet yet. In some cases you can easily modify your existing applet as shown above, but sometimes this can cause too much work, in which case you might consider using AppletStub, described in the next section.

Making a Configuration Change with AppletStub

If rearchitecting isn't your idea of fun, another way to run your applet standalone, without changing any existing code, is to create an AppletStub! The AppletStub class is created for you by the browser each time an applet is loaded. The AppletStub contains most of the information you need when the applet is loaded and started by the browser.

A simple standalone implementation of the AppletStub needs to do the following:

  • Parse parameters from the command line
  • Return correct values for getCodeBase() and getDocumentBase()
  • Provide implemetation for other required methods

Once you've created your AppletStub implementation, you can hook it to your applet by providing a static main method in your applet's list of methods. Here is a sample AppletStub implementation called MyAppletStub:



public class MyAppletStub implements AppletStub {
  private Hashtable _properties;
  private Applet _applet;

/**
 * Creates a new MyAppletStub instance and initializes 
 * thei nit parameters from the command line.
 * Arguments are passed in as name=value pairs.
 * Reading the command line arguments can be made more
 * sophisciated depending on your needs, but the basic
 * idea will likely remain the same.
 * Also, this particular implementation doesn't deal
 * very well with invalid name=value pairs.
 * 
 * @param argv[] Command line arguments passed to Main
 * @param an Applet instance.
 */
  public MyAppletStub (String argv[ 
                          ], Applet a) {
    _applet = a;
    _properties = new Hashtable();
    for ( int i = 0; i *lt; argv.length; i++ ) {
      try {
        StringTokenizer parser = 
         new StringTokenizer (
          argv[i], "=");
        String name = parser.nextToken(
                        ).toString();
        String value = parser.nextToken(
           "\"").toString();
        value = value.substring(1);
        _properties.put (name, value);
      } catch (NoSuchElementException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * Calls the applet's resize
   * @param width
   * @param height
   * @return void
   */
  public void appletResize (
     int width, int height) {
    _applet.resize (width, height);
  }

  /**
   * Returns the applet's context, which is 
   * null in this case. This is an area where more
   * creative programming
   * work can be done to try and provide a context
   * @return AppletContext Always null
   */ 
  public AppletContext getAppletContext () {
    return null;
  }

  /**
   * Returns the CodeBase. If a host parameter
   * isn't provided
   * in the command line arguments, the URL is based
   * on InetAddress.getLocalHost(). 
   * The protocol is "file:"
   * @return URL
   */
  public java.net.URL getCodeBase() {
    String host;
    if ( (host=getParameter (
      "host")) == null ) {
      try {
        host = InetAddress.getLocalHost(
                        ).getHostName();
      } catch (UnknownHostException e) {
        e.printStackTrace();
      }
    }
      
    java.net.URL u  = null;
    try {
      u = new java.net.URL (
       "file://"+host);
    } catch (Exception e) { }
    return u;
  }

  /**
   * Returns getCodeBase
   * @return URL
   */
  public java.net.URL getDocumentBase() {
    return getCodeBase();
  }

  /**
   * Returns the corresponding command line value
   * @return String
   */
  public String getParameter (
                    String p) {
    return (String)_properties.get (p);
  }

  /**
   * Applet is always true
   * @return boolean True
   */
  public boolean isActive () {
    return true;
  }
}

To use this stub, add a main method to your applet. For the example given above, the new MyApplet will be as follows:


public class MyApplet extends Applet {   
  private Button _myButton;

  public void init() {     
    _myButton = new Button (getParameter (
                      "label"));     
    _myButton.addActionListener ( 
      new AbstractAction () {         
        public void actionPerformed (
                  ActionEvent event) {
          Frame f = new Frame(
                   "Frame");           
          f.pack();           
          f.show();         
        }       
      }     
    );     
    add (_myButton);   
  } 

  static public void main (String argv[]) {
    final Applet applet = new MyApplet();
    System.runFinalizersOnExit(true);
    Frame frame = new Frame (
                 "MyApplet");
    frame.addWindowListener (
                  new WindowAdapter()
    {
      public void windowClosing (
                   WindowEvent event)
      {
        applet.stop();
        applet.destroy();
        System.exit(0);
      }
    });
    frame.add (
      "Center", applet);
    applet.setStub (new MyAppletStub (
         argv, applet));
    frame.show();
    applet.init();
    applet.start();
    frame.pack();
  }
    
}

The AppletStub technique is easier to do than rearchitecting, but may still not work completely if your applet depends on the AppletContext for anything. However, in many cases, this technique is an easy way to make your applets run standalone.

Tony Squier is a JDC tools engineer. He developed the JDC registration-management code. He invites any feedback you have about the article or the code, such as enhancements or potential bugs. If you have comments please send them to: Tony Squier

_______
1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

Oracle is reviewing the Sun product roadmap and will provide guidance to customers in accordance with Oracle's standard product communication policies. Any resulting features and timing of release of such features as determined by Oracle's review of roadmaps, are at the sole discretion of Oracle. All product roadmap information, whether communicated by Sun Microsystems or by Oracle, does not represent a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. It is intended for information purposes only, and may not be incorporated into any contract.