Program: AppletViewer

Another JDK tool that can be replicated is the AppletViewer. This uses the reflection package to load a class that is subclassed from Applet, instantiate an instance of it, and add( ) this to a frame at a given size. This is a good example of reflection in action: you can use these techniques to dynamically load any subclass of a given class. Suppose we have a simple applet like the HelloApplet in Example 25-11.

Example 25-11. HelloApplet.java

import java.applet.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

/**
 * HelloApplet is a simple applet that toggles a message
 * when you click on a Draw button.
 */
public class HelloApplet extends JApplet {

    /** The flag which controls drawing the message. */
    protected boolean requested;

    /** init(  ) is an Applet method called by the browser to initialize */
    public void init(  ) {
        JButton b;
        requested = false;
        Container cp = (Container)getContentPane(  );
        cp.setLayout(new FlowLayout(  ));
        cp.add(b = new JButton("Draw/Don't Draw"));
        b.addActionListener(new ActionListener(  ) {
            /*  Button - toggle the state of the "requested" flag, to draw or
             *  not to draw.
             */
            public void actionPerformed(ActionEvent e) {
                String arg = e.getActionCommand(  );
                // Invert the state of the draw request.
                requested = !requested;
                do_the_work(  );
            }
        });
    }

    /** paint(  ) is an AWT Component method, called when the 
     *  component needs to be painted.
     */
    public void do_the_work(  ) {
        /* If the Draw button is selected, draw something */
        if (requested) {
            showStatus("Welcome to Java!");
        } else {
            showStatus("");    // retract welcome? :-)
        }
    }
}

If we run it in my AppletViewer,[58] it shows up as a window with just the Draw button showing; if you press the button an odd number of times, the screen shows the welcome label (Figure 25-2).

My AppletViewer showing simple applet

Figure 25-2. My AppletViewer showing simple applet

Example 25-12 is the code for the main part of the AppletViewer, which creates a JFrame, and then loads the Applet class dynamically and adds it to the JFrame.

Example 25-12. AppletViewer.java main program

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;

/*
 * AppletViewer - a simple Applet Viewer program.
 */
public class AppletViewer {
    /** The main Frame of this program */
    JFrame f;
    /** The AppletAdapter (gives AppletStub, AppletContext, showStatus) */
    static AppletAdapter aa = null;
    /** The name of the Applet subclass */
    String appName = null;
    /** The Class for the actual applet type */
    Class ac = null;
    /** The Applet instance we are running, or null. Can not be a JApplet
     * until all the entire world is converted to JApplet. */
    Applet ai = null;
    /** The width of the Applet */
    final int WIDTH = 250;
    /** The height of the Applet */
    final int HEIGHT = 200;

    /** Main is where it all starts. 
     * Construct the GUI. Load the Applet. Start it running.
     */
    public static void main(String[] av) {
        new AppletViewer(av.length==0?"HelloApplet":av[0]);
    }

    /** Construct the GUI for an Applet Viewer */
    AppletViewer(String appName) {
        super(  );

        this.appName = appName;

        f = new JFrame("AppletViewer");
        f.addWindowListener(new WindowAdapter(  ) {
            public void windowClosing(WindowEvent e) {
                f.setVisible(false);
                f.dispose(  );
                System.exit(0);
            }
        });
        Container cp = f.getContentPane(  );
        cp.setLayout(new BorderLayout(  ));

        // Instantiate the AppletAdapter which gives us
        // AppletStub and AppletContext.
        if (aa == null)
            aa = new AppletAdapter(  );

        // The AppletAdapter also gives us showStatus.
        // Therefore, must add(  ) it very early on, since the Applet's
        // Constructor or its init() may use showStatus(  )
        cp.add(BorderLayout.SOUTH, aa);

        showStatus("Loading Applet " + appName);

        loadApplet(appName , WIDTH, HEIGHT);    // sets ac and ai
        if (ai == null)
            return;

        // Now right away, tell the Applet how to find showStatus et al.
        ai.setStub(aa);

        // Connect the Applet to the Frame.
        cp.add(BorderLayout.CENTER, ai);

        Dimension d = ai.getSize(  );
        d.height += aa.getSize(  ).height;
        f.setSize(d);
        f.setVisible(true);        // make the Frame and all in it appear

        showStatus("Applet " + appName + " loaded");

        // Here we pretend to be a browser!
        ai.init(  );
        ai.start(  );
    }

    /*
     * Load the Applet into memory. Should do caching.
     */
    void loadApplet(String appletName, int w, int h) {
        // appletName = ... extract from the HTML CODE= somehow ...;
        // width =         ditto
        // height =         ditto
        try {
            // get a Class object for the Applet subclass
            ac = Class.forName(appletName);
            // Construct an instance (as if using no-argument constructor)
            ai = (Applet) ac.newInstance(  );
        } catch(ClassNotFoundException e) {
            showStatus("Applet subclass " + appletName + " did not load");
            return;
        } catch (Exception e ){
            showStatus("Applet " + appletName + " did not instantiate");
            return;
        }
        ai.setSize(w, h);
    }

