Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/applet/AppletPanel.java
38829 views
/*1* Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.applet;2627import java.applet.*;28import java.awt.*;29import java.awt.event.*;30import java.io.*;31import java.lang.ref.WeakReference;32import java.lang.reflect.InvocationTargetException;33import java.lang.reflect.Method;34import java.net.JarURLConnection;35import java.net.SocketPermission;36import java.net.URL;37import java.security.*;38import java.util.*;39import java.util.Locale;40import sun.awt.AWTAccessor;41import sun.awt.AppContext;42import sun.awt.EmbeddedFrame;43import sun.awt.SunToolkit;44import sun.misc.MessageUtils;45import sun.misc.PerformanceLogger;46import sun.misc.Queue;47import sun.security.util.SecurityConstants;4849/**50* Applet panel class. The panel manages and manipulates the51* applet as it is being loaded. It forks a separate thread in a new52* thread group to call the applet's init(), start(), stop(), and53* destroy() methods.54*55* @author Arthur van Hoff56*/57public58abstract class AppletPanel extends Panel implements AppletStub, Runnable {5960/**61* The applet (if loaded).62*/63Applet applet;6465/**66* Applet will allow initialization. Should be67* set to false if loading a serialized applet68* that was pickled in the init=true state.69*/70protected boolean doInit = true;717273/**74* The classloader for the applet.75*/76protected AppletClassLoader loader;7778/* applet event ids */79public final static int APPLET_DISPOSE = 0;80public final static int APPLET_LOAD = 1;81public final static int APPLET_INIT = 2;82public final static int APPLET_START = 3;83public final static int APPLET_STOP = 4;84public final static int APPLET_DESTROY = 5;85public final static int APPLET_QUIT = 6;86public final static int APPLET_ERROR = 7;8788/* send to the parent to force relayout */89public final static int APPLET_RESIZE = 51234;9091/* sent to a (distant) parent to indicate that the applet is being92* loaded or as completed loading93*/94public final static int APPLET_LOADING = 51235;95public final static int APPLET_LOADING_COMPLETED = 51236;9697/**98* The current status. One of:99* APPLET_DISPOSE,100* APPLET_LOAD,101* APPLET_INIT,102* APPLET_START,103* APPLET_STOP,104* APPLET_DESTROY,105* APPLET_ERROR.106*/107protected int status;108109/**110* The thread for the applet.111*/112protected Thread handler;113114115/**116* The initial applet size.117*/118Dimension defaultAppletSize = new Dimension(10, 10);119120/**121* The current applet size.122*/123Dimension currentAppletSize = new Dimension(10, 10);124125MessageUtils mu = new MessageUtils();126127/**128* The thread to use during applet loading129*/130131Thread loaderThread = null;132133/**134* Flag to indicate that a loading has been cancelled135*/136boolean loadAbortRequest = false;137138/* abstract classes */139abstract protected String getCode();140abstract protected String getJarFiles();141abstract protected String getSerializedObject();142143@Override144abstract public int getWidth();145@Override146abstract public int getHeight();147abstract public boolean hasInitialFocus();148149private static int threadGroupNumber = 0;150151protected void setupAppletAppContext() {152// do nothing153}154155/*156* Creates a thread to run the applet. This method is called157* each time an applet is loaded and reloaded.158*/159synchronized void createAppletThread() {160// Create a thread group for the applet, and start a new161// thread to load the applet.162String nm = "applet-" + getCode();163loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());164loader.grab(); // Keep this puppy around!165166// 4668479: Option to turn off codebase lookup in AppletClassLoader167// during resource requests. [stanley.ho]168String param = getParameter("codebase_lookup");169170if (param != null && param.equals("false"))171loader.setCodebaseLookup(false);172else173loader.setCodebaseLookup(true);174175176ThreadGroup appletGroup = loader.getThreadGroup();177178handler = new Thread(appletGroup, this, "thread " + nm);179// set the context class loader for this thread180AccessController.doPrivileged(new PrivilegedAction() {181@Override182public Object run() {183handler.setContextClassLoader(loader);184return null;185}186});187handler.start();188}189190void joinAppletThread() throws InterruptedException {191if (handler != null) {192handler.join();193handler = null;194}195}196197void release() {198if (loader != null) {199loader.release();200loader = null;201}202}203204/**205* Construct an applet viewer and start the applet.206*/207public void init() {208try {209// Get the width (if any)210defaultAppletSize.width = getWidth();211currentAppletSize.width = defaultAppletSize.width;212213// Get the height (if any)214defaultAppletSize.height = getHeight();215currentAppletSize.height = defaultAppletSize.height;216217} catch (NumberFormatException e) {218// Turn on the error flag and let TagAppletPanel219// do the right thing.220status = APPLET_ERROR;221showAppletStatus("badattribute.exception");222showAppletLog("badattribute.exception");223showAppletException(e);224}225226setLayout(new BorderLayout());227228createAppletThread();229}230231/**232* Minimum size233*/234@Override235public Dimension minimumSize() {236return new Dimension(defaultAppletSize.width,237defaultAppletSize.height);238}239240/**241* Preferred size242*/243@Override244public Dimension preferredSize() {245return new Dimension(currentAppletSize.width,246currentAppletSize.height);247}248249private AppletListener listeners;250251/**252* AppletEvent Queue253*/254private Queue queue = null;255256257synchronized public void addAppletListener(AppletListener l) {258listeners = AppletEventMulticaster.add(listeners, l);259}260261synchronized public void removeAppletListener(AppletListener l) {262listeners = AppletEventMulticaster.remove(listeners, l);263}264265/**266* Dispatch event to the listeners..267*/268public void dispatchAppletEvent(int id, Object argument) {269//System.out.println("SEND= " + id);270if (listeners != null) {271AppletEvent evt = new AppletEvent(this, id, argument);272listeners.appletStateChanged(evt);273}274}275276/**277* Send an event. Queue it for execution by the handler thread.278*/279public void sendEvent(int id) {280synchronized(this) {281if (queue == null) {282//System.out.println("SEND0= " + id);283queue = new Queue();284}285Integer eventId = Integer.valueOf(id);286queue.enqueue(eventId);287notifyAll();288}289if (id == APPLET_QUIT) {290try {291joinAppletThread(); // Let the applet event handler exit292} catch (InterruptedException e) {293}294295// AppletClassLoader.release() must be called by a Thread296// not within the applet's ThreadGroup297if (loader == null)298loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());299release();300}301}302303/**304* Get an event from the queue.305*/306synchronized AppletEvent getNextEvent() throws InterruptedException {307while (queue == null || queue.isEmpty()) {308wait();309}310Integer eventId = (Integer)queue.dequeue();311return new AppletEvent(this, eventId.intValue(), null);312}313314boolean emptyEventQueue() {315if ((queue == null) || (queue.isEmpty()))316return true;317else318return false;319}320321/**322* This kludge is specific to get over AccessControlException thrown during323* Applet.stop() or destroy() when static thread is suspended. Set a flag324* in AppletClassLoader to indicate that an325* AccessControlException for RuntimePermission "modifyThread" or326* "modifyThreadGroup" had occurred.327*/328private void setExceptionStatus(AccessControlException e) {329Permission p = e.getPermission();330if (p instanceof RuntimePermission) {331if (p.getName().startsWith("modifyThread")) {332if (loader == null)333loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());334loader.setExceptionStatus();335}336}337}338339/**340* Execute applet events.341* Here is the state transition diagram342*343* Note: (XXX) is the action344* APPLET_XXX is the state345* (applet code loaded) --> APPLET_LOAD -- (applet init called)--> APPLET_INIT -- (346* applet start called) --> APPLET_START -- (applet stop called) -->APPLET_STOP --(applet347* destroyed called) --> APPLET_DESTROY -->(applet gets disposed) -->348* APPLET_DISPOSE -->....349*350* In the legacy lifecycle model. The applet gets loaded, inited and started. So it stays351* in the APPLET_START state unless the applet goes away(refresh page or leave the page).352* So the applet stop method called and the applet enters APPLET_STOP state. Then if the applet353* is revisited, it will call applet start method and enter the APPLET_START state and stay there.354*355* In the modern lifecycle model. When the applet first time visited, it is same as legacy lifecycle356* model. However, when the applet page goes away. It calls applet stop method and enters APPLET_STOP357* state and then applet destroyed method gets called and enters APPLET_DESTROY state.358*359* This code is also called by AppletViewer. In AppletViewer "Restart" menu, the applet is jump from360* APPLET_STOP to APPLET_DESTROY and to APPLET_INIT .361*362* Also, the applet can jump from APPLET_INIT state to APPLET_DESTROY (in Netscape/Mozilla case).363* Same as APPLET_LOAD to364* APPLET_DISPOSE since all of this are triggered by browser.365*366*367*/368@Override369public void run() {370371Thread curThread = Thread.currentThread();372if (curThread == loaderThread) {373// if we are in the loader thread, cause374// loading to occur. We may exit this with375// status being APPLET_DISPOSE, APPLET_ERROR,376// or APPLET_LOAD377runLoader();378return;379}380381boolean disposed = false;382while (!disposed && !curThread.isInterrupted()) {383AppletEvent evt;384try {385evt = getNextEvent();386} catch (InterruptedException e) {387showAppletStatus("bail");388return;389}390391//showAppletStatus("EVENT = " + evt.getID());392try {393switch (evt.getID()) {394case APPLET_LOAD:395if (!okToLoad()) {396break;397}398// This complexity allows loading of applets to be399// interruptable. The actual thread loading runs400// in a separate thread, so it can be interrupted401// without harming the applet thread.402// So that we don't have to worry about403// concurrency issues, the main applet thread waits404// until the loader thread terminates.405// (one way or another).406if (loaderThread == null) {407// REMIND: do we want a name?408//System.out.println("------------------- loading applet");409setLoaderThread(new Thread(this));410loaderThread.start();411// we get to go to sleep while this runs412loaderThread.join();413setLoaderThread(null);414} else {415// REMIND: issue an error -- this case should never416// occur.417}418break;419420case APPLET_INIT:421// AppletViewer "Restart" will jump from destroy method to422// init, that is why we need to check status w/ APPLET_DESTROY423if (status != APPLET_LOAD && status != APPLET_DESTROY) {424showAppletStatus("notloaded");425break;426}427applet.resize(defaultAppletSize);428if (doInit) {429if (PerformanceLogger.loggingEnabled()) {430PerformanceLogger.setTime("Applet Init");431PerformanceLogger.outputLog();432}433applet.init();434}435436//Need the default(fallback) font to be created in this AppContext437Font f = getFont();438if (f == null ||439"dialog".equals(f.getFamily().toLowerCase(Locale.ENGLISH)) &&440f.getSize() == 12 && f.getStyle() == Font.PLAIN) {441setFont(new Font(Font.DIALOG, Font.PLAIN, 12));442}443444doInit = true; // allow restarts445446// Validate the applet in event dispatch thread447// to avoid deadlock.448try {449final AppletPanel p = this;450Runnable r = new Runnable() {451@Override452public void run() {453p.validate();454}455};456AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);457}458catch(InterruptedException ie) {459}460catch(InvocationTargetException ite) {461}462463status = APPLET_INIT;464showAppletStatus("inited");465break;466467case APPLET_START:468{469if (status != APPLET_INIT && status != APPLET_STOP) {470showAppletStatus("notinited");471break;472}473applet.resize(currentAppletSize);474applet.start();475476// Validate and show the applet in event dispatch thread477// to avoid deadlock.478try {479final AppletPanel p = this;480final Applet a = applet;481Runnable r = new Runnable() {482@Override483public void run() {484p.validate();485a.setVisible(true);486487// Fix for BugTraq ID 4041703.488// Set the default focus for an applet.489if (hasInitialFocus()) {490setDefaultFocus();491}492}493};494AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);495}496catch(InterruptedException ie) {497}498catch(InvocationTargetException ite) {499}500501status = APPLET_START;502showAppletStatus("started");503break;504}505506case APPLET_STOP:507if (status != APPLET_START) {508showAppletStatus("notstarted");509break;510}511status = APPLET_STOP;512513// Hide the applet in event dispatch thread514// to avoid deadlock.515try {516final Applet a = applet;517Runnable r = new Runnable() {518@Override519public void run() {520a.setVisible(false);521}522};523AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);524}525catch(InterruptedException ie) {526}527catch(InvocationTargetException ite) {528}529530531// During Applet.stop(), any AccessControlException on an involved Class remains in532// the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is533// reused, the same exception will occur during class loading. Set the AppletClassLoader's534// exceptionStatusSet flag to allow recognition of what had happened535// when reusing AppletClassLoader object.536try {537applet.stop();538} catch (java.security.AccessControlException e) {539setExceptionStatus(e);540// rethrow exception to be handled as it normally would be.541throw e;542}543showAppletStatus("stopped");544break;545546case APPLET_DESTROY:547if (status != APPLET_STOP && status != APPLET_INIT) {548showAppletStatus("notstopped");549break;550}551status = APPLET_DESTROY;552553// During Applet.destroy(), any AccessControlException on an involved Class remains in554// the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is555// reused, the same exception will occur during class loading. Set the AppletClassLoader's556// exceptionStatusSet flag to allow recognition of what had happened557// when reusing AppletClassLoader object.558try {559applet.destroy();560} catch (java.security.AccessControlException e) {561setExceptionStatus(e);562// rethrow exception to be handled as it normally would be.563throw e;564}565showAppletStatus("destroyed");566break;567568case APPLET_DISPOSE:569if (status != APPLET_DESTROY && status != APPLET_LOAD) {570showAppletStatus("notdestroyed");571break;572}573status = APPLET_DISPOSE;574575try {576final Applet a = applet;577Runnable r = new Runnable() {578@Override579public void run() {580remove(a);581}582};583AWTAccessor.getEventQueueAccessor().invokeAndWait(applet, r);584}585catch(InterruptedException ie)586{587}588catch(InvocationTargetException ite)589{590}591applet = null;592showAppletStatus("disposed");593disposed = true;594break;595596case APPLET_QUIT:597return;598}599} catch (Exception e) {600status = APPLET_ERROR;601if (e.getMessage() != null) {602showAppletStatus("exception2", e.getClass().getName(),603e.getMessage());604} else {605showAppletStatus("exception", e.getClass().getName());606}607showAppletException(e);608} catch (ThreadDeath e) {609showAppletStatus("death");610return;611} catch (Error e) {612status = APPLET_ERROR;613if (e.getMessage() != null) {614showAppletStatus("error2", e.getClass().getName(),615e.getMessage());616} else {617showAppletStatus("error", e.getClass().getName());618}619showAppletException(e);620}621clearLoadAbortRequest();622}623}624625/**626* Gets most recent focus owner component associated with the given window.627* It does that without calling Window.getMostRecentFocusOwner since it628* provides its own logic contradicting with setDefautlFocus. Instead, it629* calls KeyboardFocusManager directly.630*/631private Component getMostRecentFocusOwnerForWindow(Window w) {632Method meth = (Method)AccessController.doPrivileged(new PrivilegedAction() {633@Override634public Object run() {635Method meth = null;636try {637meth = KeyboardFocusManager.class.getDeclaredMethod(638"getMostRecentFocusOwner",639new Class[]{Window.class});640meth.setAccessible(true);641} catch (Exception e) {642// Must never happen643e.printStackTrace();644}645return meth;646}647});648if (meth != null) {649// Meth refers static method650try {651return (Component)meth.invoke(null, new Object[] {w});652} catch (Exception e) {653// Must never happen654e.printStackTrace();655}656}657// Will get here if exception was thrown or meth is null658return w.getMostRecentFocusOwner();659}660661/*662* Fix for BugTraq ID 4041703.663* Set the focus to a reasonable default for an Applet.664*/665private void setDefaultFocus() {666Component toFocus = null;667Container parent = getParent();668669if(parent != null) {670if (parent instanceof Window) {671toFocus = getMostRecentFocusOwnerForWindow((Window)parent);672if (toFocus == parent || toFocus == null) {673toFocus = parent.getFocusTraversalPolicy().674getInitialComponent((Window)parent);675}676} else if (parent.isFocusCycleRoot()) {677toFocus = parent.getFocusTraversalPolicy().678getDefaultComponent(parent);679}680}681682if (toFocus != null) {683if (parent instanceof EmbeddedFrame) {684((EmbeddedFrame) parent).synthesizeWindowActivation(true);685}686// EmbeddedFrame might have focus before the applet was added.687// Thus after its activation the most recent focus owner will be688// restored. We need the applet's initial focusabled component to689// be focused here.690toFocus.requestFocusInWindow();691}692}693694/**695* Load the applet into memory.696* Runs in a seperate (and interruptible) thread from the rest of the697* applet event processing so that it can be gracefully interrupted from698* things like HotJava.699*/700private void runLoader() {701if (status != APPLET_DISPOSE) {702showAppletStatus("notdisposed");703return;704}705706dispatchAppletEvent(APPLET_LOADING, null);707708// REMIND -- might be cool to visually indicate loading here --709// maybe do animation?710status = APPLET_LOAD;711712// Create a class loader713loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());714715// Load the archives if present.716// REMIND - this probably should be done in a separate thread,717// or at least the additional archives (epll).718719String code = getCode();720721// setup applet AppContext722// this must be called before loadJarFiles723setupAppletAppContext();724725try {726loadJarFiles(loader);727applet = createApplet(loader);728} catch (ClassNotFoundException e) {729status = APPLET_ERROR;730showAppletStatus("notfound", code);731showAppletLog("notfound", code);732showAppletException(e);733return;734} catch (InstantiationException e) {735status = APPLET_ERROR;736showAppletStatus("nocreate", code);737showAppletLog("nocreate", code);738showAppletException(e);739return;740} catch (IllegalAccessException e) {741status = APPLET_ERROR;742showAppletStatus("noconstruct", code);743showAppletLog("noconstruct", code);744showAppletException(e);745// sbb -- I added a return here746return;747} catch (Exception e) {748status = APPLET_ERROR;749showAppletStatus("exception", e.getMessage());750showAppletException(e);751return;752} catch (ThreadDeath e) {753status = APPLET_ERROR;754showAppletStatus("death");755return;756} catch (Error e) {757status = APPLET_ERROR;758showAppletStatus("error", e.getMessage());759showAppletException(e);760return;761} finally {762// notify that loading is no longer going on763dispatchAppletEvent(APPLET_LOADING_COMPLETED, null);764}765766// Fixed #4508194: NullPointerException thrown during767// quick page switch768//769if (applet != null)770{771// Stick it in the frame772applet.setStub(this);773applet.hide();774add("Center", applet);775showAppletStatus("loaded");776validate();777}778}779780protected Applet createApplet(final AppletClassLoader loader) throws ClassNotFoundException,781IllegalAccessException, IOException, InstantiationException, InterruptedException {782final String serName = getSerializedObject();783String code = getCode();784785if (code != null && serName != null) {786System.err.println(amh.getMessage("runloader.err"));787// return null;788throw new InstantiationException("Either \"code\" or \"object\" should be specified, but not both.");789}790if (code == null && serName == null) {791String msg = "nocode";792status = APPLET_ERROR;793showAppletStatus(msg);794showAppletLog(msg);795repaint();796}797if (code != null) {798applet = (Applet)loader.loadCode(code).newInstance();799doInit = true;800} else {801// serName is not null;802try (InputStream is = AccessController.doPrivileged(803(PrivilegedAction<InputStream>)() -> loader.getResourceAsStream(serName));804ObjectInputStream ois = new AppletObjectInputStream(is, loader)) {805806applet = (Applet) ois.readObject();807doInit = false; // skip over the first init808}809}810811// Determine the JDK level that the applet targets.812// This is critical for enabling certain backward813// compatibility switch if an applet is a JDK 1.1814// applet. [stanley.ho]815findAppletJDKLevel(applet);816817if (Thread.interrupted()) {818try {819status = APPLET_DISPOSE; // APPLET_ERROR?820applet = null;821// REMIND: This may not be exactly the right thing: the822// status is set by the stop button and not necessarily823// here.824showAppletStatus("death");825} finally {826Thread.currentThread().interrupt(); // resignal interrupt827}828return null;829}830return applet;831}832833protected void loadJarFiles(AppletClassLoader loader) throws IOException,834InterruptedException {835// Load the archives if present.836// REMIND - this probably should be done in a separate thread,837// or at least the additional archives (epll).838String jarFiles = getJarFiles();839840if (jarFiles != null) {841StringTokenizer st = new StringTokenizer(jarFiles, ",", false);842while(st.hasMoreTokens()) {843String tok = st.nextToken().trim();844try {845loader.addJar(tok);846} catch (IllegalArgumentException e) {847// bad archive name848continue;849}850}851}852}853854/**855* Request that the loading of the applet be stopped.856*/857protected synchronized void stopLoading() {858// REMIND: fill in the body859if (loaderThread != null) {860//System.out.println("Interrupting applet loader thread: " + loaderThread);861loaderThread.interrupt();862} else {863setLoadAbortRequest();864}865}866867868protected synchronized boolean okToLoad() {869return !loadAbortRequest;870}871872protected synchronized void clearLoadAbortRequest() {873loadAbortRequest = false;874}875876protected synchronized void setLoadAbortRequest() {877loadAbortRequest = true;878}879880881private synchronized void setLoaderThread(Thread loaderThread) {882this.loaderThread = loaderThread;883}884885/**886* Return true when the applet has been started.887*/888@Override889public boolean isActive() {890return status == APPLET_START;891}892893894private EventQueue appEvtQ = null;895/**896* Is called when the applet wants to be resized.897*/898@Override899public void appletResize(int width, int height) {900currentAppletSize.width = width;901currentAppletSize.height = height;902final Dimension currentSize = new Dimension(currentAppletSize.width,903currentAppletSize.height);904905if(loader != null) {906AppContext appCtxt = loader.getAppContext();907if(appCtxt != null)908appEvtQ = (java.awt.EventQueue)appCtxt.get(AppContext.EVENT_QUEUE_KEY);909}910911final AppletPanel ap = this;912if (appEvtQ != null){913appEvtQ.postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),914new Runnable() {915@Override916public void run() {917if (ap != null) {918ap.dispatchAppletEvent(919APPLET_RESIZE,920currentSize);921}922}923}));924}925}926927@Override928public void setBounds(int x, int y, int width, int height) {929super.setBounds(x, y, width, height);930currentAppletSize.width = width;931currentAppletSize.height = height;932}933934public Applet getApplet() {935return applet;936}937938/**939* Status line. Called by the AppletPanel to provide940* feedback on the Applet's state.941*/942protected void showAppletStatus(String status) {943getAppletContext().showStatus(amh.getMessage(status));944}945946protected void showAppletStatus(String status, Object arg) {947getAppletContext().showStatus(amh.getMessage(status, arg));948}949protected void showAppletStatus(String status, Object arg1, Object arg2) {950getAppletContext().showStatus(amh.getMessage(status, arg1, arg2));951}952953/**954* Called by the AppletPanel to print to the log.955*/956protected void showAppletLog(String msg) {957System.out.println(amh.getMessage(msg));958}959960protected void showAppletLog(String msg, Object arg) {961System.out.println(amh.getMessage(msg, arg));962}963964/**965* Called by the AppletPanel to provide966* feedback when an exception has happened.967*/968protected void showAppletException(Throwable t) {969t.printStackTrace();970repaint();971}972973/**974* Get caching key for classloader cache975*/976public String getClassLoaderCacheKey()977{978/**979* Fixed #4501142: Classloader sharing policy doesn't980* take "archive" into account. This will be overridden981* by Java Plug-in. [stanleyh]982*/983return getCodeBase().toString();984}985986/**987* The class loaders988*/989private static HashMap classloaders = new HashMap();990991/**992* Flush a class loader.993*/994public static synchronized void flushClassLoader(String key) {995classloaders.remove(key);996}997998/**999* Flush all class loaders.1000*/1001public static synchronized void flushClassLoaders() {1002classloaders = new HashMap();1003}10041005/**1006* This method actually creates an AppletClassLoader.1007*1008* It can be override by subclasses (such as the Plug-in)1009* to provide different classloaders.1010*/1011protected AppletClassLoader createClassLoader(final URL codebase) {1012return new AppletClassLoader(codebase);1013}10141015/**1016* Get a class loader. Create in a restricted context1017*/1018synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) {1019AppletClassLoader c = (AppletClassLoader)classloaders.get(key);1020if (c == null) {1021AccessControlContext acc =1022getAccessControlContext(codebase);1023c = (AppletClassLoader)1024AccessController.doPrivileged(new PrivilegedAction() {1025@Override1026public Object run() {1027AppletClassLoader ac = createClassLoader(codebase);1028/* Should the creation of the classloader be1029* within the class synchronized block? Since1030* this class is used by the plugin, take care1031* to avoid deadlocks, or specialize1032* AppletPanel within the plugin. It may take1033* an arbitrary amount of time to create a1034* class loader (involving getting Jar files1035* etc.) and may block unrelated applets from1036* finishing createAppletThread (due to the1037* class synchronization). If1038* createAppletThread does not finish quickly,1039* the applet cannot process other messages,1040* particularly messages such as destroy1041* (which timeout when called from the browser).1042*/1043synchronized (getClass()) {1044AppletClassLoader res =1045(AppletClassLoader)classloaders.get(key);1046if (res == null) {1047classloaders.put(key, ac);1048return ac;1049} else {1050return res;1051}1052}1053}1054},acc);1055}1056return c;1057}10581059/**1060* get the context for the AppletClassLoader we are creating.1061* the context is granted permission to create the class loader,1062* connnect to the codebase, and whatever else the policy grants1063* to all codebases.1064*/1065private AccessControlContext getAccessControlContext(final URL codebase) {10661067PermissionCollection perms = (PermissionCollection)1068AccessController.doPrivileged(new PrivilegedAction() {1069@Override1070public Object run() {1071Policy p = java.security.Policy.getPolicy();1072if (p != null) {1073return p.getPermissions(new CodeSource(null,1074(java.security.cert.Certificate[]) null));1075} else {1076return null;1077}1078}1079});10801081if (perms == null)1082perms = new Permissions();10831084//XXX: this is needed to be able to create the classloader itself!10851086perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);10871088Permission p;1089java.net.URLConnection urlConnection = null;1090try {1091urlConnection = codebase.openConnection();1092p = urlConnection.getPermission();1093} catch (java.io.IOException ioe) {1094p = null;1095}10961097if (p != null)1098perms.add(p);10991100if (p instanceof FilePermission) {11011102String path = p.getName();11031104int endIndex = path.lastIndexOf(File.separatorChar);11051106if (endIndex != -1) {1107path = path.substring(0, endIndex+1);11081109if (path.endsWith(File.separator)) {1110path += "-";1111}1112perms.add(new FilePermission(path,1113SecurityConstants.FILE_READ_ACTION));1114}1115} else {1116URL locUrl = codebase;1117if (urlConnection instanceof JarURLConnection) {1118locUrl = ((JarURLConnection)urlConnection).getJarFileURL();1119}1120String host = locUrl.getHost();1121if (host != null && (host.length() > 0))1122perms.add(new SocketPermission(host,1123SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION));1124}11251126ProtectionDomain domain =1127new ProtectionDomain(new CodeSource(codebase,1128(java.security.cert.Certificate[]) null), perms);1129AccessControlContext acc =1130new AccessControlContext(new ProtectionDomain[] { domain });11311132return acc;1133}11341135public Thread getAppletHandlerThread() {1136return handler;1137}11381139public int getAppletWidth() {1140return currentAppletSize.width;1141}11421143public int getAppletHeight() {1144return currentAppletSize.height;1145}11461147public static void changeFrameAppContext(Frame frame, AppContext newAppContext)1148{1149// Fixed #4754451: Applet can have methods running on main1150// thread event queue.1151//1152// The cause of this bug is that the frame of the applet1153// is created in main thread group. Thus, when certain1154// AWT/Swing events are generated, the events will be1155// dispatched through the wrong event dispatch thread.1156//1157// To fix this, we rearrange the AppContext with the frame,1158// so the proper event queue will be looked up.1159//1160// Swing also maintains a Frame list for the AppContext,1161// so we will have to rearrange it as well.11621163// Check if frame's AppContext has already been set properly1164AppContext oldAppContext = SunToolkit.targetToAppContext(frame);11651166if (oldAppContext == newAppContext)1167return;11681169// Synchronization on Window.class is needed for locking the1170// critical section of the window list in AppContext.1171synchronized (Window.class)1172{1173WeakReference weakRef = null;1174// Remove frame from the Window list in wrong AppContext1175{1176// Lookup current frame's AppContext1177Vector<WeakReference<Window>> windowList = (Vector<WeakReference<Window>>)oldAppContext.get(Window.class);1178if (windowList != null) {1179for (WeakReference ref : windowList) {1180if (ref.get() == frame) {1181weakRef = ref;1182break;1183}1184}1185// Remove frame from wrong AppContext1186if (weakRef != null)1187windowList.remove(weakRef);1188}1189}11901191// Put the frame into the applet's AppContext map1192SunToolkit.insertTargetMapping(frame, newAppContext);11931194// Insert frame into the Window list in the applet's AppContext map1195{1196Vector<WeakReference<Window>> windowList = (Vector)newAppContext.get(Window.class);1197if (windowList == null) {1198windowList = new Vector<WeakReference<Window>>();1199newAppContext.put(Window.class, windowList);1200}1201// use the same weakRef here as it is used elsewhere1202windowList.add(weakRef);1203}1204}1205}12061207// Flag to indicate if applet is targeted for JDK 1.1.1208private boolean jdk11Applet = false;12091210// Flag to indicate if applet is targeted for JDK 1.2.1211private boolean jdk12Applet = false;12121213/**1214* Determine JDK level of an applet.1215*/1216private void findAppletJDKLevel(Applet applet)1217{1218// To determine the JDK level of an applet, the1219// most reliable way is to check the major version1220// of the applet class file.12211222// synchronized on applet class object, so calling from1223// different instances of the same applet will be1224// serialized.1225Class appletClass = applet.getClass();12261227synchronized(appletClass) {1228// Determine if the JDK level of an applet has been1229// checked before.1230Boolean jdk11Target = (Boolean) loader.isJDK11Target(appletClass);1231Boolean jdk12Target = (Boolean) loader.isJDK12Target(appletClass);12321233// if applet JDK level has been checked before, retrieve1234// value and return.1235if (jdk11Target != null || jdk12Target != null) {1236jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue();1237jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue();1238return;1239}12401241String name = appletClass.getName();12421243// first convert any '.' to '/'1244name = name.replace('.', '/');12451246// append .class1247final String resourceName = name + ".class";12481249byte[] classHeader = new byte[8];12501251try (InputStream is = AccessController.doPrivileged(1252(PrivilegedAction<InputStream>) () -> loader.getResourceAsStream(resourceName))) {12531254// Read the first 8 bytes of the class file1255int byteRead = is.read(classHeader, 0, 8);12561257// return if the header is not read in entirely1258// for some reasons.1259if (byteRead != 8)1260return;1261}1262catch (IOException e) {1263return;1264}12651266// Check major version in class file header1267int major_version = readShort(classHeader, 6);12681269// Major version in class file is as follows:1270// 45 - JDK 1.11271// 46 - JDK 1.21272// 47 - JDK 1.31273// 48 - JDK 1.41274// 49 - JDK 1.51275if (major_version < 46)1276jdk11Applet = true;1277else if (major_version == 46)1278jdk12Applet = true;12791280// Store applet JDK level in AppContext for later lookup,1281// e.g. page switch.1282loader.setJDK11Target(appletClass, jdk11Applet);1283loader.setJDK12Target(appletClass, jdk12Applet);1284}1285}12861287/**1288* Return true if applet is targeted to JDK 1.1.1289*/1290protected boolean isJDK11Applet() {1291return jdk11Applet;1292}12931294/**1295* Return true if applet is targeted to JDK1.2.1296*/1297protected boolean isJDK12Applet() {1298return jdk12Applet;1299}13001301/**1302* Read short from byte array.1303*/1304private int readShort(byte[] b, int off) {1305int hi = readByte(b[off]);1306int lo = readByte(b[off + 1]);1307return (hi << 8) | lo;1308}13091310private int readByte(byte b) {1311return ((int)b) & 0xFF;1312}131313141315private static AppletMessageHandler amh = new AppletMessageHandler("appletpanel");1316}131713181319