|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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 sun.awt.AWTAccessor; |
|
import sun.awt.AppContext; |
|
import sun.awt.EmbeddedFrame; |
|
import sun.awt.SunToolkit; |
|
import sun.misc.MessageUtils; |
|
import sun.misc.PerformanceLogger; |
|
import sun.misc.Queue; |
|
import sun.security.util.SecurityConstants; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public |
|
abstract class AppletPanel extends Panel implements AppletStub, Runnable { |
|
|
|
|
|
|
|
*/ |
|
Applet applet; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected boolean doInit = true; |
|
|
|
|
|
|
|
|
|
*/ |
|
protected AppletClassLoader loader; |
|
|
|
|
|
public final static int APPLET_DISPOSE = 0; |
|
public final static int APPLET_LOAD = 1; |
|
public final static int APPLET_INIT = 2; |
|
public final static int APPLET_START = 3; |
|
public final static int APPLET_STOP = 4; |
|
public final static int APPLET_DESTROY = 5; |
|
public final static int APPLET_QUIT = 6; |
|
public final static int APPLET_ERROR = 7; |
|
|
|
|
|
public final static int APPLET_RESIZE = 51234; |
|
|
|
|
|
|
|
*/ |
|
public final static int APPLET_LOADING = 51235; |
|
public final static int APPLET_LOADING_COMPLETED = 51236; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected int status; |
|
|
|
|
|
|
|
*/ |
|
protected Thread handler; |
|
|
|
|
|
|
|
|
|
*/ |
|
Dimension defaultAppletSize = new Dimension(10, 10); |
|
|
|
|
|
|
|
*/ |
|
Dimension currentAppletSize = new Dimension(10, 10); |
|
|
|
MessageUtils mu = new MessageUtils(); |
|
|
|
/** |
|
* The thread to use during applet loading |
|
*/ |
|
|
|
Thread loaderThread = null; |
|
|
|
|
|
|
|
*/ |
|
boolean loadAbortRequest = false; |
|
|
|
|
|
abstract protected String getCode(); |
|
abstract protected String getJarFiles(); |
|
abstract protected String getSerializedObject(); |
|
|
|
@Override |
|
abstract public int getWidth(); |
|
@Override |
|
abstract public int getHeight(); |
|
abstract public boolean hasInitialFocus(); |
|
|
|
private static int threadGroupNumber = 0; |
|
|
|
protected void setupAppletAppContext() { |
|
// do nothing |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized void createAppletThread() { |
|
// Create a thread group for the applet, and start a new |
|
|
|
String nm = "applet-" + getCode(); |
|
loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey()); |
|
loader.grab(); |
|
|
|
// 4668479: Option to turn off codebase lookup in AppletClassLoader |
|
|
|
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); |
|
|
|
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; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void init() { |
|
try { |
|
|
|
defaultAppletSize.width = getWidth(); |
|
currentAppletSize.width = defaultAppletSize.width; |
|
|
|
|
|
defaultAppletSize.height = getHeight(); |
|
currentAppletSize.height = defaultAppletSize.height; |
|
|
|
} catch (NumberFormatException e) { |
|
// Turn on the error flag and let TagAppletPanel |
|
|
|
status = APPLET_ERROR; |
|
showAppletStatus("badattribute.exception"); |
|
showAppletLog("badattribute.exception"); |
|
showAppletException(e); |
|
} |
|
|
|
setLayout(new BorderLayout()); |
|
|
|
createAppletThread(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public Dimension minimumSize() { |
|
return new Dimension(defaultAppletSize.width, |
|
defaultAppletSize.height); |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public Dimension preferredSize() { |
|
return new Dimension(currentAppletSize.width, |
|
currentAppletSize.height); |
|
} |
|
|
|
private AppletListener listeners; |
|
|
|
|
|
|
|
*/ |
|
private Queue queue = null; |
|
|
|
|
|
synchronized public void addAppletListener(AppletListener l) { |
|
listeners = AppletEventMulticaster.add(listeners, l); |
|
} |
|
|
|
synchronized public void removeAppletListener(AppletListener l) { |
|
listeners = AppletEventMulticaster.remove(listeners, l); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void dispatchAppletEvent(int id, Object argument) { |
|
|
|
if (listeners != null) { |
|
AppletEvent evt = new AppletEvent(this, id, argument); |
|
listeners.appletStateChanged(evt); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public void sendEvent(int id) { |
|
synchronized(this) { |
|
if (queue == null) { |
|
|
|
queue = new Queue(); |
|
} |
|
Integer eventId = Integer.valueOf(id); |
|
queue.enqueue(eventId); |
|
notifyAll(); |
|
} |
|
if (id == APPLET_QUIT) { |
|
try { |
|
joinAppletThread(); |
|
} catch (InterruptedException e) { |
|
} |
|
|
|
// AppletClassLoader.release() must be called by a Thread |
|
|
|
if (loader == null) |
|
loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey()); |
|
release(); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
synchronized AppletEvent getNextEvent() throws InterruptedException { |
|
while (queue == null || queue.isEmpty()) { |
|
wait(); |
|
} |
|
Integer eventId = (Integer)queue.dequeue(); |
|
return new AppletEvent(this, eventId.intValue(), null); |
|
} |
|
|
|
boolean emptyEventQueue() { |
|
if ((queue == null) || (queue.isEmpty())) |
|
return true; |
|
else |
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@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, |
|
|
|
runLoader(); |
|
return; |
|
} |
|
|
|
boolean disposed = false; |
|
while (!disposed && !curThread.isInterrupted()) { |
|
AppletEvent evt; |
|
try { |
|
evt = getNextEvent(); |
|
} catch (InterruptedException e) { |
|
showAppletStatus("bail"); |
|
return; |
|
} |
|
|
|
|
|
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. |
|
|
|
if (loaderThread == null) { |
|
// REMIND: do we want a name? |
|
|
|
setLoaderThread(new Thread(this)); |
|
loaderThread.start(); |
|
|
|
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 |
|
|
|
if (status != APPLET_LOAD && status != APPLET_DESTROY) { |
|
showAppletStatus("notloaded"); |
|
break; |
|
} |
|
applet.resize(defaultAppletSize); |
|
if (doInit) { |
|
if (PerformanceLogger.loggingEnabled()) { |
|
PerformanceLogger.setTime("Applet Init"); |
|
PerformanceLogger.outputLog(); |
|
} |
|
applet.init(); |
|
} |
|
|
|
|
|
Font f = getFont(); |
|
if (f == null || |
|
"dialog".equals(f.getFamily().toLowerCase(Locale.ENGLISH)) && |
|
f.getSize() == 12 && f.getStyle() == Font.PLAIN) { |
|
setFont(new Font(Font.DIALOG, Font.PLAIN, 12)); |
|
} |
|
|
|
doInit = true; |
|
|
|
// Validate the applet in event dispatch thread |
|
|
|
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 |
|
|
|
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. |
|
|
|
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 |
|
|
|
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 |
|
|
|
try { |
|
applet.stop(); |
|
} catch (java.security.AccessControlException e) { |
|
setExceptionStatus(e); |
|
|
|
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 |
|
|
|
try { |
|
applet.destroy(); |
|
} catch (java.security.AccessControlException e) { |
|
setExceptionStatus(e); |
|
|
|
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(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private Component getMostRecentFocusOwnerForWindow(Window w) { |
|
Method meth = (Method)AccessController.doPrivileged(new PrivilegedAction() { |
|
@Override |
|
public Object run() { |
|
Method meth = null; |
|
try { |
|
meth = KeyboardFocusManager.class.getDeclaredMethod( |
|
"getMostRecentFocusOwner", |
|
new Class[]{Window.class}); |
|
meth.setAccessible(true); |
|
} catch (Exception e) { |
|
|
|
e.printStackTrace(); |
|
} |
|
return meth; |
|
} |
|
}); |
|
if (meth != null) { |
|
|
|
try { |
|
return (Component)meth.invoke(null, new Object[] {w}); |
|
} catch (Exception e) { |
|
|
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
return w.getMostRecentFocusOwner(); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
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 |
|
|
|
toFocus.requestFocusInWindow(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void runLoader() { |
|
if (status != APPLET_DISPOSE) { |
|
showAppletStatus("notdisposed"); |
|
return; |
|
} |
|
|
|
dispatchAppletEvent(APPLET_LOADING, null); |
|
|
|
// REMIND -- might be cool to visually indicate loading here -- |
|
|
|
status = APPLET_LOAD; |
|
|
|
|
|
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 |
|
|
|
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); |
|
|
|
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 { |
|
|
|
dispatchAppletEvent(APPLET_LOADING_COMPLETED, null); |
|
} |
|
|
|
// Fixed #4508194: NullPointerException thrown during |
|
// quick page switch |
|
|
|
if (applet != null) |
|
{ |
|
|
|
applet.setStub(this); |
|
applet.hide(); |
|
add("Center", applet); |
|
showAppletStatus("loaded"); |
|
validate(); |
|
} |
|
} |
|
|
|
protected Applet createApplet(final AppletClassLoader loader) throws ClassNotFoundException, |
|
IllegalAccessException, IOException, InstantiationException, InterruptedException { |
|
final String serName = getSerializedObject(); |
|
String code = getCode(); |
|
|
|
if (code != null && serName != null) { |
|
System.err.println(amh.getMessage("runloader.err")); |
|
|
|
throw new InstantiationException("Either \"code\" or \"object\" should be specified, but not both."); |
|
} |
|
if (code == null && serName == null) { |
|
String msg = "nocode"; |
|
status = APPLET_ERROR; |
|
showAppletStatus(msg); |
|
showAppletLog(msg); |
|
repaint(); |
|
} |
|
if (code != null) { |
|
applet = (Applet)loader.loadCode(code).newInstance(); |
|
doInit = true; |
|
} else { |
|
|
|
try (InputStream is = AccessController.doPrivileged( |
|
(PrivilegedAction<InputStream>)() -> loader.getResourceAsStream(serName)); |
|
ObjectInputStream ois = new AppletObjectInputStream(is, loader)) { |
|
|
|
applet = (Applet) ois.readObject(); |
|
doInit = false; |
|
} |
|
} |
|
|
|
// 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 |
|
|
|
findAppletJDKLevel(applet); |
|
|
|
if (Thread.interrupted()) { |
|
try { |
|
status = APPLET_DISPOSE; |
|
applet = null; |
|
// REMIND: This may not be exactly the right thing: the |
|
// status is set by the stop button and not necessarily |
|
|
|
showAppletStatus("death"); |
|
} finally { |
|
Thread.currentThread().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, |
|
|
|
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) { |
|
|
|
continue; |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected synchronized void stopLoading() { |
|
|
|
if (loaderThread != null) { |
|
|
|
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; |
|
} |
|
|
|
|
|
|
|
*/ |
|
@Override |
|
public boolean isActive() { |
|
return status == APPLET_START; |
|
} |
|
|
|
|
|
private EventQueue appEvtQ = null; |
|
|
|
|
|
*/ |
|
@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; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
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)); |
|
} |
|
|
|
|
|
|
|
*/ |
|
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)); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected void showAppletException(Throwable t) { |
|
t.printStackTrace(); |
|
repaint(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public String getClassLoaderCacheKey() |
|
{ |
|
|
|
|
|
|
|
|
|
*/ |
|
return getCodeBase().toString(); |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static HashMap classloaders = new HashMap(); |
|
|
|
|
|
|
|
*/ |
|
public static synchronized void flushClassLoader(String key) { |
|
classloaders.remove(key); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static synchronized void flushClassLoaders() { |
|
classloaders = new HashMap(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected AppletClassLoader createClassLoader(final URL codebase) { |
|
return new AppletClassLoader(codebase); |
|
} |
|
|
|
|
|
|
|
*/ |
|
synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) { |
|
AppletClassLoader c = (AppletClassLoader)classloaders.get(key); |
|
if (c == null) { |
|
AccessControlContext acc = |
|
getAccessControlContext(codebase); |
|
c = (AppletClassLoader) |
|
AccessController.doPrivileged(new PrivilegedAction() { |
|
@Override |
|
public Object run() { |
|
AppletClassLoader ac = createClassLoader(codebase); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized (getClass()) { |
|
AppletClassLoader res = |
|
(AppletClassLoader)classloaders.get(key); |
|
if (res == null) { |
|
classloaders.put(key, ac); |
|
return ac; |
|
} else { |
|
return res; |
|
} |
|
} |
|
} |
|
},acc); |
|
} |
|
return c; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private AccessControlContext getAccessControlContext(final URL codebase) { |
|
|
|
PermissionCollection perms = (PermissionCollection) |
|
AccessController.doPrivileged(new PrivilegedAction() { |
|
@Override |
|
public Object 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. |
|
|
|
|
|
AppContext oldAppContext = SunToolkit.targetToAppContext(frame); |
|
|
|
if (oldAppContext == newAppContext) |
|
return; |
|
|
|
// Synchronization on Window.class is needed for locking the |
|
|
|
synchronized (Window.class) |
|
{ |
|
WeakReference weakRef = null; |
|
|
|
{ |
|
|
|
Vector<WeakReference<Window>> windowList = (Vector<WeakReference<Window>>)oldAppContext.get(Window.class); |
|
if (windowList != null) { |
|
for (WeakReference ref : windowList) { |
|
if (ref.get() == frame) { |
|
weakRef = ref; |
|
break; |
|
} |
|
} |
|
|
|
if (weakRef != null) |
|
windowList.remove(weakRef); |
|
} |
|
} |
|
|
|
|
|
SunToolkit.insertTargetMapping(frame, newAppContext); |
|
|
|
|
|
{ |
|
Vector<WeakReference<Window>> windowList = (Vector)newAppContext.get(Window.class); |
|
if (windowList == null) { |
|
windowList = new Vector<WeakReference<Window>>(); |
|
newAppContext.put(Window.class, windowList); |
|
} |
|
|
|
windowList.add(weakRef); |
|
} |
|
} |
|
} |
|
|
|
|
|
private boolean jdk11Applet = false; |
|
|
|
|
|
private boolean jdk12Applet = false; |
|
|
|
|
|
|
|
*/ |
|
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 |
|
|
|
Class appletClass = applet.getClass(); |
|
|
|
synchronized(appletClass) { |
|
// Determine if the JDK level of an applet has been |
|
|
|
Boolean jdk11Target = (Boolean) loader.isJDK11Target(appletClass); |
|
Boolean jdk12Target = (Boolean) loader.isJDK12Target(appletClass); |
|
|
|
// if applet JDK level has been checked before, retrieve |
|
|
|
if (jdk11Target != null || jdk12Target != null) { |
|
jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue(); |
|
jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue(); |
|
return; |
|
} |
|
|
|
String name = appletClass.getName(); |
|
|
|
|
|
name = name.replace('.', '/'); |
|
|
|
|
|
final String resourceName = name + ".class"; |
|
|
|
byte[] classHeader = new byte[8]; |
|
|
|
try (InputStream is = AccessController.doPrivileged( |
|
(PrivilegedAction<InputStream>) () -> loader.getResourceAsStream(resourceName))) { |
|
|
|
|
|
int byteRead = is.read(classHeader, 0, 8); |
|
|
|
// return if the header is not read in entirely |
|
|
|
if (byteRead != 8) |
|
return; |
|
} |
|
catch (IOException e) { |
|
return; |
|
} |
|
|
|
|
|
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 |
|
|
|
if (major_version < 46) |
|
jdk11Applet = true; |
|
else if (major_version == 46) |
|
jdk12Applet = true; |
|
|
|
// Store applet JDK level in AppContext for later lookup, |
|
|
|
loader.setJDK11Target(appletClass, jdk11Applet); |
|
loader.setJDK12Target(appletClass, jdk12Applet); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected boolean isJDK11Applet() { |
|
return jdk11Applet; |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected boolean isJDK12Applet() { |
|
return jdk12Applet; |
|
} |
|
|
|
|
|
|
|
*/ |
|
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"); |
|
} |