1318 lines · 46.2 KB · Java
RawDownload
/* * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.applet; import java.applet.*;import java.awt.*;import java.awt.event.*;import java.awt.image.ColorModel;import java.awt.image.MemoryImageSource;import java.io.*;import java.lang.ref.WeakReference;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.InetAddress;import java.net.JarURLConnection;import java.net.MalformedURLException;import java.net.SocketPermission;import java.net.URL;import java.net.UnknownHostException;import java.security.*;import java.util.*;import java.util.Collections;import java.util.Locale;import java.util.WeakHashMap;import sun.awt.AppContext;import sun.awt.EmbeddedFrame;import sun.awt.SunToolkit;import sun.misc.MessageUtils;import sun.misc.PerformanceLogger;import sun.misc.Queue;import sun.security.util.SecurityConstants; /** * 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. * * @author      Arthur van Hoff */publicabstract class AppletPanel extends Panel implements AppletStub, Runnable {     /**     * The applet (if loaded).     */    Applet applet;     /**     * Applet will allow initialization.  Should be     * set to false if loading a serialized applet     * that was pickled in the init=true state.     */    protected boolean doInit = true;      /**     * The classloader for the applet.     */    protected AppletClassLoader loader;     /* 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 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.     */    protected Thread handler;      /**     * The initial applet size.     */    Dimension defaultAppletSize = new Dimension(10, 10);     /**     * The current applet size.     */    Dimension currentAppletSize = new Dimension(10, 10);     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;     /* abstract classes */    abstract protected String getCode();    abstract protected String getJarFiles();    abstract protected String getSerializedObject();     abstract public int    getWidth();    abstract public int    getHeight();    abstract public boolean hasInitialFocus();     private static int threadGroupNumber = 0;     protected void setupAppletAppContext() {        // do nothing    }     /*     * Creates a thread to run the applet. This method is called     * each time an applet is loaded and reloaded.     */    synchronized void createAppletThread() {        // Create a thread group for the applet, and start a new        // thread to load the applet.        String nm = "applet-" + getCode();        loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());        loader.grab(); // Keep this puppy around!         // 4668479: Option to turn off codebase lookup in AppletClassLoader        // during resource requests. [stanley.ho]        String param = getParameter("codebase_lookup");         if (param != null && param.equals("false"))            loader.setCodebaseLookup(false);        else            loader.setCodebaseLookup(true);          ThreadGroup appletGroup = loader.getThreadGroup();         handler = new Thread(appletGroup, this, "thread " + nm);        // set the context class loader for this thread        AccessController.doPrivileged(new PrivilegedAction() {                public Object run() {                    handler.setContextClassLoader(loader);                    return null;                }            });        handler.start();    }     void joinAppletThread() throws InterruptedException {        if (handler != null) {            handler.join();            handler = null;        }    }     void release() {        if (loader != null) {            loader.release();            loader = null;        }    }     /**     * Construct an applet viewer and start the applet.     */    public void init() {        try {            // Get the width (if any)            defaultAppletSize.width = getWidth();            currentAppletSize.width = defaultAppletSize.width;             // Get the height (if any)            defaultAppletSize.height = getHeight();            currentAppletSize.height = defaultAppletSize.height;         } catch (NumberFormatException e) {            // Turn on the error flag and let TagAppletPanel            // do the right thing.            status = APPLET_ERROR;            showAppletStatus("badattribute.exception");            showAppletLog("badattribute.exception");            showAppletException(e);        }         setLayout(new BorderLayout());         createAppletThread();    }     /**     * Minimum size     */    public Dimension minimumSize() {        return new Dimension(defaultAppletSize.width,                             defaultAppletSize.height);    }     /**     * Preferred size     */    public Dimension preferredSize() {        return new Dimension(currentAppletSize.width,                             currentAppletSize.height);    }     private AppletListener listeners;     /**     * AppletEvent Queue     */    private Queue queue = null;      synchronized public void addAppletListener(AppletListener l) {        listeners = AppletEventMulticaster.add(listeners, l);    }     synchronized public void removeAppletListener(AppletListener l) {        listeners = AppletEventMulticaster.remove(listeners, l);    }     /**     * Dispatch event to the listeners..     */    public void dispatchAppletEvent(int id, Object argument) {        //System.out.println("SEND= " + id);        if (listeners != null) {            AppletEvent evt = new AppletEvent(this, id, argument);            listeners.appletStateChanged(evt);        }    }     /**     * Send an event. Queue it for execution by the handler thread.     */    public void sendEvent(int id) {        synchronized(this) {            if (queue == null) {                //System.out.println("SEND0= " + id);                queue = new Queue();            }            Integer eventId = Integer.valueOf(id);            queue.enqueue(eventId);            notifyAll();        }        if (id == APPLET_QUIT) {            try {                joinAppletThread(); // Let the applet event handler exit            } catch (InterruptedException e) {            }             // AppletClassLoader.release() must be called by a Thread            // not within the applet's ThreadGroup            if (loader == null)                loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());            release();        }    }     /**     * Get an event from the queue.     */    synchronized AppletEvent getNextEvent() throws InterruptedException {        while (queue == null || queue.isEmpty()) {            wait();        }        Integer eventId = (Integer)queue.dequeue();        return new AppletEvent(this, eventId.intValue(), null);    }     boolean emptyEventQueue() {        if ((queue == null) || (queue.isEmpty()))            return true;        else            return false;    }     /**     * This kludge is specific to get over AccessControlException thrown during     * Applet.stop() or destroy() when static thread is suspended.  Set a flag     * in AppletClassLoader to indicate that an     * AccessControlException for RuntimePermission "modifyThread" or     * "modifyThreadGroup" had occurred.     */     private void setExceptionStatus(AccessControlException e) {     Permission p = e.getPermission();     if (p instanceof RuntimePermission) {         if (p.getName().startsWith("modifyThread")) {             if (loader == null)                 loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());             loader.setExceptionStatus();         }     }     }     /**     * Execute applet events.     * Here is the state transition diagram     *     *   Note: (XXX) is the action     *         APPLET_XXX is the state     *  (applet code loaded) --> APPLET_LOAD -- (applet init called)--> APPLET_INIT -- (     *   applet start called) --> APPLET_START -- (applet stop called) -->APPLET_STOP --(applet     *   destroyed called) --> APPLET_DESTROY -->(applet gets disposed) -->     *   APPLET_DISPOSE -->....     *     * In the legacy lifecycle model. The applet gets loaded, inited and started. So it stays     * in the APPLET_START state unless the applet goes away(refresh page or leave the page).     * So the applet stop method called and the applet enters APPLET_STOP state. Then if the applet     * is revisited, it will call applet start method and enter the APPLET_START state and stay there.     *     * In the modern lifecycle model. When the applet first time visited, it is same as legacy lifecycle     * model. However, when the applet page goes away. It calls applet stop method and enters APPLET_STOP     * state and then applet destroyed method gets called and enters APPLET_DESTROY state.     *     * This code is also called by AppletViewer. In AppletViewer "Restart" menu, the applet is jump from     * APPLET_STOP to APPLET_DESTROY and to APPLET_INIT .     *     * Also, the applet can jump from APPLET_INIT state to APPLET_DESTROY (in Netscape/Mozilla case).         * Same as APPLET_LOAD to     * APPLET_DISPOSE since all of this are triggered by browser.     *     *     */    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;        }         boolean disposed = false;        while (!disposed && !curThread.isInterrupted()) {            AppletEvent evt;            try {                evt = getNextEvent();            } catch (InterruptedException e) {                showAppletStatus("bail");                return;            }             //showAppletStatus("EVENT = " + evt.getID());            try {                switch (evt.getID()) {                  case APPLET_LOAD:                      if (!okToLoad()) {                          break;                      }                      // This complexity allows loading 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.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:                    // AppletViewer "Restart" will jump from destroy method to                    // init, that is why we need to check status w/ APPLET_DESTROY                      if (status != APPLET_LOAD && status != APPLET_DESTROY) {                          showAppletStatus("notloaded");                          break;                      }                      applet.resize(defaultAppletSize);                      if (doInit) {                          if (PerformanceLogger.loggingEnabled()) {                              PerformanceLogger.setTime("Applet Init");                              PerformanceLogger.outputLog();                          }                          applet.init();                      }                       //Need the default(fallback) font to be created in this AppContext                      Font f = getFont();                      if (f == null ||                          "dialog".equals(f.getFamily().toLowerCase(Locale.ENGLISH)) &&                          f.getSize() == 12 && f.getStyle() == Font.PLAIN) {                          setFont(new Font(Font.DIALOG, Font.PLAIN, 12));                      }                       doInit = true;    // allow restarts                       // Validate the applet in event dispatch thread                      // to avoid deadlock.                      try {                          final AppletPanel p = this;                           EventQueue.invokeAndWait(new Runnable() {                                  public void run() {                                      p.validate();                                  }                              });                      }                      catch(InterruptedException ie) {                      }                      catch(InvocationTargetException ite) {                      }                       status = APPLET_INIT;                      showAppletStatus("inited");                      break;                   case APPLET_START:                  {                      if (status != APPLET_INIT && status != APPLET_STOP) {                          showAppletStatus("notinited");                          break;                      }                      applet.resize(currentAppletSize);                      applet.start();                       // Validate and show the applet in event dispatch thread                      // to avoid deadlock.                      try {                          final AppletPanel p = this;                          final Applet a = applet;                           EventQueue.invokeAndWait(new Runnable() {                                  public void run() {                                      p.validate();                                      a.setVisible(true);                                       // Fix for BugTraq ID 4041703.                                      // Set the default focus for an applet.                                      if (hasInitialFocus())                                        setDefaultFocus();                                  }                              });                      }                      catch(InterruptedException ie) {                      }                      catch(InvocationTargetException ite) {                      }                       status = APPLET_START;                      showAppletStatus("started");

Lines 1–500 of 1318.