Applicet Framework for Applets and Applications v2.03

Applicet Framework overview
The Applicet Framework for Applets and Applications gives full support for running applets as applications, by replacing either java.applet.Applet as superclass with be.arci.applet.Applicet for AWT applets, or java.swing.JApplet as superclass with be.arci.applet.JApplicet for Swing applets.

See:
          Description

Packages
be.arci.applet This package contains the Applicet Framework for Applets and Applications; additional helper classes can be found in the be.arci.pub package.
be.arci.pub Supplies some add-on classes and Browser implementations for the Applicet Framework for Applets and Applications, together with their source code.
edu.stanford.ejalbert Contains Eric Albert's BrowserLauncher, which is delegated to from the EricAlbertBrowser implementation of the Browser interface for handling calls to showDocument in an Applicet application's AppletContext.

 

Applicet Framework overview


The Applicet Framework for Applets and Applications gives full support for running applets as applications, by replacing either java.applet.Applet as superclass with be.arci.applet.Applicet for AWT applets, or java.swing.JApplet as superclass with be.arci.applet.JApplicet for Swing applets.

Overview Contents

  1. Introduction
  2. Programming an Applicet
  3. Running an Applicet application
  4. Packaging your Applicet classes and resources
  5. Internationalization support
  6. Viewing HTML documents
  7. Animation

