History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/applet/AppletPanel.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/applet/AppletPanel.java+1318−0
@@ -0,0 +1,1318 @@
1+/*
2+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.applet;
27+
28+import java.applet.*;
29+import java.awt.*;
30+import java.awt.event.*;
31+import java.awt.image.ColorModel;
32+import java.awt.image.MemoryImageSource;
33+import java.io.*;
34+import java.lang.ref.WeakReference;
35+import java.lang.reflect.InvocationTargetException;
36+import java.lang.reflect.Method;
37+import java.net.InetAddress;
38+import java.net.JarURLConnection;
39+import java.net.MalformedURLException;
40+import java.net.SocketPermission;
41+import java.net.URL;
42+import java.net.UnknownHostException;
43+import java.security.*;
44+import java.util.*;
45+import java.util.Collections;
46+import java.util.Locale;
47+import java.util.WeakHashMap;
48+import sun.awt.AppContext;
49+import sun.awt.EmbeddedFrame;
50+import sun.awt.SunToolkit;
51+import sun.misc.MessageUtils;
52+import sun.misc.PerformanceLogger;
53+import sun.misc.Queue;
54+import sun.security.util.SecurityConstants;
55+
56+/**
57+ * Applet panel class. The panel manages and manipulates the
58+ * applet as it is being loaded. It forks a separate thread in a new
59+ * thread group to call the applet's init(), start(), stop(), and
60+ * destroy() methods.
61+ *
62+ * @author Arthur van Hoff
63+ */
64+public
65+abstract class AppletPanel extends Panel implements AppletStub, Runnable {
66+
67+ /**
68+ * The applet (if loaded).
69+ */
70+ Applet applet;
71+
72+ /**
73+ * Applet will allow initialization. Should be
74+ * set to false if loading a serialized applet
75+ * that was pickled in the init=true state.
76+ */
77+ protected boolean doInit = true;
78+
79+
80+ /**
81+ * The classloader for the applet.
82+ */
83+ protected AppletClassLoader loader;
84+
85+ /* applet event ids */
86+ public final static int APPLET_DISPOSE = 0;
87+ public final static int APPLET_LOAD = 1;
88+ public final static int APPLET_INIT = 2;
89+ public final static int APPLET_START = 3;
90+ public final static int APPLET_STOP = 4;
91+ public final static int APPLET_DESTROY = 5;
92+ public final static int APPLET_QUIT = 6;
93+ public final static int APPLET_ERROR = 7;
94+
95+ /* send to the parent to force relayout */
96+ public final static int APPLET_RESIZE = 51234;
97+
98+ /* sent to a (distant) parent to indicate that the applet is being
99+ * loaded or as completed loading
100+ */
101+ public final static int APPLET_LOADING = 51235;
102+ public final static int APPLET_LOADING_COMPLETED = 51236;
103+
104+ /**
105+ * The current status. One of:
106+ * APPLET_DISPOSE,
107+ * APPLET_LOAD,
108+ * APPLET_INIT,
109+ * APPLET_START,
110+ * APPLET_STOP,
111+ * APPLET_DESTROY,
112+ * APPLET_ERROR.
113+ */
114+ protected int status;
115+
116+ /**
117+ * The thread for the applet.
118+ */
119+ protected Thread handler;
120+
121+
122+ /**
123+ * The initial applet size.
124+ */
125+ Dimension defaultAppletSize = new Dimension(10, 10);
126+
127+ /**
128+ * The current applet size.
129+ */
130+ Dimension currentAppletSize = new Dimension(10, 10);
131+
132+ MessageUtils mu = new MessageUtils();
133+
134+ /**
135+ * The thread to use during applet loading
136+ */
137+
138+ Thread loaderThread = null;
139+
140+ /**
141+ * Flag to indicate that a loading has been cancelled
142+ */
143+ boolean loadAbortRequest = false;
144+
145+ /* abstract classes */
146+ abstract protected String getCode();
147+ abstract protected String getJarFiles();
148+ abstract protected String getSerializedObject();
149+
150+ abstract public int getWidth();
151+ abstract public int getHeight();
152+ abstract public boolean hasInitialFocus();
153+
154+ private static int threadGroupNumber = 0;
155+
156+ protected void setupAppletAppContext() {
157+ // do nothing
158+ }
159+
160+ /*
161+ * Creates a thread to run the applet. This method is called
162+ * each time an applet is loaded and reloaded.
163+ */
164+ synchronized void createAppletThread() {
165+ // Create a thread group for the applet, and start a new
166+ // thread to load the applet.
167+ String nm = "applet-" + getCode();
168+ loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
169+ loader.grab(); // Keep this puppy around!
170+
171+ // 4668479: Option to turn off codebase lookup in AppletClassLoader
172+ // during resource requests. [stanley.ho]
173+ String param = getParameter("codebase_lookup");
174+
175+ if (param != null && param.equals("false"))
176+ loader.setCodebaseLookup(false);
177+ else
178+ loader.setCodebaseLookup(true);
179+
180+
181+ ThreadGroup appletGroup = loader.getThreadGroup();
182+
183+ handler = new Thread(appletGroup, this, "thread " + nm);
184+ // set the context class loader for this thread
185+ AccessController.doPrivileged(new PrivilegedAction() {
186+ public Object run() {
187+ handler.setContextClassLoader(loader);
188+ return null;
189+ }
190+ });
191+ handler.start();
192+ }
193+
194+ void joinAppletThread() throws InterruptedException {
195+ if (handler != null) {
196+ handler.join();
197+ handler = null;
198+ }
199+ }
200+
201+ void release() {
202+ if (loader != null) {
203+ loader.release();
204+ loader = null;
205+ }
206+ }
207+
208+ /**
209+ * Construct an applet viewer and start the applet.
210+ */
211+ public void init() {
212+ try {
213+ // Get the width (if any)
214+ defaultAppletSize.width = getWidth();
215+ currentAppletSize.width = defaultAppletSize.width;
216+
217+ // Get the height (if any)
218+ defaultAppletSize.height = getHeight();
219+ currentAppletSize.height = defaultAppletSize.height;
220+
221+ } catch (NumberFormatException e) {
222+ // Turn on the error flag and let TagAppletPanel
223+ // do the right thing.
224+ status = APPLET_ERROR;
225+ showAppletStatus("badattribute.exception");
226+ showAppletLog("badattribute.exception");
227+ showAppletException(e);
228+ }
229+
230+ setLayout(new BorderLayout());
231+
232+ createAppletThread();
233+ }
234+
235+ /**
236+ * Minimum size
237+ */
238+ public Dimension minimumSize() {
239+ return new Dimension(defaultAppletSize.width,
240+ defaultAppletSize.height);
241+ }
242+
243+ /**
244+ * Preferred size
245+ */
246+ public Dimension preferredSize() {
247+ return new Dimension(currentAppletSize.width,
248+ currentAppletSize.height);
249+ }
250+
251+ private AppletListener listeners;
252+
253+ /**
254+ * AppletEvent Queue
255+ */
256+ private Queue queue = null;
257+
258+
259+ synchronized public void addAppletListener(AppletListener l) {
260+ listeners = AppletEventMulticaster.add(listeners, l);
261+ }
262+
263+ synchronized public void removeAppletListener(AppletListener l) {
264+ listeners = AppletEventMulticaster.remove(listeners, l);
265+ }
266+
267+ /**
268+ * Dispatch event to the listeners..
269+ */
270+ public void dispatchAppletEvent(int id, Object argument) {
271+ //System.out.println("SEND= " + id);
272+ if (listeners != null) {
273+ AppletEvent evt = new AppletEvent(this, id, argument);
274+ listeners.appletStateChanged(evt);
275+ }
276+ }
277+
278+ /**
279+ * Send an event. Queue it for execution by the handler thread.
280+ */
281+ public void sendEvent(int id) {
282+ synchronized(this) {
283+ if (queue == null) {
284+ //System.out.println("SEND0= " + id);
285+ queue = new Queue();
286+ }
287+ Integer eventId = Integer.valueOf(id);
288+ queue.enqueue(eventId);
289+ notifyAll();
290+ }
291+ if (id == APPLET_QUIT) {
292+ try {
293+ joinAppletThread(); // Let the applet event handler exit
294+ } catch (InterruptedException e) {
295+ }
296+
297+ // AppletClassLoader.release() must be called by a Thread
298+ // not within the applet's ThreadGroup
299+ if (loader == null)
300+ loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
301+ release();
302+ }
303+ }
304+
305+ /**
306+ * Get an event from the queue.
307+ */
308+ synchronized AppletEvent getNextEvent() throws InterruptedException {
309+ while (queue == null || queue.isEmpty()) {
310+ wait();
311+ }
312+ Integer eventId = (Integer)queue.dequeue();
313+ return new AppletEvent(this, eventId.intValue(), null);
314+ }
315+
316+ boolean emptyEventQueue() {
317+ if ((queue == null) || (queue.isEmpty()))
318+ return true;
319+ else
320+ return false;
321+ }
322+
323+ /**
324+ * This kludge is specific to get over AccessControlException thrown during
325+ * Applet.stop() or destroy() when static thread is suspended. Set a flag
326+ * in AppletClassLoader to indicate that an
327+ * AccessControlException for RuntimePermission "modifyThread" or
328+ * "modifyThreadGroup" had occurred.
329+ */
330+ private void setExceptionStatus(AccessControlException e) {
331+ Permission p = e.getPermission();
332+ if (p instanceof RuntimePermission) {
333+ if (p.getName().startsWith("modifyThread")) {
334+ if (loader == null)
335+ loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
336+ loader.setExceptionStatus();
337+ }
338+ }
339+ }
340+
341+ /**
342+ * Execute applet events.
343+ * Here is the state transition diagram
344+ *
345+ * Note: (XXX) is the action
346+ * APPLET_XXX is the state
347+ * (applet code loaded) --> APPLET_LOAD -- (applet init called)--> APPLET_INIT -- (
348+ * applet start called) --> APPLET_START -- (applet stop called) -->APPLET_STOP --(applet
349+ * destroyed called) --> APPLET_DESTROY -->(applet gets disposed) -->
350+ * APPLET_DISPOSE -->....
351+ *
352+ * In the legacy lifecycle model. The applet gets loaded, inited and started. So it stays
353+ * in the APPLET_START state unless the applet goes away(refresh page or leave the page).
354+ * So the applet stop method called and the applet enters APPLET_STOP state. Then if the applet
355+ * is revisited, it will call applet start method and enter the APPLET_START state and stay there.
356+ *
357+ * In the modern lifecycle model. When the applet first time visited, it is same as legacy lifecycle
358+ * model. However, when the applet page goes away. It calls applet stop method and enters APPLET_STOP
359+ * state and then applet destroyed method gets called and enters APPLET_DESTROY state.
360+ *
361+ * This code is also called by AppletViewer. In AppletViewer "Restart" menu, the applet is jump from
362+ * APPLET_STOP to APPLET_DESTROY and to APPLET_INIT .
363+ *
364+ * Also, the applet can jump from APPLET_INIT state to APPLET_DESTROY (in Netscape/Mozilla case).
365+ * Same as APPLET_LOAD to
366+ * APPLET_DISPOSE since all of this are triggered by browser.
367+ *
368+ *
369+ */
370+ public void run() {
371+
372+ Thread curThread = Thread.currentThread();
373+ if (curThread == loaderThread) {
374+ // if we are in the loader thread, cause
375+ // loading to occur. We may exit this with
376+ // status being APPLET_DISPOSE, APPLET_ERROR,
377+ // or APPLET_LOAD
378+ runLoader();
379+ return;
380+ }
381+
382+ boolean disposed = false;
383+ while (!disposed && !curThread.isInterrupted()) {
384+ AppletEvent evt;
385+ try {
386+ evt = getNextEvent();
387+ } catch (InterruptedException e) {
388+ showAppletStatus("bail");
389+ return;
390+ }
391+
392+ //showAppletStatus("EVENT = " + evt.getID());
393+ try {
394+ switch (evt.getID()) {
395+ case APPLET_LOAD:
396+ if (!okToLoad()) {
397+ break;
398+ }
399+ // This complexity allows loading of applets to be
400+ // interruptable. The actual thread loading runs
401+ // in a separate thread, so it can be interrupted
402+ // without harming the applet thread.
403+ // So that we don't have to worry about
404+ // concurrency issues, the main applet thread waits
405+ // until the loader thread terminates.
406+ // (one way or another).
407+ if (loaderThread == null) {
408+ // REMIND: do we want a name?
409+ //System.out.println("------------------- loading applet");
410+ setLoaderThread(new Thread(this));
411+ loaderThread.start();
412+ // we get to go to sleep while this runs
413+ loaderThread.join();
414+ setLoaderThread(null);
415+ } else {
416+ // REMIND: issue an error -- this case should never
417+ // occur.
418+ }
419+ break;
420+
421+ case APPLET_INIT:
422+ // AppletViewer "Restart" will jump from destroy method to
423+ // init, that is why we need to check status w/ APPLET_DESTROY
424+ if (status != APPLET_LOAD && status != APPLET_DESTROY) {
425+ showAppletStatus("notloaded");
426+ break;
427+ }
428+ applet.resize(defaultAppletSize);
429+ if (doInit) {
430+ if (PerformanceLogger.loggingEnabled()) {
431+ PerformanceLogger.setTime("Applet Init");
432+ PerformanceLogger.outputLog();
433+ }
434+ applet.init();
435+ }
436+
437+ //Need the default(fallback) font to be created in this AppContext
438+ Font f = getFont();
439+ if (f == null ||
440+ "dialog".equals(f.getFamily().toLowerCase(Locale.ENGLISH)) &&
441+ f.getSize() == 12 && f.getStyle() == Font.PLAIN) {
442+ setFont(new Font(Font.DIALOG, Font.PLAIN, 12));
443+ }
444+
445+ doInit = true; // allow restarts
446+
447+ // Validate the applet in event dispatch thread
448+ // to avoid deadlock.
449+ try {
450+ final AppletPanel p = this;
451+
452+ EventQueue.invokeAndWait(new Runnable() {
453+ public void run() {
454+ p.validate();
455+ }
456+ });
457+ }
458+ catch(InterruptedException ie) {
459+ }
460+ catch(InvocationTargetException ite) {
461+ }
462+
463+ status = APPLET_INIT;
464+ showAppletStatus("inited");
465+ break;
466+
467+ case APPLET_START:
468+ {
469+ if (status != APPLET_INIT && status != APPLET_STOP) {
470+ showAppletStatus("notinited");
471+ break;
472+ }
473+ applet.resize(currentAppletSize);
474+ applet.start();
475+
476+ // Validate and show the applet in event dispatch thread
477+ // to avoid deadlock.
478+ try {
479+ final AppletPanel p = this;
480+ final Applet a = applet;
481+
482+ EventQueue.invokeAndWait(new Runnable() {
483+ public void run() {
484+ p.validate();
485+ a.setVisible(true);
486+
487+ // Fix for BugTraq ID 4041703.
488+ // Set the default focus for an applet.
489+ if (hasInitialFocus())
490+ setDefaultFocus();
491+ }
492+ });
493+ }
494+ catch(InterruptedException ie) {
495+ }
496+ catch(InvocationTargetException ite) {
497+ }
498+
499+ status = APPLET_START;
500+ showAppletStatus("started");
501+ break;
502+ }
503+
504+ case APPLET_STOP:
505+ if (status != APPLET_START) {
506+ showAppletStatus("notstarted");
507+ break;
508+ }
509+ status = APPLET_STOP;
510+
511+ // Hide the applet in event dispatch thread
512+ // to avoid deadlock.
513+ try {
514+ final Applet a = applet;
515+
516+ EventQueue.invokeAndWait(new Runnable() {
517+ public void run()
518+ {
519+ a.setVisible(false);
520+ }
521+ });
522+ }
523+ catch(InterruptedException ie) {
524+ }
525+ catch(InvocationTargetException ite) {
526+ }
527+
528+
529+ // During Applet.stop(), any AccessControlException on an involved Class remains in
530+ // the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is
531+ // reused, the same exception will occur during class loading. Set the AppletClassLoader's
532+ // exceptionStatusSet flag to allow recognition of what had happened
533+ // when reusing AppletClassLoader object.
534+ try {
535+ applet.stop();
536+ } catch (java.security.AccessControlException e) {
537+ setExceptionStatus(e);
538+ // rethrow exception to be handled as it normally would be.
539+ throw e;
540+ }
541+ showAppletStatus("stopped");
542+ break;
543+
544+ case APPLET_DESTROY:
545+ if (status != APPLET_STOP && status != APPLET_INIT) {
546+ showAppletStatus("notstopped");
547+ break;
548+ }
549+ status = APPLET_DESTROY;
550+
551+ // During Applet.destroy(), any AccessControlException on an involved Class remains in
552+ // the "memory" of the AppletClassLoader. If the same instance of the ClassLoader is
553+ // reused, the same exception will occur during class loading. Set the AppletClassLoader's
554+ // exceptionStatusSet flag to allow recognition of what had happened
555+ // when reusing AppletClassLoader object.
556+ try {
557+ applet.destroy();
558+ } catch (java.security.AccessControlException e) {
559+ setExceptionStatus(e);
560+ // rethrow exception to be handled as it normally would be.
561+ throw e;
562+ }
563+ showAppletStatus("destroyed");
564+ break;
565+
566+ case APPLET_DISPOSE:
567+ if (status != APPLET_DESTROY && status != APPLET_LOAD) {
568+ showAppletStatus("notdestroyed");
569+ break;
570+ }
571+ status = APPLET_DISPOSE;
572+
573+ try
574+ {
575+ final Applet a = applet;
576+
577+ EventQueue.invokeAndWait(new Runnable()
578+ {
579+ public void run()
580+ {
581+ remove(a);
582+ }
583+ });
584+ }
585+ catch(InterruptedException ie)
586+ {
587+ }
588+ catch(InvocationTargetException ite)
589+ {
590+ }
591+ applet = null;
592+ showAppletStatus("disposed");
593+ disposed = true;
594+ break;
595+
596+ case APPLET_QUIT:
597+ return;
598+ }
599+ } catch (Exception e) {
600+ status = APPLET_ERROR;
601+ if (e.getMessage() != null) {
602+ showAppletStatus("exception2", e.getClass().getName(),
603+ e.getMessage());
604+ } else {
605+ showAppletStatus("exception", e.getClass().getName());
606+ }
607+ showAppletException(e);
608+ } catch (ThreadDeath e) {
609+ showAppletStatus("death");
610+ return;
611+ } catch (Error e) {
612+ status = APPLET_ERROR;
613+ if (e.getMessage() != null) {
614+ showAppletStatus("error2", e.getClass().getName(),
615+ e.getMessage());
616+ } else {
617+ showAppletStatus("error", e.getClass().getName());
618+ }
619+ showAppletException(e);
620+ }
621+ clearLoadAbortRequest();
622+ }
623+ }
624+
625+ /**
626+ * Gets most recent focus owner component associated with the given window.
627+ * It does that without calling Window.getMostRecentFocusOwner since it
628+ * provides its own logic contradicting with setDefautlFocus. Instead, it
629+ * calls KeyboardFocusManager directly.
630+ */
631+ private Component getMostRecentFocusOwnerForWindow(Window w) {
632+ Method meth = (Method)AccessController.doPrivileged(new PrivilegedAction() {
633+ public Object run() {
634+ Method meth = null;
635+ try {
636+ meth = KeyboardFocusManager.class.getDeclaredMethod("getMostRecentFocusOwner", new Class[] {Window.class});
637+ meth.setAccessible(true);
638+ } catch (Exception e) {
639+ // Must never happen
640+ e.printStackTrace();
641+ }
642+ return meth;
643+ }
644+ });
645+ if (meth != null) {
646+ // Meth refers static method
647+ try {
648+ return (Component)meth.invoke(null, new Object[] {w});
649+ } catch (Exception e) {
650+ // Must never happen
651+ e.printStackTrace();
652+ }
653+ }
654+ // Will get here if exception was thrown or meth is null
655+ return w.getMostRecentFocusOwner();
656+ }
657+
658+ /*
659+ * Fix for BugTraq ID 4041703.
660+ * Set the focus to a reasonable default for an Applet.
661+ */
662+ private void setDefaultFocus() {
663+ Component toFocus = null;
664+ Container parent = getParent();
665+
666+ if(parent != null) {
667+ if (parent instanceof Window) {
668+ toFocus = getMostRecentFocusOwnerForWindow((Window)parent);
669+ if (toFocus == parent || toFocus == null) {
670+ toFocus = parent.getFocusTraversalPolicy().
671+ getInitialComponent((Window)parent);
672+ }
673+ } else if (parent.isFocusCycleRoot()) {
674+ toFocus = parent.getFocusTraversalPolicy().
675+ getDefaultComponent(parent);
676+ }
677+ }
678+
679+ if (toFocus != null) {
680+ if (parent instanceof EmbeddedFrame) {
681+ ((EmbeddedFrame)parent).synthesizeWindowActivation(true);
682+ }
683+ // EmbeddedFrame might have focus before the applet was added.
684+ // Thus after its activation the most recent focus owner will be
685+ // restored. We need the applet's initial focusabled component to
686+ // be focused here.
687+ toFocus.requestFocusInWindow();
688+ }
689+ }
690+
691+ /**
692+ * Load the applet into memory.
693+ * Runs in a seperate (and interruptible) thread from the rest of the
694+ * applet event processing so that it can be gracefully interrupted from
695+ * things like HotJava.
696+ */
697+ private void runLoader() {
698+ if (status != APPLET_DISPOSE) {
699+ showAppletStatus("notdisposed");
700+ return;
701+ }
702+
703+ dispatchAppletEvent(APPLET_LOADING, null);
704+
705+ // REMIND -- might be cool to visually indicate loading here --
706+ // maybe do animation?
707+ status = APPLET_LOAD;
708+
709+ // Create a class loader
710+ loader = getClassLoader(getCodeBase(), getClassLoaderCacheKey());
711+
712+ // Load the archives if present.
713+ // REMIND - this probably should be done in a separate thread,
714+ // or at least the additional archives (epll).
715+
716+ String code = getCode();
717+
718+ // setup applet AppContext
719+ // this must be called before loadJarFiles
720+ setupAppletAppContext();
721+
722+ try {
723+ loadJarFiles(loader);
724+ applet = createApplet(loader);
725+ } catch (ClassNotFoundException e) {
726+ status = APPLET_ERROR;
727+ showAppletStatus("notfound", code);
728+ showAppletLog("notfound", code);
729+ showAppletException(e);
730+ return;
731+ } catch (InstantiationException e) {
732+ status = APPLET_ERROR;
733+ showAppletStatus("nocreate", code);
734+ showAppletLog("nocreate", code);
735+ showAppletException(e);
736+ return;
737+ } catch (IllegalAccessException e) {
738+ status = APPLET_ERROR;
739+ showAppletStatus("noconstruct", code);
740+ showAppletLog("noconstruct", code);
741+ showAppletException(e);
742+ // sbb -- I added a return here
743+ return;
744+ } catch (Exception e) {
745+ status = APPLET_ERROR;
746+ showAppletStatus("exception", e.getMessage());
747+ showAppletException(e);
748+ return;
749+ } catch (ThreadDeath e) {
750+ status = APPLET_ERROR;
751+ showAppletStatus("death");
752+ return;
753+ } catch (Error e) {
754+ status = APPLET_ERROR;
755+ showAppletStatus("error", e.getMessage());
756+ showAppletException(e);
757+ return;
758+ } finally {
759+ // notify that loading is no longer going on
760+ dispatchAppletEvent(APPLET_LOADING_COMPLETED, null);
761+ }
762+
763+ // Fixed #4508194: NullPointerException thrown during
764+ // quick page switch
765+ //
766+ if (applet != null)
767+ {
768+ // Stick it in the frame
769+ applet.setStub(this);
770+ applet.hide();
771+ add("Center", applet);
772+ showAppletStatus("loaded");
773+ validate();
774+ }
775+ }
776+
777+ protected Applet createApplet(final AppletClassLoader loader) throws ClassNotFoundException,
778+ IllegalAccessException, IOException, InstantiationException, InterruptedException {
779+ final String serName = getSerializedObject();
780+ String code = getCode();
781+
782+ if (code != null && serName != null) {
783+ System.err.println(amh.getMessage("runloader.err"));
784+// return null;
785+ throw new InstantiationException("Either \"code\" or \"object\" should be specified, but not both.");
786+ }
787+ if (code == null && serName == null) {
788+ String msg = "nocode";
789+ status = APPLET_ERROR;
790+ showAppletStatus(msg);
791+ showAppletLog(msg);
792+ repaint();
793+ }
794+ if (code != null) {
795+ applet = (Applet)loader.loadCode(code).newInstance();
796+ doInit = true;
797+ } else {
798+ // serName is not null;
799+ InputStream is = (InputStream)
800+ java.security.AccessController.doPrivileged(
801+ new java.security.PrivilegedAction() {
802+ public Object run() {
803+ return loader.getResourceAsStream(serName);
804+ }
805+ });
806+ ObjectInputStream ois =
807+ new AppletObjectInputStream(is, loader);
808+ Object serObject = ois.readObject();
809+ applet = (Applet) serObject;
810+ doInit = false; // skip over the first init
811+ }
812+
813+ // Determine the JDK level that the applet targets.
814+ // This is critical for enabling certain backward
815+ // compatibility switch if an applet is a JDK 1.1
816+ // applet. [stanley.ho]
817+ findAppletJDKLevel(applet);
818+
819+ if (Thread.interrupted()) {
820+ try {
821+ status = APPLET_DISPOSE; // APPLET_ERROR?
822+ applet = null;
823+ // REMIND: This may not be exactly the right thing: the
824+ // status is set by the stop button and not necessarily
825+ // here.
826+ showAppletStatus("death");
827+ } finally {
828+ Thread.currentThread().interrupt(); // resignal interrupt
829+ }
830+ return null;
831+ }
832+ return applet;
833+ }
834+
835+ protected void loadJarFiles(AppletClassLoader loader) throws IOException,
836+ InterruptedException {
837+ // Load the archives if present.
838+ // REMIND - this probably should be done in a separate thread,
839+ // or at least the additional archives (epll).
840+ String jarFiles = getJarFiles();
841+
842+ if (jarFiles != null) {
843+ StringTokenizer st = new StringTokenizer(jarFiles, ",", false);
844+ while(st.hasMoreTokens()) {
845+ String tok = st.nextToken().trim();
846+ try {
847+ loader.addJar(tok);
848+ } catch (IllegalArgumentException e) {
849+ // bad archive name
850+ continue;
851+ }
852+ }
853+ }
854+ }
855+
856+ /**
857+ * Request that the loading of the applet be stopped.
858+ */
859+ protected synchronized void stopLoading() {
860+ // REMIND: fill in the body
861+ if (loaderThread != null) {
862+ //System.out.println("Interrupting applet loader thread: " + loaderThread);
863+ loaderThread.interrupt();
864+ } else {
865+ setLoadAbortRequest();
866+ }
867+ }
868+
869+
870+ protected synchronized boolean okToLoad() {
871+ return !loadAbortRequest;
872+ }
873+
874+ protected synchronized void clearLoadAbortRequest() {
875+ loadAbortRequest = false;
876+ }
877+
878+ protected synchronized void setLoadAbortRequest() {
879+ loadAbortRequest = true;
880+ }
881+
882+
883+ private synchronized void setLoaderThread(Thread loaderThread) {
884+ this.loaderThread = loaderThread;
885+ }
886+
887+ /**
888+ * Return true when the applet has been started.
889+ */
890+ public boolean isActive() {
891+ return status == APPLET_START;
892+ }
893+
894+
895+ private EventQueue appEvtQ = null;
896+ /**
897+ * Is called when the applet wants to be resized.
898+ */
899+ public void appletResize(int width, int height) {
900+ currentAppletSize.width = width;
901+ currentAppletSize.height = height;
902+ final Dimension currentSize = new Dimension(currentAppletSize.width,
903+ currentAppletSize.height);
904+
905+ if(loader != null) {
906+ AppContext appCtxt = loader.getAppContext();
907+ if(appCtxt != null)
908+ appEvtQ = (java.awt.EventQueue)appCtxt.get(AppContext.EVENT_QUEUE_KEY);
909+ }
910+
911+ final AppletPanel ap = this;
912+ if (appEvtQ != null){
913+ appEvtQ.postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(),
914+ new Runnable(){
915+ public void run(){
916+ if(ap != null)
917+ {
918+ ap.dispatchAppletEvent(APPLET_RESIZE, currentSize);
919+ }
920+ }
921+ }));
922+ }
923+ }
924+
925+ public void setBounds(int x, int y, int width, int height) {
926+ super.setBounds(x, y, width, height);
927+ currentAppletSize.width = width;
928+ currentAppletSize.height = height;
929+ }
930+
931+ public Applet getApplet() {
932+ return applet;
933+ }
934+
935+ /**
936+ * Status line. Called by the AppletPanel to provide
937+ * feedback on the Applet's state.
938+ */
939+ protected void showAppletStatus(String status) {
940+ getAppletContext().showStatus(amh.getMessage(status));
941+ }
942+
943+ protected void showAppletStatus(String status, Object arg) {
944+ getAppletContext().showStatus(amh.getMessage(status, arg));
945+ }
946+ protected void showAppletStatus(String status, Object arg1, Object arg2) {
947+ getAppletContext().showStatus(amh.getMessage(status, arg1, arg2));
948+ }
949+
950+ /**
951+ * Called by the AppletPanel to print to the log.
952+ */
953+ protected void showAppletLog(String msg) {
954+ System.out.println(amh.getMessage(msg));
955+ }
956+
957+ protected void showAppletLog(String msg, Object arg) {
958+ System.out.println(amh.getMessage(msg, arg));
959+ }
960+
961+ /**
962+ * Called by the AppletPanel to provide
963+ * feedback when an exception has happened.
964+ */
965+ protected void showAppletException(Throwable t) {
966+ t.printStackTrace();
967+ repaint();
968+ }
969+
970+ /**
971+ * Get caching key for classloader cache
972+ */
973+ public String getClassLoaderCacheKey()
974+ {
975+ /**
976+ * Fixed #4501142: Classlaoder sharing policy doesn't
977+ * take "archive" into account. This will be overridden
978+ * by Java Plug-in. [stanleyh]
979+ */
980+ return getCodeBase().toString();
981+ }
982+
983+ /**
984+ * The class loaders
985+ */
986+ private static HashMap classloaders = new HashMap();
987+
988+ /**
989+ * Flush a class loader.
990+ */
991+ public static synchronized void flushClassLoader(String key) {
992+ classloaders.remove(key);
993+ }
994+
995+ /**
996+ * Flush all class loaders.
997+ */
998+ public static synchronized void flushClassLoaders() {
999+ classloaders = new HashMap();
1000+ }
1001+
1002+ /**
1003+ * This method actually creates an AppletClassLoader.
1004+ *
1005+ * It can be override by subclasses (such as the Plug-in)
1006+ * to provide different classloaders.
1007+ */
1008+ protected AppletClassLoader createClassLoader(final URL codebase) {
1009+ return new AppletClassLoader(codebase);
1010+ }
1011+
1012+ /**
1013+ * Get a class loader. Create in a restricted context
1014+ */
1015+ synchronized AppletClassLoader getClassLoader(final URL codebase, final String key) {
1016+ AppletClassLoader c = (AppletClassLoader)classloaders.get(key);
1017+ if (c == null) {
1018+ AccessControlContext acc =
1019+ getAccessControlContext(codebase);
1020+ c = (AppletClassLoader)
1021+ AccessController.doPrivileged(new PrivilegedAction() {
1022+ public Object run() {
1023+ AppletClassLoader ac = createClassLoader(codebase);
1024+ /* Should the creation of the classloader be
1025+ * within the class synchronized block? Since
1026+ * this class is used by the plugin, take care
1027+ * to avoid deadlocks, or specialize
1028+ * AppletPanel within the plugin. It may take
1029+ * an arbitrary amount of time to create a
1030+ * class loader (involving getting Jar files
1031+ * etc.) and may block unrelated applets from
1032+ * finishing createAppletThread (due to the
1033+ * class synchronization). If
1034+ * createAppletThread does not finish quickly,
1035+ * the applet cannot process other messages,
1036+ * particularly messages such as destroy
1037+ * (which timeout when called from the browser).
1038+ */
1039+ synchronized (getClass()) {
1040+ AppletClassLoader res =
1041+ (AppletClassLoader)classloaders.get(key);
1042+ if (res == null) {
1043+ classloaders.put(key, ac);
1044+ return ac;
1045+ } else {
1046+ return res;
1047+ }
1048+ }
1049+ }
1050+ },acc);
1051+ }
1052+ return c;
1053+ }
1054+
1055+ /**
1056+ * get the context for the AppletClassLoader we are creating.
1057+ * the context is granted permission to create the class loader,
1058+ * connnect to the codebase, and whatever else the policy grants
1059+ * to all codebases.
1060+ */
1061+ private AccessControlContext getAccessControlContext(final URL codebase) {
1062+
1063+ PermissionCollection perms = (PermissionCollection)
1064+ AccessController.doPrivileged(new PrivilegedAction() {
1065+ public Object run() {
1066+ Policy p = java.security.Policy.getPolicy();
1067+ if (p != null) {
1068+ return p.getPermissions(new CodeSource(null,
1069+ (java.security.cert.Certificate[]) null));
1070+ } else {
1071+ return null;
1072+ }
1073+ }
1074+ });
1075+
1076+ if (perms == null)
1077+ perms = new Permissions();
1078+
1079+ //XXX: this is needed to be able to create the classloader itself!
1080+
1081+ perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION);
1082+
1083+ Permission p;
1084+ java.net.URLConnection urlConnection = null;
1085+ try {
1086+ urlConnection = codebase.openConnection();
1087+ p = urlConnection.getPermission();
1088+ } catch (java.io.IOException ioe) {
1089+ p = null;
1090+ }
1091+
1092+ if (p != null)
1093+ perms.add(p);
1094+
1095+ if (p instanceof FilePermission) {
1096+
1097+ String path = p.getName();
1098+
1099+ int endIndex = path.lastIndexOf(File.separatorChar);
1100+
1101+ if (endIndex != -1) {
1102+ path = path.substring(0, endIndex+1);
1103+
1104+ if (path.endsWith(File.separator)) {
1105+ path += "-";
1106+ }
1107+ perms.add(new FilePermission(path,
1108+ SecurityConstants.FILE_READ_ACTION));
1109+ }
1110+ } else {
1111+ URL locUrl = codebase;
1112+ if (urlConnection instanceof JarURLConnection) {
1113+ locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
1114+ }
1115+ String host = locUrl.getHost();
1116+ if (host != null && (host.length() > 0))
1117+ perms.add(new SocketPermission(host,
1118+ SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION));
1119+ }
1120+
1121+ ProtectionDomain domain =
1122+ new ProtectionDomain(new CodeSource(codebase,
1123+ (java.security.cert.Certificate[]) null), perms);
1124+ AccessControlContext acc =
1125+ new AccessControlContext(new ProtectionDomain[] { domain });
1126+
1127+ return acc;
1128+ }
1129+
1130+ public Thread getAppletHandlerThread() {
1131+ return handler;
1132+ }
1133+
1134+ public int getAppletWidth() {
1135+ return currentAppletSize.width;
1136+ }
1137+
1138+ public int getAppletHeight() {
1139+ return currentAppletSize.height;
1140+ }
1141+
1142+ public static void changeFrameAppContext(Frame frame, AppContext newAppContext)
1143+ {
1144+ // Fixed #4754451: Applet can have methods running on main
1145+ // thread event queue.
1146+ //
1147+ // The cause of this bug is that the frame of the applet
1148+ // is created in main thread group. Thus, when certain
1149+ // AWT/Swing events are generated, the events will be
1150+ // dispatched through the wrong event dispatch thread.
1151+ //
1152+ // To fix this, we rearrange the AppContext with the frame,
1153+ // so the proper event queue will be looked up.
1154+ //
1155+ // Swing also maintains a Frame list for the AppContext,
1156+ // so we will have to rearrange it as well.
1157+
1158+ // Check if frame's AppContext has already been set properly
1159+ AppContext oldAppContext = SunToolkit.targetToAppContext(frame);
1160+
1161+ if (oldAppContext == newAppContext)
1162+ return;
1163+
1164+ // Synchronization on Window.class is needed for locking the
1165+ // critical section of the window list in AppContext.
1166+ synchronized (Window.class)
1167+ {
1168+ WeakReference weakRef = null;
1169+ // Remove frame from the Window list in wrong AppContext
1170+ {
1171+ // Lookup current frame's AppContext
1172+ Vector<WeakReference<Window>> windowList = (Vector<WeakReference<Window>>)oldAppContext.get(Window.class);
1173+ if (windowList != null) {
1174+ for (WeakReference ref : windowList) {
1175+ if (ref.get() == frame) {
1176+ weakRef = ref;
1177+ break;
1178+ }
1179+ }
1180+ // Remove frame from wrong AppContext
1181+ if (weakRef != null)
1182+ windowList.remove(weakRef);
1183+ }
1184+ }
1185+
1186+ // Put the frame into the applet's AppContext map
1187+ SunToolkit.insertTargetMapping(frame, newAppContext);
1188+
1189+ // Insert frame into the Window list in the applet's AppContext map
1190+ {
1191+ Vector<WeakReference<Window>> windowList = (Vector)newAppContext.get(Window.class);
1192+ if (windowList == null) {
1193+ windowList = new Vector<WeakReference<Window>>();
1194+ newAppContext.put(Window.class, windowList);
1195+ }
1196+ // use the same weakRef here as it is used elsewhere
1197+ windowList.add(weakRef);
1198+ }
1199+ }
1200+ }
1201+
1202+ // Flag to indicate if applet is targeted for JDK 1.1.
1203+ private boolean jdk11Applet = false;
1204+
1205+ // Flag to indicate if applet is targeted for JDK 1.2.
1206+ private boolean jdk12Applet = false;
1207+
1208+ /**
1209+ * Determine JDK level of an applet.
1210+ */
1211+ private void findAppletJDKLevel(Applet applet)
1212+ {
1213+ // To determine the JDK level of an applet, the
1214+ // most reliable way is to check the major version
1215+ // of the applet class file.
1216+
1217+ // synchronized on applet class object, so calling from
1218+ // different instances of the same applet will be
1219+ // serialized.
1220+ Class appletClass = applet.getClass();
1221+
1222+ synchronized(appletClass) {
1223+ // Determine if the JDK level of an applet has been
1224+ // checked before.
1225+ Boolean jdk11Target = (Boolean) loader.isJDK11Target(appletClass);
1226+ Boolean jdk12Target = (Boolean) loader.isJDK12Target(appletClass);
1227+
1228+ // if applet JDK level has been checked before, retrieve
1229+ // value and return.
1230+ if (jdk11Target != null || jdk12Target != null) {
1231+ jdk11Applet = (jdk11Target == null) ? false : jdk11Target.booleanValue();
1232+ jdk12Applet = (jdk12Target == null) ? false : jdk12Target.booleanValue();
1233+ return;
1234+ }
1235+
1236+ String name = appletClass.getName();
1237+
1238+ // first convert any '.' to '/'
1239+ name = name.replace('.', '/');
1240+
1241+ // append .class
1242+ final String resourceName = name + ".class";
1243+
1244+ InputStream is = null;
1245+ byte[] classHeader = new byte[8];
1246+
1247+ try {
1248+ is = (InputStream) java.security.AccessController.doPrivileged(
1249+ new java.security.PrivilegedAction() {
1250+ public Object run() {
1251+ return loader.getResourceAsStream(resourceName);
1252+ }
1253+ });
1254+
1255+ // Read the first 8 bytes of the class file
1256+ int byteRead = is.read(classHeader, 0, 8);
1257+ is.close();
1258+
1259+ // return if the header is not read in entirely
1260+ // for some reasons.
1261+ if (byteRead != 8)
1262+ return;
1263+ }
1264+ catch (IOException e) {
1265+ return;
1266+ }
1267+
1268+ // Check major version in class file header
1269+ int major_version = readShort(classHeader, 6);
1270+
1271+ // Major version in class file is as follows:
1272+ // 45 - JDK 1.1
1273+ // 46 - JDK 1.2
1274+ // 47 - JDK 1.3
1275+ // 48 - JDK 1.4
1276+ // 49 - JDK 1.5
1277+ if (major_version < 46)
1278+ jdk11Applet = true;
1279+ else if (major_version == 46)
1280+ jdk12Applet = true;
1281+
1282+ // Store applet JDK level in AppContext for later lookup,
1283+ // e.g. page switch.
1284+ loader.setJDK11Target(appletClass, jdk11Applet);
1285+ loader.setJDK12Target(appletClass, jdk12Applet);
1286+ }
1287+ }
1288+
1289+ /**
1290+ * Return true if applet is targeted to JDK 1.1.
1291+ */
1292+ protected boolean isJDK11Applet() {
1293+ return jdk11Applet;
1294+ }
1295+
1296+ /**
1297+ * Return true if applet is targeted to JDK1.2.
1298+ */
1299+ protected boolean isJDK12Applet() {
1300+ return jdk12Applet;
1301+ }
1302+
1303+ /**
1304+ * Read short from byte array.
1305+ */
1306+ private int readShort(byte[] b, int off) {
1307+ int hi = readByte(b[off]);
1308+ int lo = readByte(b[off + 1]);
1309+ return (hi << 8) | lo;
1310+ }
1311+
1312+ private int readByte(byte b) {
1313+ return ((int)b) & 0xFF;
1314+ }
1315+
1316+
1317+ private static AppletMessageHandler amh = new AppletMessageHandler("appletpanel");
1318+}