0N/A/*
2362N/A * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.applet;
0N/A
0N/Aimport java.applet.*;
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport java.awt.image.ColorModel;
0N/Aimport java.awt.image.MemoryImageSource;
0N/Aimport java.io.*;
0N/Aimport java.lang.ref.WeakReference;
0N/Aimport java.lang.reflect.InvocationTargetException;
0N/Aimport java.lang.reflect.Method;
0N/Aimport java.net.InetAddress;
0N/Aimport java.net.JarURLConnection;
0N/Aimport java.net.MalformedURLException;
0N/Aimport java.net.SocketPermission;
0N/Aimport java.net.URL;
0N/Aimport java.net.UnknownHostException;
0N/Aimport java.security.*;
0N/Aimport java.util.*;
0N/Aimport java.util.Collections;
0N/Aimport java.util.Locale;
0N/Aimport java.util.WeakHashMap;
5704N/Aimport sun.awt.AWTAccessor;
0N/Aimport sun.awt.AppContext;
0N/Aimport sun.awt.EmbeddedFrame;
0N/Aimport sun.awt.SunToolkit;
0N/Aimport sun.misc.MessageUtils;
0N/Aimport sun.misc.PerformanceLogger;
0N/Aimport sun.misc.Queue;
0N/Aimport sun.security.util.SecurityConstants;
0N/A
0N/A/**
0N/A * Applet panel class. The panel manages and manipulates the
0N/A * applet as it is being loaded. It forks a separate thread in a new
0N/A * thread group to call the applet's init(), start(), stop(), and
0N/A * destroy() methods.
0N/A *
0N/A * @author Arthur van Hoff
0N/A */
0N/Apublic
0N/Aabstract class AppletPanel extends Panel implements AppletStub, Runnable {
0N/A
0N/A /**
0N/A * The applet (if loaded).
0N/A */
0N/A Applet applet;
0N/A
0N/A /**
0N/A * Applet will allow initialization. Should be
0N/A * set to false if loading a serialized applet
0N/A * that was pickled in the init=true state.
0N/A */
0N/A protected boolean doInit = true;
0N/A
0N/A
0N/A /**
0N/A * The classloader for the applet.
0N/A */
1365N/A protected AppletClassLoader loader;
0N/A
0N/A /* applet event ids */
0N/A public final static int APPLET_DISPOSE = 0;
0N/A public final static int APPLET_LOAD = 1;
0N/A public final static int APPLET_INIT = 2;
0N/A public final static int APPLET_START = 3;
0N/A public final static int APPLET_STOP = 4;
0N/A public final static int APPLET_DESTROY = 5;
0N/A public final static int APPLET_QUIT = 6;
0N/A public final static int APPLET_ERROR = 7;
0N/A
0N/A /* send to the parent to force relayout */
0N/A public final static int APPLET_RESIZE = 51234;
0N/A
0N/A /* sent to a (distant) parent to indicate that the applet is being
0N/A * loaded or as completed loading
0N/A */
0N/A public final static int APPLET_LOADING = 51235;
0N/A public final static int APPLET_LOADING_COMPLETED = 51236;
0N/A
0N/A /**
0N/A * The current status. One of:
0N/A * APPLET_DISPOSE,
0N/A * APPLET_LOAD,
0N/A * APPLET_INIT,
0N/A * APPLET_START,
0N/A * APPLET_STOP,
0N/A * APPLET_DESTROY,
0N/A * APPLET_ERROR.
0N/A */
0N/A protected int status;
0N/A
0N/A /**
0N/A * The thread for the applet.
0N/A */
1365N/A protected Thread handler;
0N/A
0N/A
0N/A /**
0N/A * The initial applet size.
0N/A */
0N/A Dimension defaultAppletSize = new Dimension(10, 10);
0N/A
0N/A /**
0N/A * The current applet size.
0N/A */
0N/A Dimension currentAppletSize = new Dimension(10, 10);
0N/A
0N/A MessageUtils mu = new MessageUtils();
0N/A
0N/A /**
0N/A * The thread to use during applet loading
0N/A */
0N/A
0N/A Thread loaderThread = null;
0N/A
0N/A /**
0N/A * Flag to indicate that a loading has been cancelled
0N/A */
0N/A boolean loadAbortRequest = false;
0N/A
0N/A /* abstract classes */
0N/A abstract protected String getCode();
0N/A abstract protected String getJarFiles();
0N/A abstract protected String getSerializedObject();
0N/A
0N/A abstract public int getWidth();
0N/A abstract public int getHeight();
0N/A abstract public boolean hasInitialFocus();
0N/A
0N/A private static int threadGroupNumber = 0;
0N/A
0N/A protected void setupAppletAppContext() {
0N/A // do nothing
0N/A }
0N/A
0N/A /*
0N/A * Creates a thread to run the applet. This method is called
0N/A * each time an applet is loaded and reloaded.
0N/A */
0N/A synchronized void createAppletThread() {
0N/A // Create a thread group for the applet, and start a new
0N/A // thread to load the applet.
0N/A String nm = "applet-" + getCode();
0N/A loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
0N/A loader.grab(); // Keep this puppy around!
0N/A
0N/A // 4668479: Option to turn off codebase lookup in AppletClassLoader
0N/A // during resource requests. [stanley.ho]
0N/A String param = getParameter("codebase_lookup");
0N/A
0N/A if (param != null && param.equals("false"))
0N/A loader.setCodebaseLookup(false);
0N/A else
0N/A loader.setCodebaseLookup(true);
0N/A
0N/A
0N/A ThreadGroup appletGroup = loader.getThreadGroup();
0N/A
0N/A handler = new Thread(appletGroup, this, "thread " + nm);
0N/A // set the context class loader for this thread
0N/A AccessController.doPrivileged(new PrivilegedAction() {
0N/A public Object run() {
0N/A handler.setContextClassLoader(loader);
0N/A return null;
0N/A }
0N/A });
0N/A handler.start();
0N/A }
0N/A
0N/A void joinAppletThread() throws InterruptedException {
0N/A if (handler != null) {
0N/A handler.join();
0N/A handler = null;
0N/A }
0N/A }
0N/A
0N/A void release() {
0N/A if (loader != null) {
0N/A loader.release();
0N/A loader = null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Construct an applet viewer and start the applet.
0N/A */
0N/A public void init() {
0N/A try {
0N/A // Get the width (if any)
0N/A defaultAppletSize.width = getWidth();
0N/A currentAppletSize.width = defaultAppletSize.width;
0N/A
0N/A // Get the height (if any)
0N/A defaultAppletSize.height = getHeight();
0N/A currentAppletSize.height = defaultAppletSize.height;
0N/A
0N/A } catch (NumberFormatException e) {
0N/A // Turn on the error flag and let TagAppletPanel
0N/A // do the right thing.
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("badattribute.exception");
0N/A showAppletLog("badattribute.exception");
0N/A showAppletException(e);
0N/A }
0N/A
0N/A setLayout(new BorderLayout());
0N/A
0N/A createAppletThread();
0N/A }
0N/A
0N/A /**
0N/A * Minimum size
0N/A */
0N/A public Dimension minimumSize() {
0N/A return new Dimension(defaultAppletSize.width,
0N/A defaultAppletSize.height);
0N/A }
0N/A
0N/A /**
0N/A * Preferred size
0N/A */
0N/A public Dimension preferredSize() {
0N/A return new Dimension(currentAppletSize.width,
0N/A currentAppletSize.height);
0N/A }
0N/A
0N/A private AppletListener listeners;
0N/A
0N/A /**
0N/A * AppletEvent Queue
0N/A */
0N/A private Queue queue = null;
0N/A
0N/A
0N/A synchronized public void addAppletListener(AppletListener l) {
0N/A listeners = AppletEventMulticaster.add(listeners, l);
0N/A }
0N/A
0N/A synchronized public void removeAppletListener(AppletListener l) {
0N/A listeners = AppletEventMulticaster.remove(listeners, l);
0N/A }
0N/A
0N/A /**
0N/A * Dispatch event to the listeners..
0N/A */
0N/A public void dispatchAppletEvent(int id, Object argument) {
0N/A //System.out.println("SEND= " + id);
0N/A if (listeners != null) {
0N/A AppletEvent evt = new AppletEvent(this, id, argument);
0N/A listeners.appletStateChanged(evt);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Send an event. Queue it for execution by the handler thread.
0N/A */
0N/A public void sendEvent(int id) {
0N/A synchronized(this) {
0N/A if (queue == null) {
0N/A //System.out.println("SEND0= " + id);
0N/A queue = new Queue();
0N/A }
215N/A Integer eventId = Integer.valueOf(id);
0N/A queue.enqueue(eventId);
0N/A notifyAll();
0N/A }
0N/A if (id == APPLET_QUIT) {
0N/A try {
0N/A joinAppletThread(); // Let the applet event handler exit
0N/A } catch (InterruptedException e) {
0N/A }
0N/A
0N/A // AppletClassLoader.release() must be called by a Thread
0N/A // not within the applet's ThreadGroup
0N/A if (loader == null)
0N/A loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
0N/A release();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Get an event from the queue.
0N/A */
0N/A synchronized AppletEvent getNextEvent() throws InterruptedException {
0N/A while (queue == null || queue.isEmpty()) {
0N/A wait();
0N/A }
0N/A Integer eventId = (Integer)queue.dequeue();
0N/A return new AppletEvent(this, eventId.intValue(), null);
0N/A }
0N/A
0N/A boolean emptyEventQueue() {
0N/A if ((queue == null) || (queue.isEmpty()))
0N/A return true;
0N/A else
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * This kludge is specific to get over AccessControlException thrown during
0N/A * Applet.stop() or destroy() when static thread is suspended. Set a flag
0N/A * in AppletClassLoader to indicate that an
0N/A * AccessControlException for RuntimePermission "modifyThread" or
0N/A * "modifyThreadGroup" had occurred.
0N/A */
0N/A private void setExceptionStatus(AccessControlException e) {
0N/A Permission p = e.getPermission();
0N/A if (p instanceof RuntimePermission) {
0N/A if (p.getName().startsWith("modifyThread")) {
0N/A if (loader == null)
0N/A loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
0N/A loader.setExceptionStatus();
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Execute applet events.
0N/A * Here is the state transition diagram
0N/A *
0N/A * Note: (XXX) is the action
0N/A * APPLET_XXX is the state
0N/A * (applet code loaded) --> APPLET_LOAD -- (applet init called)--> APPLET_INIT -- (
0N/A * applet start called) --> APPLET_START -- (applet stop called) -->APPLET_STOP --(applet
0N/A * destroyed called) --> APPLET_DESTROY -->(applet gets disposed) -->
0N/A * APPLET_DISPOSE -->....
0N/A *
0N/A * In the legacy lifecycle model. The applet gets loaded, inited and started. So it stays
0N/A * in the APPLET_START state unless the applet goes away(refresh page or leave the page).
0N/A * So the applet stop method called and the applet enters APPLET_STOP state. Then if the applet
0N/A * is revisited, it will call applet start method and enter the APPLET_START state and stay there.
0N/A *
0N/A * In the modern lifecycle model. When the applet first time visited, it is same as legacy lifecycle
0N/A * model. However, when the applet page goes away. It calls applet stop method and enters APPLET_STOP
0N/A * state and then applet destroyed method gets called and enters APPLET_DESTROY state.
0N/A *
0N/A * This code is also called by AppletViewer. In AppletViewer "Restart" menu, the applet is jump from
0N/A * APPLET_STOP to APPLET_DESTROY and to APPLET_INIT .
0N/A *
0N/A * Also, the applet can jump from APPLET_INIT state to APPLET_DESTROY (in Netscape/Mozilla case).
0N/A * Same as APPLET_LOAD to
0N/A * APPLET_DISPOSE since all of this are triggered by browser.
0N/A *
0N/A *
0N/A */
0N/A public void run() {
0N/A
0N/A Thread curThread = Thread.currentThread();
0N/A if (curThread == loaderThread) {
0N/A // if we are in the loader thread, cause
0N/A // loading to occur. We may exit this with
0N/A // status being APPLET_DISPOSE, APPLET_ERROR,
0N/A // or APPLET_LOAD
0N/A runLoader();
0N/A return;
0N/A }
0N/A
0N/A boolean disposed = false;
0N/A while (!disposed && !curThread.isInterrupted()) {
0N/A AppletEvent evt;
0N/A try {
0N/A evt = getNextEvent();
0N/A } catch (InterruptedException e) {
0N/A showAppletStatus("bail");
0N/A return;
0N/A }
0N/A
0N/A //showAppletStatus("EVENT = " + evt.getID());
0N/A try {
0N/A switch (evt.getID()) {
0N/A case APPLET_LOAD:
0N/A if (!okToLoad()) {
0N/A break;
0N/A }
0N/A // This complexity allows loading of applets to be
0N/A // interruptable. The actual thread loading runs
0N/A // in a separate thread, so it can be interrupted
0N/A // without harming the applet thread.
0N/A // So that we don't have to worry about
0N/A // concurrency issues, the main applet thread waits
0N/A // until the loader thread terminates.
0N/A // (one way or another).
0N/A if (loaderThread == null) {
0N/A // REMIND: do we want a name?
0N/A //System.out.println("------------------- loading applet");
0N/A setLoaderThread(new Thread(this));
0N/A loaderThread.start();
0N/A // we get to go to sleep while this runs
0N/A loaderThread.join();
0N/A setLoaderThread(null);
0N/A } else {
0N/A // REMIND: issue an error -- this case should never
0N/A // occur.
0N/A }
0N/A break;
0N/A
0N/A case APPLET_INIT:
0N/A // AppletViewer "Restart" will jump from destroy method to
0N/A // init, that is why we need to check status w/ APPLET_DESTROY
0N/A if (status != APPLET_LOAD && status != APPLET_DESTROY) {
0N/A showAppletStatus("notloaded");
0N/A break;
0N/A }
0N/A applet.resize(defaultAppletSize);
0N/A if (doInit) {
0N/A if (PerformanceLogger.loggingEnabled()) {
0N/A PerformanceLogger.setTime("Applet Init");
0N/A PerformanceLogger.outputLog();
0N/A }
0N/A applet.init();
0N/A }
0N/A
0N/A //Need the default(fallback) font to be created in this AppContext
0N/A Font f = getFont();
0N/A if (f == null ||
0N/A "dialog".equals(f.getFamily().toLowerCase(Locale.ENGLISH)) &&
0N/A f.getSize() == 12 && f.getStyle() == Font.PLAIN) {
0N/A setFont(new Font(Font.DIALOG, Font.PLAIN, 12));
0N/A }
0N/A
0N/A doInit = true; // allow restarts
0N/A
0N/A // Validate the applet in event dispatch thread
0N/A // to avoid deadlock.
0N/A try {
0N/A final AppletPanel p = this;
5704N/A Runnable r = new Runnable() {
5704N/A public void run() {
5704N/A p.validate();
5704N/A }
5704N/A };
5704N/A AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);
0N/A }
0N/A catch(InterruptedException ie) {
0N/A }
0N/A catch(InvocationTargetException ite) {
0N/A }
0N/A
0N/A status = APPLET_INIT;
0N/A showAppletStatus("inited");
0N/A break;
0N/A
0N/A case APPLET_START:
0N/A {
0N/A if (status != APPLET_INIT && status != APPLET_STOP) {
0N/A showAppletStatus("notinited");
0N/A break;
0N/A }
0N/A applet.resize(currentAppletSize);
0N/A applet.start();
0N/A
0N/A // Validate and show the applet in event dispatch thread
0N/A // to avoid deadlock.
0N/A try {
0N/A final AppletPanel p = this;
0N/A final Applet a = applet;
5704N/A Runnable r = new Runnable() {
5704N/A public void run() {
5704N/A p.validate();
5704N/A a.setVisible(true);
0N/A
5704N/A // Fix for BugTraq ID 4041703.
5704N/A // Set the default focus for an applet.
5704N/A if (hasInitialFocus()) {
5704N/A setDefaultFocus();
0N/A }
5704N/A }
5704N/A };
5704N/A AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);
0N/A }
0N/A catch(InterruptedException ie) {
0N/A }
0N/A catch(InvocationTargetException ite) {
0N/A }
0N/A
0N/A status = APPLET_START;
0N/A showAppletStatus("started");
0N/A break;
0N/A }
0N/A
0N/A case APPLET_STOP:
0N/A if (status != APPLET_START) {
0N/A showAppletStatus("notstarted");
0N/A break;
0N/A }
0N/A status = APPLET_STOP;
0N/A
0N/A // Hide the applet in event dispatch thread
0N/A // to avoid deadlock.
0N/A try {
0N/A final Applet a = applet;
5704N/A Runnable r = new Runnable() {
5704N/A public void run() {
5704N/A a.setVisible(false);
5704N/A }
5704N/A };
5704N/A AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);
0N/A }
0N/A catch(InterruptedException ie) {
0N/A }
0N/A catch(InvocationTargetException ite) {
0N/A }
0N/A
0N/A
0N/A // During Applet.stop(), any AccessControlException on an involved Class remains in
0N/A // the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is
0N/A // reused, the same exception will occur during class loading. Set the AppletClassLoader's
0N/A // exceptionStatusSet flag to allow recognition of what had happened
0N/A // when reusing AppletClassLoader object.
0N/A try {
0N/A applet.stop();
0N/A } catch (java.security.AccessControlException e) {
0N/A setExceptionStatus(e);
0N/A // rethrow exception to be handled as it normally would be.
0N/A throw e;
0N/A }
0N/A showAppletStatus("stopped");
0N/A break;
0N/A
0N/A case APPLET_DESTROY:
0N/A if (status != APPLET_STOP && status != APPLET_INIT) {
0N/A showAppletStatus("notstopped");
0N/A break;
0N/A }
0N/A status = APPLET_DESTROY;
0N/A
0N/A // During Applet.destroy(), any AccessControlException on an involved Class remains in
0N/A // the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is
0N/A // reused, the same exception will occur during class loading. Set the AppletClassLoader's
0N/A // exceptionStatusSet flag to allow recognition of what had happened
0N/A // when reusing AppletClassLoader object.
0N/A try {
0N/A applet.destroy();
0N/A } catch (java.security.AccessControlException e) {
0N/A setExceptionStatus(e);
0N/A // rethrow exception to be handled as it normally would be.
0N/A throw e;
0N/A }
0N/A showAppletStatus("destroyed");
0N/A break;
0N/A
0N/A case APPLET_DISPOSE:
0N/A if (status != APPLET_DESTROY && status != APPLET_LOAD) {
0N/A showAppletStatus("notdestroyed");
0N/A break;
0N/A }
0N/A status = APPLET_DISPOSE;
0N/A
5704N/A try {
0N/A final Applet a = applet;
5704N/A Runnable r = new Runnable() {
5704N/A public void run() {
0N/A remove(a);
0N/A }
5704N/A };
5704N/A AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);
0N/A }
0N/A catch(InterruptedException ie)
0N/A {
0N/A }
0N/A catch(InvocationTargetException ite)
0N/A {
0N/A }
0N/A applet = null;
0N/A showAppletStatus("disposed");
0N/A disposed = true;
0N/A break;
0N/A
0N/A case APPLET_QUIT:
0N/A return;
0N/A }
0N/A } catch (Exception e) {
0N/A status = APPLET_ERROR;
0N/A if (e.getMessage() != null) {
0N/A showAppletStatus("exception2", e.getClass().getName(),
0N/A e.getMessage());
0N/A } else {
0N/A showAppletStatus("exception", e.getClass().getName());
0N/A }
0N/A showAppletException(e);
0N/A } catch (ThreadDeath e) {
0N/A showAppletStatus("death");
0N/A return;
0N/A } catch (Error e) {
0N/A status = APPLET_ERROR;
0N/A if (e.getMessage() != null) {
0N/A showAppletStatus("error2", e.getClass().getName(),
0N/A e.getMessage());
0N/A } else {
0N/A showAppletStatus("error", e.getClass().getName());
0N/A }
0N/A showAppletException(e);
0N/A }
0N/A clearLoadAbortRequest();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Gets most recent focus owner component associated with the given window.
0N/A * It does that without calling Window.getMostRecentFocusOwner since it
0N/A * provides its own logic contradicting with setDefautlFocus. Instead, it
0N/A * calls KeyboardFocusManager directly.
0N/A */
0N/A private Component getMostRecentFocusOwnerForWindow(Window w) {
0N/A Method meth = (Method)AccessController.doPrivileged(new PrivilegedAction() {
0N/A public Object run() {
0N/A Method meth = null;
0N/A try {
0N/A meth = KeyboardFocusManager.class.getDeclaredMethod("getMostRecentFocusOwner", new Class[] {Window.class});
0N/A meth.setAccessible(true);
0N/A } catch (Exception e) {
0N/A // Must never happen
0N/A e.printStackTrace();
0N/A }
0N/A return meth;
0N/A }
0N/A });
0N/A if (meth != null) {
0N/A // Meth refers static method
0N/A try {
0N/A return (Component)meth.invoke(null, new Object[] {w});
0N/A } catch (Exception e) {
0N/A // Must never happen
0N/A e.printStackTrace();
0N/A }
0N/A }
0N/A // Will get here if exception was thrown or meth is null
0N/A return w.getMostRecentFocusOwner();
0N/A }
0N/A
0N/A /*
0N/A * Fix for BugTraq ID 4041703.
0N/A * Set the focus to a reasonable default for an Applet.
0N/A */
0N/A private void setDefaultFocus() {
0N/A Component toFocus = null;
0N/A Container parent = getParent();
0N/A
0N/A if(parent != null) {
0N/A if (parent instanceof Window) {
0N/A toFocus = getMostRecentFocusOwnerForWindow((Window)parent);
0N/A if (toFocus == parent || toFocus == null) {
0N/A toFocus = parent.getFocusTraversalPolicy().
0N/A getInitialComponent((Window)parent);
0N/A }
0N/A } else if (parent.isFocusCycleRoot()) {
0N/A toFocus = parent.getFocusTraversalPolicy().
0N/A getDefaultComponent(parent);
0N/A }
0N/A }
0N/A
0N/A if (toFocus != null) {
0N/A if (parent instanceof EmbeddedFrame) {
0N/A ((EmbeddedFrame)parent).synthesizeWindowActivation(true);
0N/A }
0N/A // EmbeddedFrame might have focus before the applet was added.
0N/A // Thus after its activation the most recent focus owner will be
0N/A // restored. We need the applet's initial focusabled component to
0N/A // be focused here.
0N/A toFocus.requestFocusInWindow();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Load the applet into memory.
0N/A * Runs in a seperate (and interruptible) thread from the rest of the
0N/A * applet event processing so that it can be gracefully interrupted from
0N/A * things like HotJava.
0N/A */
0N/A private void runLoader() {
0N/A if (status != APPLET_DISPOSE) {
0N/A showAppletStatus("notdisposed");
0N/A return;
0N/A }
0N/A
0N/A dispatchAppletEvent(APPLET_LOADING, null);
0N/A
0N/A // REMIND -- might be cool to visually indicate loading here --
0N/A // maybe do animation?
0N/A status = APPLET_LOAD;
0N/A
0N/A // Create a class loader
0N/A loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
0N/A
0N/A // Load the archives if present.
0N/A // REMIND - this probably should be done in a separate thread,
0N/A // or at least the additional archives (epll).
0N/A
0N/A String code = getCode();
0N/A
0N/A // setup applet AppContext
0N/A // this must be called before loadJarFiles
0N/A setupAppletAppContext();
0N/A
0N/A try {
0N/A loadJarFiles(loader);
0N/A applet = createApplet(loader);
0N/A } catch (ClassNotFoundException e) {
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("notfound", code);
0N/A showAppletLog("notfound", code);
0N/A showAppletException(e);
0N/A return;
0N/A } catch (InstantiationException e) {
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("nocreate", code);
0N/A showAppletLog("nocreate", code);
0N/A showAppletException(e);
0N/A return;
0N/A } catch (IllegalAccessException e) {
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("noconstruct", code);
0N/A showAppletLog("noconstruct", code);
0N/A showAppletException(e);
0N/A // sbb -- I added a return here
0N/A return;
0N/A } catch (Exception e) {
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("exception", e.getMessage());
0N/A showAppletException(e);
0N/A return;
0N/A } catch (ThreadDeath e) {
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("death");
0N/A return;
0N/A } catch (Error e) {
0N/A status = APPLET_ERROR;
0N/A showAppletStatus("error", e.getMessage());
0N/A showAppletException(e);
0N/A return;
0N/A } finally {
0N/A // notify that loading is no longer going on
0N/A dispatchAppletEvent(APPLET_LOADING_COMPLETED, null);
0N/A }
0N/A
0N/A // Fixed #4508194: NullPointerException thrown during
0N/A // quick page switch
0N/A //
0N/A if (applet != null)
0N/A {
0N/A // Stick it in the frame
0N/A applet.setStub(this);
0N/A applet.hide();
0N/A add("Center", applet);
0N/A showAppletStatus("loaded");
0N/A validate();
0N/A }
0N/A }
0N/A
0N/A protected Applet createApplet(final AppletClassLoader loader) throws ClassNotFoundException,
0N/A IllegalAccessException, IOException, InstantiationException, InterruptedException {
0N/A final String serName = getSerializedObject();
0N/A String code = getCode();
0N/A
0N/A if (code != null && serName != null) {
0N/A System.err.println(amh.getMessage("runloader.err"));
0N/A// return null;
0N/A throw new InstantiationException("Either \"code\" or \"object\" should be specified, but not both.");
0N/A }
0N/A if (code == null && serName == null) {
0N/A String msg = "nocode";
0N/A status = APPLET_ERROR;
0N/A showAppletStatus(msg);
0N/A showAppletLog(msg);
0N/A repaint();
0N/A }
0N/A if (code != null) {
0N/A applet = (Applet)loader.loadCode(code).newInstance();
0N/A doInit = true;
0N/A } else {
0N/A // serName is not null;
0N/A InputStream is = (InputStream)
0N/A java.security.AccessController.doPrivileged(
0N/A new java.security.PrivilegedAction() {
0N/A public Object run() {
0N/A return loader.getResourceAsStream(serName);
0N/A }
0N/A });
0N/A ObjectInputStream ois =
0N/A new AppletObjectInputStream(is, loader);
0N/A Object serObject = ois.readObject();
0N/A applet = (Applet) serObject;
0N/A doInit = false; // skip over the first init
0N/A }
0N/A
0N/A // Determine the JDK level that the applet targets.
0N/A // This is critical for enabling certain backward
0N/A // compatibility switch if an applet is a JDK 1.1
0N/A // applet. [stanley.ho]
0N/A findAppletJDKLevel(applet);
0N/A
0N/A if (Thread.interrupted()) {
0N/A try {
0N/A status = APPLET_DISPOSE; // APPLET_ERROR?
0N/A applet = null;
0N/A // REMIND: This may not be exactly the right thing: the
0N/A // status is set by the stop button and not necessarily
0N/A // here.
0N/A showAppletStatus("death");
0N/A } finally {
0N/A Thread.currentThread().interrupt(); // resignal interrupt
0N/A }
0N/A return null;
0N/A }
0N/A return applet;
0N/A }
0N/A
0N/A protected void loadJarFiles(AppletClassLoader loader) throws IOException,
0N/A InterruptedException {
0N/A // Load the archives if present.
0N/A // REMIND - this probably should be done in a separate thread,
0N/A // or at least the additional archives (epll).
0N/A String jarFiles = getJarFiles();
0N/A
0N/A if (jarFiles != null) {
0N/A StringTokenizer st = new StringTokenizer(jarFiles, ",", false);
0N/A while(st.hasMoreTokens()) {
0N/A String tok = st.nextToken().trim();
0N/A try {
0N/A loader.addJar(tok);
0N/A } catch (IllegalArgumentException e) {
0N/A // bad archive name
0N/A continue;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Request that the loading of the applet be stopped.
0N/A */
0N/A protected synchronized void stopLoading() {
0N/A // REMIND: fill in the body
0N/A if (loaderThread != null) {
0N/A //System.out.println("Interrupting applet loader thread: " + loaderThread);
0N/A loaderThread.interrupt();
0N/A } else {
0N/A setLoadAbortRequest();
0N/A }
0N/A }
0N/A
0N/A
0N/A protected synchronized boolean okToLoad() {
0N/A return !loadAbortRequest;
0N/A }
0N/A
0N/A protected synchronized void clearLoadAbortRequest() {
0N/A loadAbortRequest = false;
0N/A }
0N/A
0N/A protected synchronized void setLoadAbortRequest() {
0N/A loadAbortRequest = true;
0N/A }
0N/A
0N/A
0N/A private synchronized void setLoaderThread(Thread loaderThread) {
0N/A this.loaderThread = loaderThread;
0N/A }
0N/A
0N/A /**
0N/A * Return true when the applet has been started.
0N/A */
0N/A public boolean isActive() {
0N/A return status == APPLET_START;
0N/A }
0N/A
0N/A
0N/A private EventQueue appEvtQ = null;
0N/A /**
0N/A * Is called when the applet wants to be resized.
0N/A */
0N/A public void appletResize(int width, int height) {
0N/A currentAppletSize.width = width;
0N/A currentAppletSize.height = height;
0N/A final Dimension currentSize = new Dimension(currentAppletSize.width,
0N/A currentAppletSize.height);
0N/A
0N/A if(loader != null) {
0N/A AppContext appCtxt = loader.getAppContext();
0N/A if(appCtxt != null)
0N/A appEvtQ = (java.awt.EventQueue)appCtxt.get(AppContext.EVENT_QUEUE_KEY);
0N/A }
0N/A
0N/A final AppletPanel ap = this;
0N/A if (appEvtQ != null){
0N/A appEvtQ.postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
0N/A new Runnable(){
0N/A public void run(){
0N/A if(ap != null)
0N/A {
0N/A ap.dispatchAppletEvent(APPLET_RESIZE, currentSize);
0N/A }
0N/A }
0N/A }));
0N/A }
0N/A }
0N/A
0N/A public void setBounds(int x, int y, int width, int height) {
0N/A super.setBounds(x, y, width, height);
0N/A currentAppletSize.width = width;
0N/A currentAppletSize.height = height;
0N/A }
0N/A
0N/A public Applet getApplet() {
0N/A return applet;
0N/A }
0N/A
0N/A /**
0N/A * Status line. Called by the AppletPanel to provide
0N/A * feedback on the Applet's state.
0N/A */
0N/A protected void showAppletStatus(String status) {
0N/A getAppletContext().showStatus(amh.getMessage(status));
0N/A }
0N/A
0N/A protected void showAppletStatus(String status, Object arg) {
0N/A getAppletContext().showStatus(amh.getMessage(status, arg));
0N/A }
0N/A protected void showAppletStatus(String status, Object arg1, Object arg2) {
0N/A getAppletContext().showStatus(amh.getMessage(status, arg1, arg2));
0N/A }
0N/A
0N/A /**
0N/A * Called by the AppletPanel to print to the log.
0N/A */
0N/A protected void showAppletLog(String msg) {
0N/A System.out.println(amh.getMessage(msg));
0N/A }
0N/A
0N/A protected void showAppletLog(String msg, Object arg) {
0N/A System.out.println(amh.getMessage(msg, arg));
0N/A }
0N/A
0N/A /**
0N/A * Called by the AppletPanel to provide
0N/A * feedback when an exception has happened.
0N/A */
0N/A protected void showAppletException(Throwable t) {
0N/A t.printStackTrace();
0N/A repaint();
0N/A }
0N/A
0N/A /**
0N/A * Get caching key for classloader cache
0N/A */
0N/A public String getClassLoaderCacheKey()
0N/A {
0N/A /**
0N/A * Fixed #4501142: Classlaoder sharing policy doesn't
0N/A * take "archive" into account. This will be overridden
0N/A * by Java Plug-in. [stanleyh]
0N/A */
0N/A return getCodeBase().toString();
0N/A }
0N/A
0N/A /**
0N/A * The class loaders
0N/A */
0N/A private static HashMap classloaders = new HashMap();
0N/A
0N/A /**
0N/A * Flush a class loader.
0N/A */
0N/A public static synchronized void flushClassLoader(String key) {
0N/A classloaders.remove(key);
0N/A }
0N/A
0N/A /**
0N/A * Flush all class loaders.
0N/A */
0N/A public static synchronized void flushClassLoaders() {
0N/A classloaders = new HashMap();
0N/A }
0N/A
0N/A /**
0N/A * This method actually creates an AppletClassLoader.
0N/A *
0N/A * It can be override by subclasses (such as the Plug-in)
0N/A * to provide different classloaders.
0N/A */
0N/A protected AppletClassLoader createClassLoader(final URL codebase) {
0N/A return new AppletClassLoader(codebase);
0N/A }
0N/A
0N/A /**
0N/A * Get a class loader. Create in a restricted context
0N/A */
0N/A synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) {
0N/A AppletClassLoader c = (AppletClassLoader)classloaders.get(key);
0N/A if (c == null) {
0N/A AccessControlContext acc =
0N/A getAccessControlContext(codebase);
0N/A c = (AppletClassLoader)
0N/A AccessController.doPrivileged(new PrivilegedAction() {
0N/A public Object run() {
0N/A AppletClassLoader ac = createClassLoader(codebase);
0N/A /* Should the creation of the classloader be
0N/A * within the class synchronized block? Since
0N/A * this class is used by the plugin, take care
0N/A * to avoid deadlocks, or specialize
0N/A * AppletPanel within the plugin. It may take
0N/A * an arbitrary amount of time to create a
0N/A * class loader (involving getting Jar files
0N/A * etc.) and may block unrelated applets from
0N/A * finishing createAppletThread (due to the
0N/A * class synchronization). If
0N/A * createAppletThread does not finish quickly,
0N/A * the applet cannot process other messages,
0N/A * particularly messages such as destroy
0N/A * (which timeout when called from the browser).
0N/A */
0N/A synchronized (getClass()) {
0N/A AppletClassLoader res =
0N/A (AppletClassLoader)classloaders.get(key);
0N/A if (res == null) {
0N/A classloaders.put(key, ac);
0N/A return ac;
0N/A } else {
0N/A return res;
0N/A }
0N/A }
0N/A }
0N/A },acc);
0N/A }
0N/A return c;
0N/A }
0N/A
0N/A /**
0N/A * get the context for the AppletClassLoader we are creating.
0N/A * the context is granted permission to create the class loader,
0N/A * connnect to the codebase, and whatever else the policy grants
0N/A * to all codebases.
0N/A */
0N/A private AccessControlContext getAccessControlContext(final URL codebase) {
0N/A
0N/A PermissionCollection perms = (PermissionCollection)
0N/A AccessController.doPrivileged(new PrivilegedAction() {
0N/A public Object run() {
0N/A Policy p = java.security.Policy.getPolicy();
0N/A if (p != null) {
0N/A return p.getPermissions(new CodeSource(null,
0N/A (java.security.cert.Certificate[]) null));
0N/A } else {
0N/A return null;
0N/A }
0N/A }
0N/A });
0N/A
0N/A if (perms == null)
0N/A perms = new Permissions();
0N/A
0N/A //XXX: this is needed to be able to create the classloader itself!
0N/A
0N/A perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
0N/A
0N/A Permission p;
0N/A java.net.URLConnection urlConnection = null;
0N/A try {
0N/A urlConnection = codebase.openConnection();
0N/A p = urlConnection.getPermission();
0N/A } catch (java.io.IOException ioe) {
0N/A p = null;
0N/A }
0N/A
0N/A if (p != null)
0N/A perms.add(p);
0N/A
0N/A if (p instanceof FilePermission) {
0N/A
0N/A String path = p.getName();
0N/A
0N/A int endIndex = path.lastIndexOf(File.separatorChar);
0N/A
0N/A if (endIndex != -1) {
0N/A path = path.substring(0, endIndex+1);
0N/A
0N/A if (path.endsWith(File.separator)) {
0N/A path += "-";
0N/A }
0N/A perms.add(new FilePermission(path,
0N/A SecurityConstants.FILE_READ_ACTION));
0N/A }
0N/A } else {
0N/A URL locUrl = codebase;
0N/A if (urlConnection instanceof JarURLConnection) {
0N/A locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
0N/A }
0N/A String host = locUrl.getHost();
0N/A if (host != null && (host.length() > 0))
0N/A perms.add(new SocketPermission(host,
0N/A SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION));
0N/A }
0N/A
0N/A ProtectionDomain domain =
0N/A new ProtectionDomain(new CodeSource(codebase,
0N/A (java.security.cert.Certificate[]) null), perms);
0N/A AccessControlContext acc =
0N/A new AccessControlContext(new ProtectionDomain[] { domain });
0N/A
0N/A return acc;
0N/A }
0N/A
0N/A public Thread getAppletHandlerThread() {
0N/A return handler;
0N/A }
0N/A
0N/A public int getAppletWidth() {
0N/A return currentAppletSize.width;
0N/A }
0N/A
0N/A public int getAppletHeight() {
0N/A return currentAppletSize.height;
0N/A }
0N/A
0N/A public static void changeFrameAppContext(Frame frame, AppContext newAppContext)
0N/A {
0N/A // Fixed #4754451: Applet can have methods running on main
0N/A // thread event queue.
0N/A //
0N/A // The cause of this bug is that the frame of the applet
0N/A // is created in main thread group. Thus, when certain
0N/A // AWT/Swing events are generated, the events will be
0N/A // dispatched through the wrong event dispatch thread.
0N/A //
0N/A // To fix this, we rearrange the AppContext with the frame,
0N/A // so the proper event queue will be looked up.
0N/A //
0N/A // Swing also maintains a Frame list for the AppContext,
0N/A // so we will have to rearrange it as well.
0N/A
0N/A // Check if frame's AppContext has already been set properly
0N/A AppContext oldAppContext = SunToolkit.targetToAppContext(frame);
0N/A
0N/A if (oldAppContext == newAppContext)
0N/A return;
0N/A
0N/A // Synchronization on Window.class is needed for locking the
0N/A // critical section of the window list in AppContext.
0N/A synchronized (Window.class)
0N/A {
0N/A WeakReference weakRef = null;
0N/A // Remove frame from the Window list in wrong AppContext
0N/A {
0N/A // Lookup current frame's AppContext
0N/A Vector<WeakReference<Window>> windowList = (Vector<WeakReference<Window>>)oldAppContext.get(Window.class);
0N/A if (windowList != null) {
0N/A for (WeakReference ref : windowList) {
0N/A if (ref.get() == frame) {
0N/A weakRef = ref;
0N/A break;
0N/A }
0N/A }
0N/A // Remove frame from wrong AppContext
0N/A if (weakRef != null)
0N/A windowList.remove(weakRef);
0N/A }
0N/A }
0N/A
0N/A // Put the frame into the applet's AppContext map
0N/A SunToolkit.insertTargetMapping(frame, newAppContext);
0N/A
0N/A // Insert frame into the Window list in the applet's AppContext map
0N/A {
0N/A Vector<WeakReference<Window>> windowList = (Vector)newAppContext.get(Window.class);
0N/A if (windowList == null) {
0N/A windowList = new Vector<WeakReference<Window>>();
0N/A newAppContext.put(Window.class, windowList);
0N/A }
0N/A // use the same weakRef here as it is used elsewhere
0N/A windowList.add(weakRef);
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Flag to indicate if applet is targeted for JDK 1.1.
0N/A private boolean jdk11Applet = false;
0N/A
0N/A // Flag to indicate if applet is targeted for JDK 1.2.
0N/A private boolean jdk12Applet = false;
0N/A
0N/A /**
0N/A * Determine JDK level of an applet.
0N/A */
0N/A private void findAppletJDKLevel(Applet applet)
0N/A {
0N/A // To determine the JDK level of an applet, the
0N/A // most reliable way is to check the major version
0N/A // of the applet class file.
0N/A
0N/A // synchronized on applet class object, so calling from
0N/A // different instances of the same applet will be
0N/A // serialized.
0N/A Class appletClass = applet.getClass();
0N/A
0N/A synchronized(appletClass) {
0N/A // Determine if the JDK level of an applet has been
0N/A // checked before.
0N/A Boolean jdk11Target = (Boolean) loader.isJDK11Target(appletClass);
0N/A Boolean jdk12Target = (Boolean) loader.isJDK12Target(appletClass);
0N/A
0N/A // if applet JDK level has been checked before, retrieve
0N/A // value and return.
0N/A if (jdk11Target != null || jdk12Target != null) {
0N/A jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue();
0N/A jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue();
0N/A return;
0N/A }
0N/A
0N/A String name = appletClass.getName();
0N/A
0N/A // first convert any '.' to '/'
0N/A name = name.replace('.', '/');
0N/A
0N/A // append .class
0N/A final String resourceName = name + ".class";
0N/A
0N/A InputStream is = null;
0N/A byte[] classHeader = new byte[8];
0N/A
0N/A try {
0N/A is = (InputStream) java.security.AccessController.doPrivileged(
0N/A new java.security.PrivilegedAction() {
0N/A public Object run() {
0N/A return loader.getResourceAsStream(resourceName);
0N/A }
0N/A });
0N/A
0N/A // Read the first 8 bytes of the class file
0N/A int byteRead = is.read(classHeader, 0, 8);
0N/A is.close();
0N/A
0N/A // return if the header is not read in entirely
0N/A // for some reasons.
0N/A if (byteRead != 8)
0N/A return;
0N/A }
0N/A catch (IOException e) {
0N/A return;
0N/A }
0N/A
0N/A // Check major version in class file header
0N/A int major_version = readShort(classHeader, 6);
0N/A
0N/A // Major version in class file is as follows:
0N/A // 45 - JDK 1.1
0N/A // 46 - JDK 1.2
0N/A // 47 - JDK 1.3
0N/A // 48 - JDK 1.4
0N/A // 49 - JDK 1.5
0N/A if (major_version < 46)
0N/A jdk11Applet = true;
0N/A else if (major_version == 46)
0N/A jdk12Applet = true;
0N/A
0N/A // Store applet JDK level in AppContext for later lookup,
0N/A // e.g. page switch.
0N/A loader.setJDK11Target(appletClass, jdk11Applet);
0N/A loader.setJDK12Target(appletClass, jdk12Applet);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Return true if applet is targeted to JDK 1.1.
0N/A */
0N/A protected boolean isJDK11Applet() {
0N/A return jdk11Applet;
0N/A }
0N/A
0N/A /**
0N/A * Return true if applet is targeted to JDK1.2.
0N/A */
0N/A protected boolean isJDK12Applet() {
0N/A return jdk12Applet;
0N/A }
0N/A
0N/A /**
0N/A * Read short from byte array.
0N/A */
0N/A private int readShort(byte[] b, int off) {
0N/A int hi = readByte(b[off]);
0N/A int lo = readByte(b[off + 1]);
0N/A return (hi << 8) | lo;
0N/A }
0N/A
0N/A private int readByte(byte b) {
0N/A return ((int)b) & 0xFF;
0N/A }
0N/A
0N/A
0N/A private static AppletMessageHandler amh = new AppletMessageHandler("appletpanel");
0N/A}