Recipe 25.8 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 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,[1] 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).

[1] My AppletViewer doesn't parse HTML like 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.

Figure 25-2. My AppletViewer showing simple applet
figs/jcb2_2502.gif


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. In a real browser, they are probably implemented separately, but 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 been tested only with a basic Hello World applet, and it 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 the 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 an important exercise for anyone planning to load classes over the Internet! (For more information about security managers and the Java Security APIs, see 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 Apache Software Foundation maintains a variety of useful software packages that are free to get and use. Source code is always available without charge from its web site. Two packages you might want to investigate include the Commons BeanUtils and the Byte Code Engineering Library (BCEL). The Commons BeanUtils, available from http://jakarta.apache.org/commons/beanutils/, claims to provide easier-to-use wrappers around some of the Reflection API. BCEL is a third-party toolkit for building and manipulating "bytecode" class files. Written by Markus Dahm, BCEL has become part of the Jakarta Project and is available from http://jakarta.apache.org/bcel/.



Java Cookbook
Java Cookbook, Second Edition
ISBN: 0596007019
EAN: 2147483647
Year: 2003
Pages: 409
Authors: Ian F Darwin

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net