home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-01-27 | 14.8 KB | 572 lines |
- /*
- * @(#)AppletPanel.java 1.22 96/03/20
- *
- * Copyright (c) 1994-1995 Sun Microsystems, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL purposes and without
- * fee is hereby granted provided that this copyright notice
- * appears in all copies. Please refer to the file "copyright.html"
- * for further important copyright and licensing information.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
- * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
- * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- */
-
- package sun.applet;
-
- import java.util.*;
- import java.io.*;
- import java.net.URL;
- import java.net.MalformedURLException;
- import java.awt.*;
- import java.applet.*;
- import java.awt.image.MemoryImageSource;
- import java.awt.image.ColorModel;
-
- import sun.misc.MessageUtils;
-
-
- /**
- * Applet panel class. The panel manages and manipulates the
- * applet as it is being loaded. It forks a separate thread in a new
- * thread group to call the applet's init(), start(), stop(), and
- * destroy() methods.
- *
- * @version 1.22, 03/20/96
- * @author Arthur van Hoff
- */
- public
- abstract class AppletPanel extends Panel implements AppletStub, Runnable {
- /**
- * Root name to use for messages.
- */
- static String propName = "appletloader";
-
- /**
- * The applet (if loaded).
- */
- Applet applet;
-
- /**
- * The classloader for the applet.
- */
- AppletClassLoader loader;
-
- /**
- * The current status. One of: APPLET_DISPOSE, APPLET_LOAD,
- * APPLET_INIT, APPLET_START, APPLET_STOP,
- * APPLET_DESTROY, APPLET_ERROR.
- */
- protected int status;
-
- /**
- * The thread for the applet.
- */
- Thread handler;
-
- /* applet event ids */
- public final static int APPLET_DISPOSE = 0;
- public final static int APPLET_LOAD = 1;
- public final static int APPLET_INIT = 2;
- public final static int APPLET_START = 3;
- public final static int APPLET_STOP = 4;
- public final static int APPLET_DESTROY = 5;
- public final static int APPLET_QUIT = 6;
- public final static int APPLET_ERROR = 7;
-
- /* send to the parent to force relayout */
- public final static int APPLET_RESIZE = 51234;
-
- /* sent to a (distant) parent to indicate that the applet is being
- * loaded or as completed loading
- */
- public final static int APPLET_LOADING = 51235;
- public final static int APPLET_LOADING_COMPLETED = 51236;
-
- /**
- * The applet size.
- */
- Dimension appletSize = new Dimension(100, 100);
-
- MessageUtils mu = new MessageUtils();
-
- /**
- * The thread to use during applet loading
- */
-
- Thread loaderThread = null;
-
- /**
- * Flag to indicate that a loading has been cancelled
- */
- boolean loadAbortRequest = false;
-
-
- /**
- * Construct an applet viewer and start the applet.
- */
- public void init() {
- setLayout(new BorderLayout());
-
- // Get the width (if any)
- String att = getParameter("width");
- if (att != null) {
- appletSize.width = Integer.valueOf(att).intValue();
- }
-
- // Get the height (if any)
- att = getParameter("height");
- if (att != null) {
- appletSize.height = Integer.valueOf(att).intValue();
- }
-
- // Create a thread group for the applet, and start a new
- // thread to load the applet.
- String nm = "applet-" + getParameter("code");
- handler = new Thread(new AppletThreadGroup("group " + nm), this, "thread " + nm);
- //System.out.println("+++++++ Starting applet loading");
- handler.start();
- }
-
- /**
- * Minimum size
- */
- public Dimension minimumSize() {
- return new Dimension(appletSize.width, appletSize.height);
- }
-
- /**
- * Preferred size
- */
- public Dimension preferredSize() {
- return minimumSize();
- }
-
- /**
- * Event Queue
- */
- Event queue = null;
-
- /**
- * Send an event.
- */
- public void sendEvent(int id) {
- //System.out.println("SEND= " + id);
- sendEvent(new Event(null, id, null));
- }
-
- /**
- * Send an event. Queue it for execution by the handler thread.
- */
- protected synchronized void sendEvent(Event evt) {
- if (queue == null) {
- //System.out.println("SEND0= " + evt);
- evt.target = queue;
- queue = evt;
- notifyAll();
- } else {
- //System.out.println("SEND1= " + evt);
- Event q = queue;
- for (; q.target != null ; q = (Event)q.target);
- q.target = evt;
- }
- }
-
- /**
- * Get an event from the queue.
- */
- synchronized Event getNextEvent() throws InterruptedException {
- while (queue == null) {
- wait();
- }
- Event evt = queue;
- queue = (Event)queue.target;
- evt.target = this;
- return evt;
- }
-
- /**
- * Execute applet events.
- */
- public void run() {
-
- Thread curThread = Thread.currentThread();
- if (curThread == loaderThread) {
- // if we are in the loader thread, cause
- // loading to occur. We may exit this with
- // status being APPLET_DISPOSE, APPLET_ERROR,
- // or APPLET_LOAD
- runLoader();
- return;
- }
-
- // Bump up the priority, so that applet events are processed in
- // a timely manner.
- int priority = curThread.getPriority();
- curThread.setPriority(priority + 1);
-
- while (true) {
- Event evt;
- try {
- evt = getNextEvent();
- } catch (InterruptedException e) {
- showAppletStatus(propName+".bail");
- return;
- }
-
- //showAppletStatus("EVENT = " + evt.id);
- try {
- switch (evt.id) {
- case APPLET_LOAD:
- if (!okToLoad()) {
- break;
- }
- // This complexity allows laoding of applets to be
- // interruptable. The actual thread loading runs
- // in a separate thread, so it can be interrupted
- // without harming the applet thread.
- // So that we don't have to worry about
- // concurrency issues, the main applet thread waits
- // until the loader thread terminates.
- // (one way or another).
- if (loaderThread == null) {
- // REMIND: do we want a name?
- //System.out.println("------------------- loading applet");
- setLoaderThread(new Thread(this));
- loaderThread.setPriority(priority+1);
- loaderThread.start();
- // we get to go to sleep while this runs
- loaderThread.join();
- setLoaderThread(null);
- } else {
- // REMIND: issue an error -- this case should never
- // occur.
- }
- break;
-
-
- case APPLET_INIT:
- if (status != APPLET_LOAD) {
- showAppletStatus(propName+".notloaded");
- break;
- }
- applet.resize(appletSize);
- applet.init();
- validate();
- status = APPLET_INIT;
- showAppletStatus(propName+".inited");
- break;
-
- case APPLET_START:
- if (status != APPLET_INIT) {
- showAppletStatus(propName+".notinited");
- break;
- }
- applet.resize(appletSize);
- applet.start();
- validate();
- applet.show();
- status = APPLET_START;
- showAppletStatus(propName+".started");
- break;
-
- case APPLET_STOP:
- if (status != APPLET_START) {
- showAppletStatus(propName+".notstarted");
- break;
- }
- status = APPLET_INIT;
- applet.hide();
- applet.stop();
- showAppletStatus(propName+".stopped");
- break;
-
- case APPLET_DESTROY:
- if (status != APPLET_INIT) {
- showAppletStatus(propName+".notstopped");
- break;
- }
- status = APPLET_LOAD;
- applet.destroy();
- showAppletStatus(propName+".destroyed");
- break;
-
- case APPLET_DISPOSE:
- if (status != APPLET_LOAD) {
- showAppletStatus(propName+".notdestroyed");
- break;
- }
- status = APPLET_DISPOSE;
- remove(applet);
- showAppletStatus(propName+".disposed");
- break;
-
- case APPLET_QUIT:
- return;
- }
- } catch (Exception e) {
- showAppletStatus(mu.substProp(propName+".exception2",
- e.getClass().getName(),
- e.getMessage()));
- showAppletException(e);
- } catch (ThreadDeath e) {
- showAppletStatus(propName+".death");
- return;
- } catch (Error e) {
- showAppletStatus(mu.substProp(propName+".error2",
- e.getClass().getName(),
- e.getMessage()));
- showAppletException(e);
- }
-
- clearLoadAbortRequest();
-
- }
- }
-
-
- /**
- * Load the applet into memory.
- * Runs in a seperate (and interruptible) thread from the rest of the
- * applet event processing so that it can be gracefully interrupted from
- * things like HotJava.
- */
- private void runLoader() {
- if (status != APPLET_DISPOSE) {
- showAppletStatus(propName+".notdisposed");
- return;
- }
-
- postEvent(new Event(this, APPLET_LOADING, null));
-
-
- // REMIND -- might be cool to visually indicate loading here --
- // maybe do animation?
- status = APPLET_LOAD;
-
- // Create a class loader
- try {
- loader = getClassLoader(getCodeBase());
- if (Thread.interrupted()) {
- // no need for a null test on loader -- we're leaving
- // no matter what.
- status = APPLET_DISPOSE; // APPLET_ERROR?
- postEvent(new Event(this, APPLET_LOADING_COMPLETED, null));
- return;
- }
- } catch (IOException e) {
- status = APPLET_ERROR;
- showAppletStatus(e.getMessage());
- showAppletLog(e.getMessage());
- showAppletException(e);
- postEvent(new Event(this, APPLET_LOADING_COMPLETED, null));
- return;
- }
-
- // Create the applet using the class loader
- String code = getParameter("code");
- if (code == null) {
- String msg = propName+".nocode";
- status = APPLET_ERROR;
- showAppletStatus(msg);
- showAppletLog(msg);
- repaint();
- } else if (code.endsWith(".class")) {
- code = code.substring(0, code.length() - 6).replace('/', '.');
- } else if (code.endsWith(".java")) {
- code = code.substring(0, code.length() - 5).replace('/', '.');
- }
-
- try {
- applet = (Applet)loader.loadClass(code).newInstance();
- if (Thread.interrupted()) {
- status = APPLET_DISPOSE; // APPLET_ERROR?
- applet = null;
- // REMIND: This may not be exactly the right thing: the
- // status is set by the stop button and not necessarily
- // here.
- showAppletStatus(propName+".death");
- return;
- }
- } catch (ClassNotFoundException e) {
- status = APPLET_ERROR;
- String msg = mu.substProp(propName+".notfound", code);
- showAppletStatus(msg);
- showAppletLog(msg);
- showAppletException(e);
- return;
- } catch (InstantiationException e) {
- status = APPLET_ERROR;
- String msg = mu.substProp(propName+".nocreate", code);
- showAppletStatus(msg);
- showAppletLog(msg);
- showAppletException(e);
- return;
- } catch (IllegalAccessException e) {
- status = APPLET_ERROR;
- String msg = mu.substProp(propName+".noconstruct", code);
- showAppletStatus(msg);
- showAppletLog(msg);
- showAppletException(e);
- // sbb -- I added a return here
- return;
- } catch (Exception e) {
- status = APPLET_ERROR;
- showAppletStatus(mu.substProp(propName+".exception",
- e.getMessage()));
- showAppletException(e);
- return;
- } catch (ThreadDeath e) {
- status = APPLET_ERROR;
- showAppletStatus(propName+".death");
- return;
- } catch (Error e) {
- status = APPLET_ERROR;
- showAppletStatus(mu.substProp(propName+".error",
- e.getMessage()));
- showAppletException(e);
- return;
- } finally {
- // notify that loading is no longer going on
- postEvent(new Event(this, APPLET_LOADING_COMPLETED, null));
- }
-
- // Stick it in the frame
- applet.setStub(this);
- applet.hide();
- add("Center", applet);
- showAppletStatus(propName+".loaded");
- validate();
- }
-
-
- /**
- * Request that the loading of the applet be stopped.
- */
- protected synchronized void stopLoading() {
- // REMIND: fill in the body
- if (loaderThread != null) {
- //System.out.println("Interrupting applet loader thread: " + loaderThread);
- loaderThread.interrupt();
- } else {
- setLoadAbortRequest();
- }
- }
-
-
- protected synchronized boolean okToLoad() {
- return !loadAbortRequest;
- }
-
- protected synchronized void clearLoadAbortRequest() {
- loadAbortRequest = false;
- }
-
- protected synchronized void setLoadAbortRequest() {
- loadAbortRequest = true;
- }
-
-
- private synchronized void setLoaderThread(Thread loaderThread) {
- this.loaderThread = loaderThread;
- }
-
- /**
- * Return true when the applet has been started.
- */
- public boolean isActive() {
- return status == APPLET_START;
- }
-
- /**
- * Is called when the applet wants to be resized.
- */
- public void appletResize(int width, int height) {
- appletSize.width = width;
- appletSize.height = height;
- postEvent(new Event(this, APPLET_RESIZE, preferredSize()));
- }
-
- public Applet getApplet() {
- return applet;
- }
-
- /**
- * Status line. Called by the AppletPanel to provide
- * feedback on the Applet's state.
- */
- protected void showAppletStatus(String status) {
- String str = System.getProperty(status);
- if (str == null) {
- str = status;
- }
- getAppletContext().showStatus(str);
- }
-
- /**
- * Called by the AppletPanel to print to the log.
- */
- protected void showAppletLog(String msg) {
- String str = System.getProperty(msg);
- if (str == null) {
- str = msg;
- }
- System.out.println(str);
- }
-
- /**
- * Called by the AppletPanel to provide
- * feedback when an exception has happened.
- */
- protected void showAppletException(Throwable t) {
- t.printStackTrace();
- repaint();
- }
-
- /**
- * The class loaders
- */
- private static Hashtable classloaders = new Hashtable();
-
- /**
- * Flush a class loader.
- */
- public static synchronized void flushClassLoader(URL codebase) {
- classloaders.remove(codebase);
- }
-
- /**
- * Flush all class loaders.
- */
- public static synchronized void flushClassLoaders() {
- classloaders = new Hashtable();
- }
-
- /**
- * Get a class loader.
- */
- static synchronized AppletClassLoader getClassLoader(URL codebase)
- throws IOException {
- AppletClassLoader c = (AppletClassLoader)classloaders.get(codebase);
- if (c == null) {
- c = new AppletClassLoader(codebase);
- /*
- if (codebase.getFile().endsWith("/")) {
- c = new AppletClassLoader(codebase);
- } else {
- // If code base URL is not a directory, then assume it's
- // a zip file.
- c = new AppletZipClassLoader(codebase);
- }
- */
- classloaders.put(codebase, c);
- }
- return c;
- }
- }
-