    public void showStatus(String s) {
        aa.getAppletContext(  ).showStatus(s);
    }
}

For Applet methods to work, two additional classes must be defined: AppletStub and AppletContext. The AppletStub is the tie-in between the applet and the browser, and the AppletContext is a set of methods used by the applet. Although in a real browser they are probably implemented separately, I have combined them into one class (see Example 25-13). Note that the scope of applets that will work without throwing exceptions is rather limited, since so many of the methods here are at present dummied out. This AppletViewer is not a full replacement for Sun’s AppletViewer; it has only been tested with a basic Hello World applet, and is simply provided as a starting point for those who want to fill in the gaps and make a full-blown applet viewer program.

Example 25-13. AppletAdapter.java, partial AppletStub and AppletContext

import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import java.util.*;

/*
 * AppletAdaptor: partial implementation of AppletStub and AppletContext.
 *
 * This code is far from finished, as you will see.
 *
 */
public class AppletAdapter extends Panel implements AppletStub, AppletContext {
    /** The status window at the bottom */
    Label status = null;

    /** Construct the GUI for an Applet Status window */
    AppletAdapter(  ) {
        super(  );

        // Must do this very early on, since the Applet's
        // Constructor or its init() may use showStatus(  )
        add(status = new Label(  ));

        // Give "status" the full width
        status.setSize(getSize().width, status.getSize(  ).height);

        showStatus("AppletAdapter constructed");    // now it can be said
    }

    /****************** AppletStub ***********************/
    /** Called when the applet wants to be resized.  */
    public void appletResize(int w, int h) {
        // applet.setSize(w, h);
    }

    /** Gets a reference to the applet's context.  */
    public AppletContext getAppletContext(  ) {
        return this;
    }

    /** Gets the base URL.  */
    public URL getCodeBase(  ) {
        return getClass(  ).getResource(".");
    }

    /** Gets the document URL.  */
    public URL getDocumentBase(  ) {
        return getClass(  ).getResource(".");
    }

    /** Returns the value of the named parameter in the HTML tag.  */
    public String getParameter(String name) {
        String value = null;
        return value;
    }
    /** Determines if the applet is active.  */
    public boolean isActive(  ) {
        return true;
    }

    /************************ AppletContext ************************/

    /** Finds and returns the applet with the given name. */
    public Applet getApplet(String an) {
        return null;
    }

    /** Finds all the applets in the document */
    public Enumeration getApplets(  )  {
        class AppletLister implements Enumeration {
            public boolean hasMoreElements(  ) {
                return false;
            }
            public Object nextElement(  ) {
                return null;
            }
        }
        return new AppletLister(  );
    }

    /** Create an audio clip for the given URL of a .au file */
    public AudioClip getAudioClip(URL u) {
        return null;
    }

    /** Look up and create an Image object that can be paint(  )ed */
    public Image getImage(URL u)  {
        return null;
    }

    /** Request to overlay the current page with a new one - ignored */
    public void showDocument(URL u) {
    }

    /** as above but with a Frame target */
    public void showDocument(URL u, String frame)  {
    }

    /** Called by the Applet to display a message in the bottom line */
    public void showStatus(String msg) {
        if (msg == null)
            msg = "";
        status.setText(msg);
    }
}

It is left as an exercise for the reader to implement getImage( ) and other methods in terms of other recipes used in this book.

See Also

We have not investigated all the ins and outs of reflection or the ClassLoader mechanism, but I hope I’ve given you a basic idea of how it works.

Perhaps the most important omissions are SecurityManager and ProtectionDomain. Only one SecurityManager can be installed in a given instance of JVM (e.g., to prevent a malicious applet from providing its own!). A browser, for example, provides a SecurityManager that is far more restrictive than the standard one. Writing such a SecurityManager is left as an exercise for the reader, but an important exercise for anyone planning to load classes over the Internet! (For more information about security managers and the Java Security APIs, see O’Reilly’s Java Security, by Scott Oaks.) A ProtectionDomain can be provided with a ClassLoader to specify all the permissions needed for the class to run.

I’ve also left unexplored some other topics in the JVM; see the O’Reilly books The Java Virtual Machine and The Java Language, or Sun’s JVM Specification document (http://java.sun.com/docs/books/vmspec/) for a lifetime of reading enjoyment and edification!

The Byte Code Engineering Library (BCEL) is a third-party toolkit for building and manipulating class files. BCEL was written by Markus Dahm and is available for free from http://bcel.sourceforge.net. Source code is included.



[58] My AppletViewer doesn’t parse the HTML as the real one does, so you invoke it with just the name of the Applet subclass on its command line. The size is therefore hardcoded, at least until somebody gets around to writing code to extract the CLASS, WIDTH, and HEIGHT attributes from the APPLET tag in the HTML page like the real McCoy does.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.10.45