Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/sun/applet/AppletPanel.java

/*
 * @(#)AppletPanel.java	1.12 95/11/13
 *
 * 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 java.lang.SecurityManager;


/**
 * Applet panel class. The panel manages and manipulates the
 * applet as it is being loaded. It forks a seperate thread in a new
 * thread group to call the applet's init(), start(), stop(), and
 * destroy() methods.
 *
 * @version 	1.12, 13 Nov 1995
 * @author 	Arthur van Hoff
 */
public abstract class AppletPanel extends Panel implements AppletStub, Runnable {
    /**
     * The applet (if loaded).
     */
    Applet applet;

    /**
     * The classloader for the applet.
     */
    AppletClassLoader loader;

    /**
     * The current status. Either: APPLET_DISPOSE, APPLET_LOAD, 
     * APPLET_INIT, APPLET_START.
     */
    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;

    /* send to the parent to force relayout */
    public final static int APPLET_RESIZE = 51234;

    /**
     * The applet size.
     */
    Dimension appletSize = new Dimension(100, 100);

    /**
     * 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();
	}

	SecurityManager.setScopePermission();
	// 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);
	SecurityManager.resetScopePermission();
	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() {
        // Bump up the priority, so that applet events are processed in
        // a timely manner.
        int priority = Thread.currentThread().getPriority();
	SecurityManager.setScopePermission();
        Thread.currentThread().setPriority(priority + 1);
	SecurityManager.resetScopePermission();

	while (true) {
	    Event evt;
	    try {
		evt = getNextEvent();
	    } catch (InterruptedException e) {
		showAppletStatus("bailing out...");
		return;
	    }

	    //showAppletStatus("EVENT = " + evt.id);
	    try {
		switch (evt.id) {
		  case APPLET_LOAD:
		    if (status != APPLET_DISPOSE) {
			showAppletStatus("load: not disposed");
			break;
		    }
		    // Create a class loader
		    loader = getClassLoader(getCodeBase());

		    // Create the applet using the class loader
		    String code = getParameter("code");
		    if (code.endsWith(".class")) {
			code = code.substring(0, code.length() - 6).replace('/', '.');
		    }
		    if (code.endsWith(".java")) {
			code = code.substring(0, code.length() - 5).replace('/', '.');
		    }
		    try {
			applet = (Applet)loader.loadClass(code).newInstance();
		    } catch (ClassNotFoundException e) {
			showAppletStatus("load: class " + code + " not found");
			showAppletLog("load: class " + code + " not found");
			showAppletException(e);
			break;
		    } catch (InstantiationException e) {
			showAppletStatus("load: " + code + " can't be instantiated");
			showAppletLog("load: " + code + " can't be instantiated");
			showAppletException(e);
			break;
		    } catch (IllegalAccessException e) {
			showAppletStatus("load: " + code + " is not public or has no public constructor");
			showAppletLog("load: " + code + " is not public or has no public constructor");
			showAppletException(e);
		    } catch (Exception e) {
			showAppletStatus("exception: " + e.getMessage());
			showAppletException(e);
			break;
		    } catch (ThreadDeath e) {
			showAppletStatus("killed");
			return;
		    } catch (Error e) {
			showAppletStatus("error: " + e.getMessage());
			showAppletException(e);
			break;
		    }
		
		    // Stick it in the frame
		    applet.setStub(this);
		    applet.hide();
		    add("Center", applet);
		    status = APPLET_LOAD;
		    showAppletStatus("applet loaded");
		    validate();
		    break;
		  
		  case APPLET_INIT:
		    if (status != APPLET_LOAD) {
			showAppletStatus("init: applet not loaded");
			break;
		    }
		    applet.resize(appletSize);
		    applet.init();
		    validate();
		    status = APPLET_INIT;
		    showAppletStatus("applet initialized");
		    break;

		  case APPLET_START:
		    if (status != APPLET_INIT) {
			showAppletStatus("start: applet not initialized");
			break;
		    }
		    applet.resize(appletSize);
		    applet.start();
		    applet.show();
		    validate();
		    status = APPLET_START;
		    showAppletStatus("applet started");
		    break;

		  case APPLET_STOP:
		    if (status != APPLET_START) {
			showAppletStatus("stop: applet not started");
			break;
		    }
		    status = APPLET_INIT;
		    applet.hide();
		    SecurityManager.setScopePermission();
		    applet.stop();
		    SecurityManager.resetScopePermission();
		    showAppletStatus("applet stopped");
		    break;

		  case APPLET_DESTROY:
		    if (status != APPLET_INIT) {
			showAppletStatus("destroy: applet not stopped");
			break;
		    }
		    status = APPLET_LOAD;
		    SecurityManager.setScopePermission();
		    applet.destroy();
		    SecurityManager.resetScopePermission();
		    showAppletStatus("applet destroyed");
		    break;

		  case APPLET_DISPOSE:
		    if (status != APPLET_LOAD) {
			showAppletStatus("dispose: applet not destroyed");
			break;
		    }
		    status = APPLET_DISPOSE;
		    remove(applet);
		    showAppletStatus("applet disposed");
		    break;

		  case APPLET_QUIT:
		    return;
		}
	    } catch (Exception e) {
		showAppletStatus("exception: " + e.getClass().getName() + ": " + e.getMessage());
		showAppletException(e);
	    } catch (ThreadDeath e) {
		showAppletStatus("killed");
		return;
	    } catch (Error e) {
		showAppletStatus("error: " + e.getClass().getName() + ": " + e.getMessage());
		showAppletException(e);
	    }
	}
    }

    /**
     * Return true when the applet has been started.
     */
    public boolean isActive() {
	return status == APPLET_START;
    }

    /**
     * Is called when the applet want to be resized.
     */
    public void appletResize(int width, int height) {
	appletSize.width = width;
	appletSize.height = height;
	postEvent(new Event(this, APPLET_RESIZE, preferredSize()));
    }

    /**
     * Status line. Called by the AppletPanel to provide
     * feedback on the Applet's state.
     */
    protected void showAppletStatus(String status) {
	//System.out.println("STATUS = " + status);
	getAppletContext().showStatus(status);
    }		

    /**
     * Called by the AppletPanel to print to the log.
     */
    protected void showAppletLog(String str) {
	System.out.println(str);
    }		

    /**
     * Called by the AppletPanel to provide
     * feedback when an exception has happend.
     */
    protected void showAppletException(Throwable t) {
	t.printStackTrace();
    }		

    /**
     * The class loaders
     */
    private static Hashtable classloaders = new Hashtable();
    
    /**
     * Flush the class loaders.
     */
    static synchronized void flushClassLoader(URL codebase) {
	classloaders.remove(codebase);
    }

    /**
     * Get a class loader.
     */
    static synchronized AppletClassLoader getClassLoader(URL codebase) {
	AppletClassLoader c = (AppletClassLoader)classloaders.get(codebase);
	if (c == null) {
	    c = new AppletClassLoader(codebase);
	    classloaders.put(codebase, c);
	}
	return c;
    }
}