/* * Copyright (c) 1995, 2015, 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.io.*; import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.JarURLConnection; import java.net.SocketPermission; import java.net.URL; import java.security.*; import java.util.*; import java.util.Locale; import java.util.concurrent.LinkedBlockingQueue; import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.EmbeddedFrame; import sun.awt.SunToolkit; import sun.awt.util.PerformanceLogger; 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 */ @SuppressWarnings({"serial", "deprecation"}) // JDK implementation class public abstract class AppletPanel extends Panel implements AppletStub, Runnable { /** * The applet (if loaded). */ Applet applet; /** * The classloader for the applet. */ protected AppletClassLoader loader; /* applet event ids */ public static final int APPLET_DISPOSE = 0; public static final int APPLET_LOAD = 1; public static final int APPLET_INIT = 2; public static final int APPLET_START = 3; public static final int APPLET_STOP = 4; public static final int APPLET_DESTROY = 5; public static final int APPLET_QUIT = 6; public static final int APPLET_ERROR = 7; /* send to the parent to force relayout */ public static final int APPLET_RESIZE = 51234; /* sent to a (distant) parent to indicate that the applet is being * loaded or as completed loading */ public static final int APPLET_LOADING = 51235; public static final 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); /** * The thread to use during applet loading */ Thread loaderThread = null; /** * Flag to indicate that a loading has been cancelled */ boolean loadAbortRequest = false; /* abstract classes */ protected abstract String getCode(); protected abstract String getJarFiles(); @Override public abstract int getWidth(); @Override public abstract int getHeight(); public abstract 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, 0, false); // set the context class loader for this thread AccessController.doPrivileged(new PrivilegedAction() { @Override 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 */ @Override @SuppressWarnings("deprecation") public Dimension minimumSize() { return new Dimension(defaultAppletSize.width, defaultAppletSize.height); } /** * Preferred size */ @Override @SuppressWarnings("deprecation") public Dimension preferredSize() { return new Dimension(currentAppletSize.width, currentAppletSize.height); } private AppletListener listeners; /** * AppletEvent Queue */ private LinkedBlockingQueue queue = null; public synchronized void addAppletListener(AppletListener l) { listeners = AppletEventMulticaster.add(listeners, l); } public synchronized 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 LinkedBlockingQueue<>(); } boolean inserted = queue.add(id); 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(); } int eventId = queue.take(); return new AppletEvent(this, eventId, 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 * *
{@literal
     *   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. * */ @Override 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) { setLoaderThread(new Thread(null, this, "AppletLoader", 0, false)); 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 (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)); } // Validate the applet in event dispatch thread // to avoid deadlock. try { final AppletPanel p = this; Runnable r = new Runnable() { @Override public void run() { p.validate(); } }; AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } 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; Runnable r = new Runnable() { @Override public void run() { p.validate(); a.setVisible(true); // Fix for BugTraq ID 4041703. // Set the default focus for an applet. if (hasInitialFocus()) { setDefaultFocus(); } } }; AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { } catch(InvocationTargetException ite) { } status = APPLET_START; showAppletStatus("started"); break; } case APPLET_STOP: if (status != APPLET_START) { showAppletStatus("notstarted"); break; } status = APPLET_STOP; // Hide the applet in event dispatch thread // to avoid deadlock. try { final Applet a = applet; Runnable r = new Runnable() { @Override public void run() { a.setVisible(false); } }; AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { } catch(InvocationTargetException ite) { } // During Applet.stop(), any AccessControlException on an involved Class remains in // the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is // reused, the same exception will occur during class loading. Set the AppletClassLoader's // exceptionStatusSet flag to allow recognition of what had happened // when reusing AppletClassLoader object. try { applet.stop(); } catch (java.security.AccessControlException e) { setExceptionStatus(e); // rethrow exception to be handled as it normally would be. throw e; } showAppletStatus("stopped"); break; case APPLET_DESTROY: if (status != APPLET_STOP && status != APPLET_INIT) { showAppletStatus("notstopped"); break; } status = APPLET_DESTROY; // During Applet.destroy(), any AccessControlException on an involved Class remains in // the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is // reused, the same exception will occur during class loading. Set the AppletClassLoader's // exceptionStatusSet flag to allow recognition of what had happened // when reusing AppletClassLoader object. try { applet.destroy(); } catch (java.security.AccessControlException e) { setExceptionStatus(e); // rethrow exception to be handled as it normally would be. throw e; } showAppletStatus("destroyed"); break; case APPLET_DISPOSE: if (status != APPLET_DESTROY && status != APPLET_LOAD) { showAppletStatus("notdestroyed"); break; } status = APPLET_DISPOSE; try { final Applet a = applet; Runnable r = new Runnable() { @Override public void run() { remove(a); } }; AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r); } catch(InterruptedException ie) { } catch(InvocationTargetException ite) { } applet = null; showAppletStatus("disposed"); disposed = true; break; case APPLET_QUIT: return; } } catch (Exception e) { status = APPLET_ERROR; if (e.getMessage() != null) { showAppletStatus("exception2", e.getClass().getName(), e.getMessage()); } else { showAppletStatus("exception", e.getClass().getName()); } showAppletException(e); } catch (ThreadDeath e) { showAppletStatus("death"); return; } catch (Error e) { status = APPLET_ERROR; if (e.getMessage() != null) { showAppletStatus("error2", e.getClass().getName(), e.getMessage()); } else { showAppletStatus("error", e.getClass().getName()); } showAppletException(e); } clearLoadAbortRequest(); } } /** * Gets most recent focus owner component associated with the given window. * It does that without calling Window.getMostRecentFocusOwner since it * provides its own logic contradicting with setDefautlFocus. Instead, it * calls KeyboardFocusManager directly. */ private Component getMostRecentFocusOwnerForWindow(Window w) { return AWTAccessor.getKeyboardFocusManagerAccessor() .getMostRecentFocusOwner(w); } /* * Fix for BugTraq ID 4041703. * Set the focus to a reasonable default for an Applet. */ private void setDefaultFocus() { Component toFocus = null; Container parent = getParent(); if(parent != null) { if (parent instanceof Window) { toFocus = getMostRecentFocusOwnerForWindow((Window)parent); if (toFocus == parent || toFocus == null) { toFocus = parent.getFocusTraversalPolicy(). getInitialComponent((Window)parent); } } else if (parent.isFocusCycleRoot()) { toFocus = parent.getFocusTraversalPolicy(). getDefaultComponent(parent); } } if (toFocus != null) { if (parent instanceof EmbeddedFrame) { ((EmbeddedFrame) parent).synthesizeWindowActivation(true); } // EmbeddedFrame might have focus before the applet was added. // Thus after its activation the most recent focus owner will be // restored. We need the applet's initial focusabled component to // be focused here. toFocus.requestFocusInWindow(); } } /** * 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. */ @SuppressWarnings("deprecation") private void runLoader() { if (status != APPLET_DISPOSE) { showAppletStatus("notdisposed"); return; } dispatchAppletEvent(APPLET_LOADING, null); // REMIND -- might be cool to visually indicate loading here -- // maybe do animation? status = APPLET_LOAD; // Create a class loader loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey()); // Load the archives if present. // REMIND - this probably should be done in a separate thread, // or at least the additional archives (epll). String code = getCode(); // setup applet AppContext // this must be called before loadJarFiles setupAppletAppContext(); try { loadJarFiles(loader); applet = createApplet(loader); } catch (ClassNotFoundException e) { status = APPLET_ERROR; showAppletStatus("notfound", code); showAppletLog("notfound", code); showAppletException(e); return; } catch (InstantiationException e) { status = APPLET_ERROR; showAppletStatus("nocreate", code); showAppletLog("nocreate", code); showAppletException(e); return; } catch (IllegalAccessException e) { status = APPLET_ERROR; showAppletStatus("noconstruct", code); showAppletLog("noconstruct", code); showAppletException(e); // sbb -- I added a return here return; } catch (Exception e) { status = APPLET_ERROR; showAppletStatus("exception", e.getMessage()); showAppletException(e); return; } catch (ThreadDeath e) { status = APPLET_ERROR; showAppletStatus("death"); return; } catch (Error e) { status = APPLET_ERROR; showAppletStatus("error", e.getMessage()); showAppletException(e); return; } finally { // notify that loading is no longer going on dispatchAppletEvent(APPLET_LOADING_COMPLETED, null); } // Fixed #4508194: NullPointerException thrown during // quick page switch // if (applet != null) { // Stick it in the frame applet.setStub(this); applet.hide(); add("Center", applet); showAppletStatus("loaded"); validate(); } } protected Applet createApplet(final AppletClassLoader loader) throws ClassNotFoundException, IllegalAccessException, IOException, InstantiationException, InterruptedException { String code = getCode(); if (code != null) { applet = (Applet)loader.loadCode(code).newInstance(); } else { String msg = "nocode"; status = APPLET_ERROR; showAppletStatus(msg); showAppletLog(msg); repaint(); } // Determine the JDK level that the applet targets. // This is critical for enabling certain backward // compatibility switch if an applet is a JDK 1.1 // applet. [stanley.ho] findAppletJDKLevel(applet); if (Thread.interrupted()) { try { 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("death"); } finally { Thread.currentThread().interrupt(); // resignal interrupt } return null; } return applet; } protected void loadJarFiles(AppletClassLoader loader) throws IOException, InterruptedException { // Load the archives if present. // REMIND - this probably should be done in a separate thread, // or at least the additional archives (epll). String jarFiles = getJarFiles(); if (jarFiles != null) { StringTokenizer st = new StringTokenizer(jarFiles, ",", false); while(st.hasMoreTokens()) { String tok = st.nextToken().trim(); try { loader.addJar(tok); } catch (IllegalArgumentException e) { // bad archive name continue; } } } } /** * 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. */ @Override public boolean isActive() { return status == APPLET_START; } private EventQueue appEvtQ = null; /** * Is called when the applet wants to be resized. */ @Override public void appletResize(int width, int height) { currentAppletSize.width = width; currentAppletSize.height = height; final Dimension currentSize = new Dimension(currentAppletSize.width, currentAppletSize.height); if(loader != null) { AppContext appCtxt = loader.getAppContext(); if(appCtxt != null) appEvtQ = (java.awt.EventQueue)appCtxt.get(AppContext.EVENT_QUEUE_KEY); } final AppletPanel ap = this; if (appEvtQ != null){ appEvtQ.postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(), new Runnable() { @Override public void run() { if (ap != null) { ap.dispatchAppletEvent( APPLET_RESIZE, currentSize); } } })); } } @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); currentAppletSize.width = width; currentAppletSize.height = height; } public Applet getApplet() { return applet; } /** * Status line. Called by the AppletPanel to provide * feedback on the Applet's state. */ protected void showAppletStatus(String status) { getAppletContext().showStatus(amh.getMessage(status)); } protected void showAppletStatus(String status, Object arg) { getAppletContext().showStatus(amh.getMessage(status, arg)); } protected void showAppletStatus(String status, Object arg1, Object arg2) { getAppletContext().showStatus(amh.getMessage(status, arg1, arg2)); } /** * Called by the AppletPanel to print to the log. */ protected void showAppletLog(String msg) { System.out.println(amh.getMessage(msg)); } protected void showAppletLog(String msg, Object arg) { System.out.println(amh.getMessage(msg, arg)); } /** * Called by the AppletPanel to provide * feedback when an exception has happened. */ protected void showAppletException(Throwable t) { t.printStackTrace(); repaint(); } /** * Get caching key for classloader cache */ public String getClassLoaderCacheKey() { /** * Fixed #4501142: Classloader sharing policy doesn't * take "archive" into account. This will be overridden * by Java Plug-in. [stanleyh] */ return getCodeBase().toString(); } /** * The class loaders */ private static HashMap classloaders = new HashMap<>(); /** * Flush a class loader. */ public static synchronized void flushClassLoader(String key) { classloaders.remove(key); } /** * Flush all class loaders. */ public static synchronized void flushClassLoaders() { classloaders = new HashMap<>(); } /** * This method actually creates an AppletClassLoader. * * It can be override by subclasses (such as the Plug-in) * to provide different classloaders. */ protected AppletClassLoader createClassLoader(final URL codebase) { return new AppletClassLoader(codebase); } /** * Get a class loader. Create in a restricted context */ synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) { AppletClassLoader c = classloaders.get(key); if (c == null) { AccessControlContext acc = getAccessControlContext(codebase); c = AccessController.doPrivileged( new PrivilegedAction() { @Override public AppletClassLoader run() { AppletClassLoader ac = createClassLoader(codebase); /* Should the creation of the classloader be * within the class synchronized block? Since * this class is used by the plugin, take care * to avoid deadlocks, or specialize * AppletPanel within the plugin. It may take * an arbitrary amount of time to create a * class loader (involving getting Jar files * etc.) and may block unrelated applets from * finishing createAppletThread (due to the * class synchronization). If * createAppletThread does not finish quickly, * the applet cannot process other messages, * particularly messages such as destroy * (which timeout when called from the browser). */ synchronized (getClass()) { AppletClassLoader res = classloaders.get(key); if (res == null) { classloaders.put(key, ac); return ac; } else { return res; } } } },acc); } return c; } /** * get the context for the AppletClassLoader we are creating. * the context is granted permission to create the class loader, * connnect to the codebase, and whatever else the policy grants * to all codebases. */ private AccessControlContext getAccessControlContext(final URL codebase) { PermissionCollection perms = AccessController.doPrivileged( new PrivilegedAction() { @Override public PermissionCollection run() { Policy p = java.security.Policy.getPolicy(); if (p != null) { return p.getPermissions(new CodeSource(null, (java.security.cert.Certificate[]) null)); } else { return null; } } }); if (perms == null) perms = new Permissions(); //XXX: this is needed to be able to create the classloader itself! perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); Permission p; java.net.URLConnection urlConnection = null; try { urlConnection = codebase.openConnection(); p = urlConnection.getPermission(); } catch (java.io.IOException ioe) { p = null; } if (p != null) perms.add(p); if (p instanceof FilePermission) { String path = p.getName(); int endIndex = path.lastIndexOf(File.separatorChar); if (endIndex != -1) { path = path.substring(0, endIndex+1); if (path.endsWith(File.separator)) { path += "-"; } perms.add(new FilePermission(path, SecurityConstants.FILE_READ_ACTION)); } } else { URL locUrl = codebase; if (urlConnection instanceof JarURLConnection) { locUrl = ((JarURLConnection)urlConnection).getJarFileURL(); } String host = locUrl.getHost(); if (host != null && (host.length() > 0)) perms.add(new SocketPermission(host, SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION)); } ProtectionDomain domain = new ProtectionDomain(new CodeSource(codebase, (java.security.cert.Certificate[]) null), perms); AccessControlContext acc = new AccessControlContext(new ProtectionDomain[] { domain }); return acc; } public Thread getAppletHandlerThread() { return handler; } public int getAppletWidth() { return currentAppletSize.width; } public int getAppletHeight() { return currentAppletSize.height; } public static void changeFrameAppContext(Frame frame, AppContext newAppContext) { // Fixed #4754451: Applet can have methods running on main // thread event queue. // // The cause of this bug is that the frame of the applet // is created in main thread group. Thus, when certain // AWT/Swing events are generated, the events will be // dispatched through the wrong event dispatch thread. // // To fix this, we rearrange the AppContext with the frame, // so the proper event queue will be looked up. // // Swing also maintains a Frame list for the AppContext, // so we will have to rearrange it as well. // Check if frame's AppContext has already been set properly AppContext oldAppContext = SunToolkit.targetToAppContext(frame); if (oldAppContext == newAppContext) return; // Synchronization on Window.class is needed for locking the // critical section of the window list in AppContext. synchronized (Window.class) { WeakReference weakRef = null; // Remove frame from the Window list in wrong AppContext { // Lookup current frame's AppContext @SuppressWarnings("unchecked") Vector> windowList = (Vector>)oldAppContext.get(Window.class); if (windowList != null) { for (WeakReference ref : windowList) { if (ref.get() == frame) { weakRef = ref; break; } } // Remove frame from wrong AppContext if (weakRef != null) windowList.remove(weakRef); } } // Put the frame into the applet's AppContext map SunToolkit.insertTargetMapping(frame, newAppContext); // Insert frame into the Window list in the applet's AppContext map { @SuppressWarnings("unchecked") Vector> windowList = (Vector>)newAppContext.get(Window.class); if (windowList == null) { windowList = new Vector>(); newAppContext.put(Window.class, windowList); } // use the same weakRef here as it is used elsewhere windowList.add(weakRef); } } } // Flag to indicate if applet is targeted for JDK 1.1. private boolean jdk11Applet = false; // Flag to indicate if applet is targeted for JDK 1.2. private boolean jdk12Applet = false; /** * Determine JDK level of an applet. */ private void findAppletJDKLevel(Applet applet) { // To determine the JDK level of an applet, the // most reliable way is to check the major version // of the applet class file. // synchronized on applet class object, so calling from // different instances of the same applet will be // serialized. Class appletClass = applet.getClass(); synchronized(appletClass) { // Determine if the JDK level of an applet has been // checked before. Boolean jdk11Target = loader.isJDK11Target(appletClass); Boolean jdk12Target = loader.isJDK12Target(appletClass); // if applet JDK level has been checked before, retrieve // value and return. if (jdk11Target != null || jdk12Target != null) { jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue(); jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue(); return; } String name = appletClass.getName(); // first convert any '.' to '/' name = name.replace('.', '/'); // append .class final String resourceName = name + ".class"; byte[] classHeader = new byte[8]; try (InputStream is = AccessController.doPrivileged( (PrivilegedAction) () -> loader.getResourceAsStream(resourceName))) { // Read the first 8 bytes of the class file int byteRead = is.read(classHeader, 0, 8); // return if the header is not read in entirely // for some reasons. if (byteRead != 8) return; } catch (IOException e) { return; } // Check major version in class file header int major_version = readShort(classHeader, 6); // Major version in class file is as follows: // 45 - JDK 1.1 // 46 - JDK 1.2 // 47 - JDK 1.3 // 48 - JDK 1.4 // 49 - JDK 1.5 if (major_version < 46) jdk11Applet = true; else if (major_version == 46) jdk12Applet = true; // Store applet JDK level in AppContext for later lookup, // e.g. page switch. loader.setJDK11Target(appletClass, jdk11Applet); loader.setJDK12Target(appletClass, jdk12Applet); } } /** * Return true if applet is targeted to JDK 1.1. */ protected boolean isJDK11Applet() { return jdk11Applet; } /** * Return true if applet is targeted to JDK1.2. */ protected boolean isJDK12Applet() { return jdk12Applet; } /** * Read short from byte array. */ private int readShort(byte[] b, int off) { int hi = readByte(b[off]); int lo = readByte(b[off + 1]); return (hi << 8) | lo; } private int readByte(byte b) { return ((int)b) & 0xFF; } private static AppletMessageHandler amh = new AppletMessageHandler("appletpanel"); }