home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 25 / CDROM25.iso / Share / prog / VJ11 / VJTRIAL.EXE / IE30Java.exe / classd.exe / sun / applet / AppletPanel.java < prev    next >
Encoding:
Java Source  |  1997-01-27  |  14.8 KB  |  572 lines

  1. /*
  2.  * @(#)AppletPanel.java    1.22 96/03/20
  3.  *
  4.  * Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package sun.applet;
  21.  
  22. import java.util.*;
  23. import java.io.*;
  24. import java.net.URL;
  25. import java.net.MalformedURLException;
  26. import java.awt.*;
  27. import java.applet.*;
  28. import java.awt.image.MemoryImageSource;
  29. import java.awt.image.ColorModel;
  30.  
  31. import sun.misc.MessageUtils;
  32.  
  33.  
  34. /**
  35.  * Applet panel class. The panel manages and manipulates the
  36.  * applet as it is being loaded. It forks a separate thread in a new
  37.  * thread group to call the applet's init(), start(), stop(), and
  38.  * destroy() methods.
  39.  *
  40.  * @version     1.22, 03/20/96
  41.  * @author     Arthur van Hoff
  42.  */
  43. public
  44. abstract class AppletPanel extends Panel implements AppletStub, Runnable {
  45.     /**
  46.      * Root name to use for messages.
  47.      */
  48.     static String propName = "appletloader";
  49.  
  50.     /**
  51.      * The applet (if loaded).
  52.      */
  53.     Applet applet;
  54.  
  55.     /**
  56.      * The classloader for the applet.
  57.      */
  58.     AppletClassLoader loader;
  59.  
  60.     /**
  61.      * The current status. One of: APPLET_DISPOSE, APPLET_LOAD,
  62.      * APPLET_INIT, APPLET_START, APPLET_STOP, 
  63.      * APPLET_DESTROY, APPLET_ERROR.
  64.      */
  65.     protected int status;
  66.  
  67.     /**
  68.      * The thread for the applet.
  69.      */
  70.     Thread handler;
  71.  
  72.     /* applet event ids */
  73.     public final static int APPLET_DISPOSE = 0;
  74.     public final static int APPLET_LOAD = 1;
  75.     public final static int APPLET_INIT = 2;
  76.     public final static int APPLET_START = 3;
  77.     public final static int APPLET_STOP = 4;
  78.     public final static int APPLET_DESTROY = 5;
  79.     public final static int APPLET_QUIT = 6;
  80.     public final static int APPLET_ERROR = 7;
  81.  
  82.     /* send to the parent to force relayout */
  83.     public final static int APPLET_RESIZE = 51234;
  84.  
  85.     /* sent to a (distant) parent to indicate that the applet is being
  86.      * loaded or as completed loading
  87.      */
  88.     public final static int APPLET_LOADING = 51235;
  89.     public final static int APPLET_LOADING_COMPLETED = 51236;
  90.  
  91.     /**
  92.      * The applet size.
  93.      */
  94.     Dimension appletSize = new Dimension(100, 100);
  95.  
  96.     MessageUtils mu = new MessageUtils();
  97.  
  98.     /**
  99.      * The thread to use during applet loading
  100.      */
  101.  
  102.     Thread loaderThread = null;
  103.  
  104.     /**
  105.      * Flag to indicate that a loading has been cancelled
  106.      */
  107.     boolean loadAbortRequest = false;
  108.  
  109.  
  110.     /**
  111.      * Construct an applet viewer and start the applet.
  112.      */
  113.     public void init() {
  114.     setLayout(new BorderLayout());
  115.  
  116.     // Get the width (if any)
  117.     String att = getParameter("width");
  118.     if (att != null) {
  119.         appletSize.width = Integer.valueOf(att).intValue();
  120.     }
  121.  
  122.     // Get the height (if any)
  123.     att = getParameter("height");
  124.     if (att != null) {
  125.         appletSize.height = Integer.valueOf(att).intValue();
  126.     }
  127.  
  128.     // Create a thread group for the applet, and start a new
  129.         // thread to load the applet.
  130.     String nm = "applet-" + getParameter("code");
  131.     handler = new Thread(new AppletThreadGroup("group " + nm), this, "thread " + nm);
  132.     //System.out.println("+++++++ Starting applet loading");
  133.     handler.start();
  134.     }
  135.  
  136.     /**
  137.      * Minimum size
  138.      */
  139.     public Dimension minimumSize() {
  140.     return new Dimension(appletSize.width, appletSize.height);
  141.     }
  142.  
  143.     /**
  144.      * Preferred size
  145.      */
  146.     public Dimension preferredSize() {
  147.     return minimumSize();
  148.     }
  149.  
  150.     /**
  151.      * Event Queue
  152.      */
  153.     Event queue = null;
  154.  
  155.     /**
  156.      * Send an event.
  157.      */
  158.     public void sendEvent(int id) {
  159.     //System.out.println("SEND= " + id);
  160.     sendEvent(new Event(null, id, null));
  161.     }
  162.  
  163.     /**
  164.      * Send an event. Queue it for execution by the handler thread.
  165.      */
  166.     protected synchronized void sendEvent(Event evt) {
  167.     if (queue == null) {
  168.         //System.out.println("SEND0= " + evt);
  169.         evt.target = queue;
  170.         queue = evt;
  171.         notifyAll();
  172.     } else {
  173.         //System.out.println("SEND1= " + evt);
  174.         Event q = queue;
  175.         for (; q.target != null ; q = (Event)q.target);
  176.         q.target = evt;
  177.     }
  178.     }
  179.  
  180.     /**
  181.      * Get an event from the queue.
  182.      */
  183.     synchronized Event getNextEvent() throws InterruptedException {
  184.     while (queue == null) {
  185.         wait();
  186.     }
  187.     Event evt = queue;
  188.     queue = (Event)queue.target;
  189.     evt.target = this;
  190.     return evt;
  191.     }
  192.  
  193.     /**
  194.      * Execute applet events.
  195.      */
  196.     public void run() {
  197.  
  198.     Thread curThread = Thread.currentThread();
  199.     if (curThread == loaderThread) {
  200.         // if we are in the loader thread, cause
  201.         // loading to occur.  We may exit this with
  202.         // status being APPLET_DISPOSE, APPLET_ERROR,
  203.         // or APPLET_LOAD
  204.         runLoader();
  205.         return;
  206.     }
  207.  
  208.         // Bump up the priority, so that applet events are processed in
  209.         // a timely manner.
  210.         int priority = curThread.getPriority();
  211.         curThread.setPriority(priority + 1);
  212.  
  213.     while (true) {
  214.         Event evt;
  215.         try {
  216.         evt = getNextEvent();
  217.         } catch (InterruptedException e) {
  218.         showAppletStatus(propName+".bail");
  219.         return;
  220.         }
  221.  
  222.         //showAppletStatus("EVENT = " + evt.id);
  223.         try {
  224.         switch (evt.id) {
  225.           case APPLET_LOAD:
  226.             if (!okToLoad()) {
  227.             break;
  228.             }
  229.             // This complexity allows laoding of applets to be
  230.             // interruptable.  The actual thread loading runs
  231.             // in a separate thread, so it can be interrupted
  232.             // without harming the applet thread.
  233.             // So that we don't have to worry about
  234.             // concurrency issues, the main applet thread waits
  235.             // until the loader thread terminates.
  236.             // (one way or another).
  237.             if (loaderThread == null) {
  238.             // REMIND: do we want a name?
  239.             //System.out.println("------------------- loading applet");
  240.             setLoaderThread(new Thread(this));
  241.             loaderThread.setPriority(priority+1);
  242.             loaderThread.start();
  243.             // we get to go to sleep while this runs
  244.             loaderThread.join();
  245.             setLoaderThread(null);
  246.             } else {
  247.             // REMIND: issue an error -- this case should never
  248.             // occur.
  249.             }
  250.             break;
  251.  
  252.           
  253.           case APPLET_INIT:
  254.             if (status != APPLET_LOAD) {
  255.             showAppletStatus(propName+".notloaded");
  256.             break;
  257.             }
  258.             applet.resize(appletSize);
  259.             applet.init();
  260.             validate();
  261.             status = APPLET_INIT;
  262.             showAppletStatus(propName+".inited");
  263.             break;
  264.  
  265.           case APPLET_START:
  266.             if (status != APPLET_INIT) {
  267.             showAppletStatus(propName+".notinited");
  268.             break;
  269.             }
  270.             applet.resize(appletSize);
  271.             applet.start();
  272.             validate();
  273.             applet.show();
  274.             status = APPLET_START;
  275.             showAppletStatus(propName+".started");
  276.             break;
  277.  
  278.           case APPLET_STOP:
  279.             if (status != APPLET_START) {
  280.             showAppletStatus(propName+".notstarted");
  281.             break;
  282.             }
  283.             status = APPLET_INIT;
  284.             applet.hide();
  285.             applet.stop();
  286.             showAppletStatus(propName+".stopped");
  287.             break;
  288.  
  289.           case APPLET_DESTROY:
  290.             if (status != APPLET_INIT) {
  291.             showAppletStatus(propName+".notstopped");
  292.             break;
  293.             }
  294.             status = APPLET_LOAD;
  295.             applet.destroy();
  296.             showAppletStatus(propName+".destroyed");
  297.             break;
  298.  
  299.           case APPLET_DISPOSE:
  300.             if (status != APPLET_LOAD) {
  301.             showAppletStatus(propName+".notdestroyed");
  302.             break;
  303.             }
  304.             status = APPLET_DISPOSE;
  305.             remove(applet);
  306.             showAppletStatus(propName+".disposed");
  307.             break;
  308.  
  309.           case APPLET_QUIT:
  310.             return;
  311.         }
  312.         } catch (Exception e) {
  313.         showAppletStatus(mu.substProp(propName+".exception2",
  314.                           e.getClass().getName(),
  315.                           e.getMessage()));
  316.         showAppletException(e);
  317.         } catch (ThreadDeath e) {
  318.         showAppletStatus(propName+".death");
  319.         return;
  320.         } catch (Error e) {
  321.         showAppletStatus(mu.substProp(propName+".error2",
  322.                           e.getClass().getName(),
  323.                           e.getMessage()));
  324.         showAppletException(e);
  325.         }
  326.  
  327.         clearLoadAbortRequest();
  328.         
  329.     }
  330.     }
  331.  
  332.  
  333.     /**
  334.      * Load the applet into memory.
  335.      * Runs in a seperate (and interruptible) thread from the rest of the
  336.      * applet event processing so that it can be gracefully interrupted from
  337.      * things like HotJava.
  338.      */
  339.     private void runLoader() {
  340.     if (status != APPLET_DISPOSE) {
  341.         showAppletStatus(propName+".notdisposed");
  342.         return;
  343.     }
  344.  
  345.     postEvent(new Event(this, APPLET_LOADING, null));
  346.  
  347.  
  348.     // REMIND -- might be cool to visually indicate loading here --
  349.     // maybe do animation?
  350.     status = APPLET_LOAD;
  351.  
  352.     // Create a class loader
  353.     try {
  354.         loader = getClassLoader(getCodeBase());
  355.         if (Thread.interrupted()) {    
  356.         // no need for a null test on loader -- we're leaving
  357.         // no matter what.
  358.         status = APPLET_DISPOSE; // APPLET_ERROR?
  359.         postEvent(new Event(this, APPLET_LOADING_COMPLETED, null));
  360.         return;
  361.         }
  362.     } catch (IOException e) {
  363.         status = APPLET_ERROR;
  364.         showAppletStatus(e.getMessage());
  365.         showAppletLog(e.getMessage());
  366.         showAppletException(e);
  367.         postEvent(new Event(this, APPLET_LOADING_COMPLETED, null));
  368.         return;
  369.     }
  370.  
  371.     // Create the applet using the class loader
  372.     String code = getParameter("code");
  373.     if (code == null) {
  374.         String msg = propName+".nocode";
  375.         status = APPLET_ERROR;
  376.         showAppletStatus(msg);
  377.         showAppletLog(msg);
  378.         repaint();
  379.     } else if (code.endsWith(".class")) {
  380.         code = code.substring(0, code.length() - 6).replace('/', '.');
  381.     } else if (code.endsWith(".java")) {
  382.         code = code.substring(0, code.length() - 5).replace('/', '.');
  383.     }
  384.  
  385.     try {
  386.         applet = (Applet)loader.loadClass(code).newInstance();
  387.         if (Thread.interrupted()) {
  388.         status = APPLET_DISPOSE; // APPLET_ERROR?
  389.         applet = null;
  390.         // REMIND: This may not be exactly the right thing: the
  391.         // status is set by the stop button and not necessarily
  392.         // here.
  393.         showAppletStatus(propName+".death");
  394.         return;
  395.         }
  396.     } catch (ClassNotFoundException e) {
  397.         status = APPLET_ERROR;
  398.         String msg = mu.substProp(propName+".notfound", code);
  399.         showAppletStatus(msg);
  400.         showAppletLog(msg);
  401.         showAppletException(e);
  402.         return;
  403.     } catch (InstantiationException e) {
  404.         status = APPLET_ERROR;
  405.         String msg = mu.substProp(propName+".nocreate", code);
  406.         showAppletStatus(msg);
  407.         showAppletLog(msg);
  408.         showAppletException(e);
  409.         return;
  410.     } catch (IllegalAccessException e) {
  411.         status = APPLET_ERROR;
  412.         String msg = mu.substProp(propName+".noconstruct", code);
  413.         showAppletStatus(msg);
  414.         showAppletLog(msg);
  415.         showAppletException(e);
  416.         // sbb -- I added a return here
  417.         return;
  418.     } catch (Exception e) {
  419.         status = APPLET_ERROR;
  420.         showAppletStatus(mu.substProp(propName+".exception",
  421.                       e.getMessage()));
  422.         showAppletException(e);
  423.         return;
  424.     } catch (ThreadDeath e) {
  425.         status = APPLET_ERROR;
  426.         showAppletStatus(propName+".death");
  427.         return;
  428.     } catch (Error e) {
  429.         status = APPLET_ERROR;
  430.         showAppletStatus(mu.substProp(propName+".error",
  431.                       e.getMessage()));
  432.         showAppletException(e);
  433.         return;
  434.     } finally {
  435.         // notify that loading is no longer going on
  436.         postEvent(new Event(this, APPLET_LOADING_COMPLETED, null));
  437.     }
  438.  
  439.     // Stick it in the frame
  440.     applet.setStub(this);
  441.     applet.hide();
  442.     add("Center", applet);
  443.     showAppletStatus(propName+".loaded");
  444.     validate();
  445.     }
  446.  
  447.  
  448.     /**
  449.      * Request that the loading of the applet be stopped.
  450.      */
  451.     protected synchronized void stopLoading() {
  452.     // REMIND: fill in the body 
  453.     if (loaderThread != null) {
  454.         //System.out.println("Interrupting applet loader thread: " + loaderThread);
  455.         loaderThread.interrupt();
  456.         } else {
  457.         setLoadAbortRequest();
  458.     }
  459.     }
  460.  
  461.  
  462.     protected synchronized boolean okToLoad() {
  463.     return !loadAbortRequest;
  464.     }
  465.  
  466.     protected synchronized void clearLoadAbortRequest() {
  467.     loadAbortRequest = false;
  468.     }
  469.  
  470.     protected synchronized void setLoadAbortRequest() {
  471.     loadAbortRequest = true;
  472.     }
  473.  
  474.  
  475.     private synchronized void setLoaderThread(Thread loaderThread) {
  476.     this.loaderThread = loaderThread;
  477.     }
  478.  
  479.     /**
  480.      * Return true when the applet has been started.
  481.      */
  482.     public boolean isActive() {
  483.     return status == APPLET_START;
  484.     }
  485.  
  486.     /**
  487.      * Is called when the applet wants to be resized.
  488.      */
  489.     public void appletResize(int width, int height) {
  490.     appletSize.width = width;
  491.     appletSize.height = height;
  492.     postEvent(new Event(this, APPLET_RESIZE, preferredSize()));
  493.     }
  494.  
  495.     public Applet getApplet() {
  496.     return applet;
  497.     }
  498.  
  499.     /**
  500.      * Status line. Called by the AppletPanel to provide
  501.      * feedback on the Applet's state.
  502.      */
  503.     protected void showAppletStatus(String status) {
  504.     String str = System.getProperty(status);
  505.     if (str == null) {
  506.         str = status;
  507.     }
  508.     getAppletContext().showStatus(str);
  509.     }        
  510.  
  511.     /**
  512.      * Called by the AppletPanel to print to the log.
  513.      */
  514.     protected void showAppletLog(String msg) {
  515.     String str = System.getProperty(msg);
  516.     if (str == null) {
  517.         str = msg;
  518.     }
  519.     System.out.println(str);
  520.     }        
  521.  
  522.     /**
  523.      * Called by the AppletPanel to provide
  524.      * feedback when an exception has happened.
  525.      */
  526.     protected void showAppletException(Throwable t) {
  527.     t.printStackTrace();
  528.     repaint();
  529.     }        
  530.  
  531.     /**
  532.      * The class loaders
  533.      */
  534.     private static Hashtable classloaders = new Hashtable();
  535.     
  536.     /**
  537.      * Flush a class loader.
  538.      */
  539.     public static synchronized void flushClassLoader(URL codebase) {
  540.     classloaders.remove(codebase);
  541.     }
  542.     
  543.     /**
  544.      * Flush all class loaders.
  545.      */
  546.     public static synchronized void flushClassLoaders() {
  547.     classloaders = new Hashtable();
  548.     }
  549.  
  550.     /**
  551.      * Get a class loader.
  552.      */
  553.     static synchronized AppletClassLoader getClassLoader(URL codebase)
  554.         throws IOException {
  555.     AppletClassLoader c = (AppletClassLoader)classloaders.get(codebase);
  556.     if (c == null) {
  557.         c = new AppletClassLoader(codebase);
  558. /*
  559.         if (codebase.getFile().endsWith("/")) {
  560.         c = new AppletClassLoader(codebase);
  561.         } else {
  562.         // If code base URL is not a directory, then assume it's
  563.         // a zip file.
  564.         c = new AppletZipClassLoader(codebase);
  565.         }
  566. */
  567.         classloaders.put(codebase, c);
  568.     }
  569.     return c;
  570.     }
  571. }
  572.