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