Related Documents

  1. Introduction
  2. It is popular belief that all you have to do to run an applet as application is to add a main() method calling init() and start() on your applet instance. But why then are there so few applets that run as an application as well? The answer is simple: while the simple main() method might be enough for very basic applets, it is not at all the case for most (if not all) usefull applets. About anything an applet needs apart from it's own canvas to draw on, it'll have to ask for from it's AppletStub and it's AppletContext.

    The Applicet Framework gives Applicet applications the necessary implementations of the java.applet.AppletStub and java.applet.AppletContext interfaces that are needed to run an applet as application without changing any code, and without having to branch on switches you maintain to distinguish between both execution environments. Additional benefits are uniform support for retrieving resources as Image, AudioClip, URL or Inputstream, even across application environments, Web browsers and packaging options. And last but not least, the Applicet Framework makes internationalization of your applet/application trivial.

    Note: In this and other documents we'll say 'Applicet applet' or 'Applicet application' whenever there is a difference between running as an applet and running as an application. But really it is the same program. We will also only make the distinction AWT Applicet versus Swing JApplicet when there is need for it.

  3. Programming an Applicet
  4. To use the Applicet Framework for Applets and Applications, all you need to do is extend be.arci.applet.Applicet instead of java.applet.Applet (or be.arci.applet.JApplicet instead of javax.swing.JApplet for Swing applets), and implement a simple main method as described in what follows. This doesn't change anything to running as an applet, though you could profit from Applicet's easier resource handling and internationalization support.

    The main method in the class that you will use to start as application (probably the Applicet subclass itself), has to instantiate (construct) the Applicet, and invoke runAsApplication() on it, as described below. In fact, we successfully converted many existing applets to applications by just changing the extends clause and adding a single-line main():
    import be.arci.applet.*;

    public class MyApplicet extends Applicet { //extends JApplicet for Swing applets

        public static void main(String[] args) {
            Applicet myApplicet = new MyApplicet().runAsApplication(args);
        }
        ...
    }

    The method runAsApplication(String[] args) does the same for an Applicet application, as the webbrowser does for an applet. It also reads parameters from the args commandline arguments and from default .properties files, just the same parameters a browser would read from the HTML document containing the same Applicet as applet. You must invoke this method exactly once on the Applicet application instance, preferrably as first method after construction. Typically you will invoke runAsApplication() from the static void main(String[] args) method that you must define to run an application, but you might as well call it from the constructor code itself. Do not ever invoke runAsApplication() from the parameterless constructor of your Applicet subclass, for that constructer is used for as-Applet construction by browsers!

    The Applicet class has three different signatures for runAsApplication():

    runAsApplication(String[] args)
    creates a java.awt.Frame to hold the Applicet application (remember that as AWT components java.applet.Applet, and hence be.arci.applet.Applicet, are just implementations of java.awt.Panel), and will activate the Applicet, including calling it's init() and start() methods, if any. Calling runAsApplication(args) is equivalent to runAsApplication(args, true).
    runAsApplication(String[] args, boolean swSetActive)
    If swSetActive == true this is equivalent to runAsApplication(String[] args). If false the method will return after creating the java.awt.Frame and doing all other setup, but without starting up the Applicet; this allows you to do some more customization before calling ((Applicet.Context)getAppletContext()).setActive(true) to activate your Applicet yourself and set it's Frame visible. When the Frame is closed by the user, the Applicet application is de-activated, including calling it's stop() and destroy() methods, and System.exit(0) is called. Calling runAsApplication(args, swSetActive) is equivalent to runAsApplication(args, swSetActive, true, null).
    runAsApplication(String[] args, boolean swSetActive, boolean swCreateFrame, String sName)
    If swCreateFrame is true, this is equivalent to runAsApplication(args, swSetActive) (apart from the sName argument). If false, you have to host the Applicet application panel in your own Container and take care of calling ((Applicet.Context)getAppletContext()).setActive(false) and System.exit() at the appropriate time (even if after all you add the Applicet application to a Frame created by createFrame() or getFrame()). This signature allows to start and init multiple Applicet applications as needed, together in the same JVM, and stopping each of them while keeping the others alive. The sName argument allows to retrieve the different Applicet applications by name (via getAppletContext().getApplet(String sName)) for intra-Applicet communication.

    Here are some minimal examples:
    import be.arci.applet.*;

    public class MyApplicet extends Applicet { //extends JApplicet for Swing applets
        //needed to start as an application
        public static void main(java.lang.String[] args) {
            //you shouldn't do much work in an Applet's
            //constructor; do it in init() instead
            new MyApplicet().runAsApplication(args);
        }
     ...
    }
    or, if you want to override some defaults:
    import be.arci.applet.*;

    public class MyApplicet extends Applicet { //extends JApplicet for Swing applets
        //needed to start as an application
        public static void main(java.lang.String[] args) {
            //you shouldn't do much work in an Applet's
            //constructor; do it in init() instead
            MyApplicet myApplicet = new MyApplicet();
            //optional, the default title is "MyApplicet"
            myApplicet.getParentFrame().setTitle("my title");
            //optional, the default icon is
            //my.package.MyApplicet.gif (or .jpg), if found
            Image icon = myApplicet.getImage"myicon.gif");
            myApplicet.getParentFrame().setIconImage(icon);
            myApplicet.runAsApplication(args);
        }
     ...
    }
    You might want to override getPreferredSize() to lock the initial size of your Applicet application. We strongly suggest that you also implement (as you would for any other decent Applet) the methods getAppletInfo(), which forms the default status line text, and above all getParameterInfo(). Whereas for plain applets the method getParameterInfo() is rarely used, for Applicets it definitely is very useful. First, getParameterInfo() provides the parameter names that can be abbreviated (see above) with command line invocation. Second, getParameterInfo() is called for getting the information displayed in the default help dialog (see also Applicet.Context.showUsage(String sMessage, boolean swExit) or JApplicet.Context.showUsage(String sMessage, boolean swExit)).

  5. Running an Applicet application
  6. An Applicet application is normally put into a frame by runAsApplication(). The following defaults are assumed, but can be overridden as described:

    Parameter names in .properties files should have a "param." prefix, to distinguish them from possible other properties (like localized user messages).

    Parameter names can be defined in the return value of getParameterInfo(). If they are, Applicet's application stub expands commandline parameter name abbreviations (not those in .properties files) to the full parameter name. If an abbreviation is ambiguous, a usage dialog is displayed and the Applicet application exits.

    All attributes of the <APPLET> tag are reserved parameter names (and can also be abbreviated) (also see the HTML APPLET tag description). Of these currently the following are used in Applicet applications:

    WIDTH = pixels or percent% and
    HEIGHT = pixels or percent%
    set the preferred size of the Applicet application; the default value used for each unspecified dimension is half the screensize. Percentage values are interpreted as percentage of screensize. Values <= 0 are ignored. The preferred size is used to dimension the Frame in which the Applicet application is placed. You can for example lock the preferred size by overriding getPreferredSize(). The default Applicet application Frame is resizable, unlike an applet in a browser; you can cancel this with getParentFrame().setResizable(false).
    Note: If your Applicet requires percentage values, you should consider putting them in a .properties parameter file: some operating systems (we have nothing against Windows) have a special treatment of the commandline if they see 2 '%' characters.
    ALIGN = alignment
    Specifies the alignment of the Applicet application Frame with the screen. The possible values of this attribute are different from those for the HTML <APPLET> tag ALIGN attribute, as an application Frame lacks the concept of a 'current line of text'. The possible alignment values for Applicet applications are: left, right, bottom, topleft (== lefttop), topright (== righttop), bottomleft (== leftbottom), bottomright (== rightbottom) and middle (which is the default). Other values are ignored. The default Applicet application Frame can be moved around the screen, unlike an applet in a browser.
    DOCUMENTBASE = documentURL
    The equivalent of the HTML document that normally contains the Applet. If this parameter is not specified, then the user directory is used. Applicet uses this parameter as return value of getDocumentBase().
    CODEBASE = codebaseURL
    The equivalent of the CODEBASE attribute in an <APPLET> tag in an HTML document. Specifies the base URL of the applet (the directory that contains the Applicet's executable code). If this attribute is not specified, then the documentURL is used. Applicet uses this parameter as return value of getCodeBase().
    ARCHIVE = jarfilelist
    jarfile list is a comma-separated list of .jar filenames that are searched in left-to-right order for resources like images and sound. For Applicet applications this is not yet implemented ; use a jarfile as CODEBASE when you distribute (part of) your Applicet application in a jarfile. For Applicet applets it is the browser's VM that will handle this <APPLET>-tag attribute (but a.o. Netscape 4.5 does not handle multiple jarfiles).

    The NAME = applicetInstanceName attribute is replaced by the String sName argument of runAsApplication, as applet naming serves intra-applet communication, and you wouldn't want users interfere with that. Other parameters supplied to the Applicet application are the equivalent of the <PARM NAME = "" VALUE = ""> tags in an HTML document for the Applicet applet.

    Parameter help (see also Applicet.Context.showUsage(String sMessage, boolean swExit) or JApplicet.Context.showUsage(String sMessage, boolean swExit)) is displayed in a Dialog and in the eventual console window if either

    Parameter help is not shown when a parameter cannot be matched to a parameter named by the return value of getParameterInfo(); this allows for the use of 'hidden' parameters , as well as for the omission of getParameterInfo() (fie!).

    In the current implementation the default parent Frame (or JFrame's contentpane for Swing applicets) has the BorderLayout, with your Applicet at BorderLayout.CENTER and a status field at BorderLayout.SOUTH; don't count on this layout to remain that way though (you have no control over it for an applet in a webbrowser either).

  7. Packaging your Applicet classes and resources
  8. We suggest you use Applicet's methods to retrieve an Image, AudioClip or other resource content by relative filename (String), rather than by the equivalent java.applet.Applet methods that require you to construct an appropriate URL. When going the Applicet way you can choose to

    You don't have to change a single line of code for it, and it'll run in Netscape and MS Internet Explorer (locally or from a website), or locally as application (or even with AppletViewer).

    The following files have to be included in your package:

    1. AWT-based user interface
      (*) File sizes for Production version without line numbers. Evaluation version sizes will be larger.
      Files to include in distribution Approx. jarred size(*) Applicet applet Applicet application Both
      Basic (incl. sound by URL) Sound by name I18N Basic (incl. I18N) Sound by URL or name show HTML Parameter conveniences
      be / arci / applet / Framework.class 0.3kB X X X X X X X
      be / arci / applet / Applicet.class 3.5kB X X X X X X X
      be / arci / applet / HFile.class
      (some environments do not require this file)
      0.1kB X X X X X X X
      be / arci / applet / Applicet_xx.properties n.a. - - - X X X X
      be / arci / applet / AudioClipFactory.class 0.8kB - X - - X - -
      be / arci / applet / FallbackAudioClip.class 0.6kB - X - - X - -
      be / arci / applet / I18NDelegate.class 2.0kB - - X X X X X
      be / arci / applet / Applicet $ Brethren.class 0.7kB - - - X X X X
      be / arci / applet / Applicet $ Context $ Destroyer.class 0.4kB - - - X X X X
      be / arci / applet / Applicet $ Context $ Disposer.class 0.4kB - - - X X X X
      be / arci / applet / Applicet $ Context.class 3.1kB - - - X X X X
      be / arci / applet / Applicet $ Stub.class 2.2kB - - - X X X X
      be / arci / applet / Browser.class 0.2kB - - - X - - -
      be / arci / applet / DummyBrowser.class 0.4kB - - - - - X -
      be / arci / pub / ExecBrowser.class +
      be / arci / pub / ExecBrowser.properties
      1.3kB - - - - - Opt. -
      be / arci / pub / SwingBrowser.class 1.5kB - - - - - Opt. -
      be / arci / pub / EricAlbertBrowser.class +
      edu / stanford / ejalbert / BrowserLauncher.class
      3.6kB - - - - - Opt. -
      be / arci / pub / ColorParameter.class 0.7kB - - - - - - Opt.
      be / arci / pub / ParameterParser.class 1.1kB - - - - - - Opt.
    2. Swing-based user interface
      (*) File sizes for Production version without line numbers. Evaluation version sizes will be larger.
      Files to include in distribution Approx. jarred size(*) JApplicet applet JApplicet application Both
      Basic (incl. sound by URL) Sound by name I18N Basic (incl. I18N) Sound by URL or name show HTML Parameter conveniences
      be / arci / applet / Framework.class 0.3kB X X X X X X X
      be / arci / applet / JApplicet.class 3.5kB X X X X X X X
      be / arci / applet / HFile.class
      (some environments do not require this file)
      0.1kB X X X X X X X
      be / arci / applet / Applicet_xx.properties n.a. - - - X X X X
      be / arci / applet / AudioClipFactory.class 0.8kB - X - - X - -
      be / arci / applet / FallbackAudioClip.class 0.6kB - X - - X - -
      be / arci / applet / I18NDelegate.class 2.0kB - - X X X X X
      be / arci / applet / JApplicet $ Brethren.class 0.6kB - - - X X X X
      be / arci / applet / JApplicet $ Context $ Destroyer.class 0.3kB - - - X X X X
      be / arci / applet / JApplicet $ Context $ Disposer.class 0.3kB - - - X X X X
      be / arci / applet / JApplicet $ Context.class 3.3kB - - - X X X X
      be / arci / applet / JApplicet $ Stub.class 2.2kB - - - X X X X
      be / arci / applet / Browser.class 0.2kB - - - X - - -
      be / arci / applet / DummyBrowser.class 0.4kB - - - - - X -
      be / arci / pub / ExecBrowser.class +
      be / arci / pub / ExecBrowser.properties
      1.3kB - - - - - Opt. -
      be / arci / pub / SwingBrowser.class 1.5kB - - - - - Opt. -
      be / arci / pub / EricAlbertBrowser.class +
      edu / stanford / ejalbert / BrowserLauncher.class
      3.6kB - - - - - Opt. -
      be / arci / pub / ColorParameter.class 0.7kB - - - - - - Opt.
      be / arci / pub / ParameterParser.class 1.1kB - - - - - - Opt.

  9. Internationalization support
  10. Because internationalization (I18N) of applets, spite Java's facilities for it, is so often overlooked, we decided to make it even easier to acomplish for Applicet subclasses. You can view some examples on our websites, where we provided (within our multilingual limitations) some applicets that automatically switch between English, French, German and Dutch, depending on the user's language.

    Applicet supports easy internationalization with the get/setI18Nxxx class of methods. All you have to do now to make international multi-lingual applets and applications is the following:

    1. give all user message Strings a name, and put them in a file MyApplicet.properties as name = message pairs (where MyApplicet, as usual, is the qualified name of your Applicet subclass).
    2. replace all hard-coded user message Strings by getI18NString(name). There are also convenient I18N methods for localizing String arrays and for formatting Objects according to a localized MessageFormat pattern.
    3. You can now simply add new languages (locales) without reprogramming: e.g. for spanish, just put the message translations in a file MyApplicet_es.properties. You can even ask your international users to do this for you, via a mailform on your website, for all they need for the translation is the original (well documented) MyApplicet.properties file.

    The execution environment itself will determine the language your user works in, enabling Applicet to display the appropriate set of messages. If a language is not found, or a single message is not translated, Applicet will use the original language message as a fallback.

    Popular browsers (at the time of writing) still use a crippled implementation of java.util.ResourceBundle, that stumbles over its own feet when trying to retrieve a .properties files with the same basename as a .class file. Therefor Applicet resorts to direct support of I18N sets of .properties files, at the same time taking out some of the stingy parts of ResourceBundles. Applicet uses the default locale, and as basename the Applicet subclass name, for retrieving the default I18N set of .properties files used by getI18NString(String) etc. The default locale can be changed with setLocale(Locale), and retrieved by getLocale() (see java.awt.Component.setLocale() and java.applet.Applet.getLocale()). If this is not of your liking, you can retrieve a specific I18N set with the getI18NSet() methods and use setI18NDefault() to install it as default for getI18NString() etc.

    The process for getting from a basename and a Locale to an I18N set is largely the same as with ResourceBundle. If the environment's default locale is l1_C1_v1 (language, country and variant), and l2_C2_v2 the locale to use for the I18N set, that I18N set is built as follows. :

    with lower levels supplying the defaults for messages/properties that do not occur at higher levels. (Note that in earlier JDK's the javadoc for java.util.Resourcebundle is wrong on this hierarchy; we implemented it as it is programmed).

    With getI18NDefault() you can retrieve the resulting Properties instance for direct manipulation. With getI18NSet(String,Locale) you can also directly retrieve a differently named I18N set of .properties files directly, without influencing the default set used by getI18NString(String) etc.

    TIP: You can test your Applicet application for different locales by passing language and/or country as parameters to the java program. As an example for french Canadian :

        java -Duser.language=fr -Duser.region=CA MyApplicet
    

    You can also do the same for testing it as an applet with the AppletViewer:

        appletviewer -J-Duser.language=fr -J-Duser.region=CA MyApplicetDocument.html
    

    Doing the same in a Windows.x webbrowser requires changing the operating system's locale settings and rebooting.

    For completeness, we repeat the Java 2 (JDK13) description of .properties file syntax here

  11. Viewing HTML documents
  12. The concept of showDocument() in an Applicet application is quite different from that in an Applicet applet: an applet is 'hosted' by a webpage document, while an application is running free of any document context.

    As a consequence an applet calling showDocument() may cause it's hosting document to be replaced by another document, implicating that the applet itself is stopped and hidden (and possibly a new instance of it created and started in the new document). That is why applets will often use the target argument in showDocument().

    This is not the case for an Applicet application; the most common use of showDocument() in Applicet applications will probably be to display nicely formatted user information, or even application-generated HTML content, without affecting the running Applicet application. Also Applicet applet showDocument() calls will typically be made while connected to the Internet, whereas this may not be so when the Applicet application calls showDocument().

    An Applicet application's AppletContext (Applicet.Context) delegates the display of documents (showDocument(URL urlDocument, String sTarget)) to an implementation of the Browser interface, that can be set by a call to (Applicet.Context)getAppletContext())setBrowser(Browser). The default Browser implementation is DummyBrowser, that does nothing at all; a few other implementation examples, with source code, are provided in the package be.arci.pub. A Browser implementation is free to ignore sTarget (just as it is free to ignore the complete showDocument() request).

    The difference in execution environment for Applicet applets and applications may leed to the need to display different documents; the method isApplication() may be of use here. Anyway (but depending on the actual Browser implementation you use), if String sDocument represents a path to a document relative to the Applicet's documentbase, both Applicet applet and Applicet application will be able to display the same document with the same method call as such:

    //executing somewhere in the Applicet subclass code
    String sDocument = "mypath/mydocument.html";
    URL urlDocument = new URL(getDocumentBase(), sDocument);
    getAppletContext().showDocument(urlDocument);
    

  13. Animation
  14. (applies to plain Applet as well)
    Any animation or other non-interactive stuff should run in a seperate Thread, instead of in the start() method. The reason is that Browsers and appletViewers usually do not paint your Applicet (or Applet) until after you returned from it's start() method.
    Example of running in a separate Thread:
    public class MyAnimation 
                 extends 
    Applicet  // extends JApplicet for Swing applets
                 implements Runnable
    {
    //---extends Applicet---------------------
    //...see above examples
    Thread thrAnimation;
    //Start the Applet by forking an animation thread.
    public void start()
    {
     super.start();
     //do your stuff
     thrAnimation = new Thread(this);
     thrAnimation.start();//start the animation thread and return
    }
    //if you do override Applicet.stop(), do it as follows:
    public void stop()
    {
     thrAnimation = null;//will falsify run()'s while-condition.
     //You might want to implement a piece of code to wait
     //till the running thread actually stopped.
     super.stop();
     //do your stuff
    }
    //---implements Runnable------------------
    public void run()
    {
     Thread thrCurrent = Thread.currentThread();
     while (thrCurrent == thrAnimation)
     {
      //do your stuff, followed by e.g.:
      try Thread.currentThread().sleep(1000)}
      catch (InterruptedException e) { }
     }

.


Applicet Framework for Applets and Applications v2.03