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/AppletClassLoader.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/applet/AppletClassLoader.java+873−0
@@ -0,0 +1,873 @@
1/*
2 * Copyright (c) 1995, 2011, 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
26package sun.applet;
27
28import java.lang.NullPointerException;
29import java.net.URL;
30import java.net.URLClassLoader;
31import java.net.SocketPermission;
32import java.net.URLConnection;
33import java.net.MalformedURLException;
34import java.net.InetAddress;
35import java.net.UnknownHostException;
36import java.io.File;
37import java.io.FilePermission;
38import java.io.IOException;
39import java.io.BufferedInputStream;
40import java.io.InputStream;
41import java.util.Enumeration;
42import java.util.HashMap;
43import java.util.NoSuchElementException;
44import java.security.AccessController;
45import java.security.AccessControlContext;
46import java.security.PrivilegedAction;
47import java.security.PrivilegedExceptionAction;
48import java.security.PrivilegedActionException;
49import java.security.CodeSource;
50import java.security.Permission;
51import java.security.PermissionCollection;
52import sun.awt.AppContext;
53import sun.awt.SunToolkit;
54import sun.misc.IOUtils;
55import sun.net.www.ParseUtil;
56import sun.security.util.SecurityConstants;
57
58/**
59 * This class defines the class loader for loading applet classes and
60 * resources. It extends URLClassLoader to search the applet code base
61 * for the class or resource after checking any loaded JAR files.
62 */
63public class AppletClassLoader extends URLClassLoader {
64 private URL base; /* applet code base URL */
65 private CodeSource codesource; /* codesource for the base URL */
66 private AccessControlContext acc;
67 private boolean exceptionStatus = false;
68
69 private final Object threadGroupSynchronizer = new Object();
70 private final Object grabReleaseSynchronizer = new Object();
71
72 private boolean codebaseLookup = true;
73 private volatile boolean allowRecursiveDirectoryRead = true;
74
75 /*
76 * Creates a new AppletClassLoader for the specified base URL.
77 */
78 protected AppletClassLoader(URL base) {
79 super(new URL[0]);
80 this.base = base;
81 this.codesource =
82 new CodeSource(base, (java.security.cert.Certificate[]) null);
83 acc = AccessController.getContext();
84 }
85
86 public void disableRecursiveDirectoryRead() {
87 allowRecursiveDirectoryRead = false;
88 }
89
90
91 /**
92 * Set the codebase lookup flag.
93 */
94 void setCodebaseLookup(boolean codebaseLookup) {
95 this.codebaseLookup = codebaseLookup;
96 }
97
98 /*
99 * Returns the applet code base URL.
100 */
101 URL getBaseURL() {
102 return base;
103 }
104
105 /*
106 * Returns the URLs used for loading classes and resources.
107 */
108 public URL[] getURLs() {
109 URL[] jars = super.getURLs();
110 URL[] urls = new URL[jars.length + 1];
111 System.arraycopy(jars, 0, urls, 0, jars.length);
112 urls[urls.length - 1] = base;
113 return urls;
114 }
115
116 /*
117 * Adds the specified JAR file to the search path of loaded JAR files.
118 * Changed modifier to protected in order to be able to overwrite addJar()
119 * in PluginClassLoader.java
120 */
121 protected void addJar(String name) throws IOException {
122 URL url;
123 try {
124 url = new URL(base, name);
125 } catch (MalformedURLException e) {
126 throw new IllegalArgumentException("name");
127 }
128 addURL(url);
129 // DEBUG
130 //URL[] urls = getURLs();
131 //for (int i = 0; i < urls.length; i++) {
132 // System.out.println("url[" + i + "] = " + urls[i]);
133 //}
134 }
135
136 /*
137 * Override loadClass so that class loading errors can be caught in
138 * order to print better error messages.
139 */
140 public synchronized Class loadClass(String name, boolean resolve)
141 throws ClassNotFoundException
142 {
143 // First check if we have permission to access the package. This
144 // should go away once we've added support for exported packages.
145 int i = name.lastIndexOf('.');
146 if (i != -1) {
147 SecurityManager sm = System.getSecurityManager();
148 if (sm != null)
149 sm.checkPackageAccess(name.substring(0, i));
150 }
151 try {
152 return super.loadClass(name, resolve);
153 } catch (ClassNotFoundException e) {
154 //printError(name, e.getException());
155 throw e;
156 } catch (RuntimeException e) {
157 //printError(name, e);
158 throw e;
159 } catch (Error e) {
160 //printError(name, e);
161 throw e;
162 }
163 }
164
165 /*
166 * Finds the applet class with the specified name. First searches
167 * loaded JAR files then the applet code base for the class.
168 */
169 protected Class findClass(String name) throws ClassNotFoundException {
170
171 int index = name.indexOf(";");
172 String cookie = "";
173 if(index != -1) {
174 cookie = name.substring(index, name.length());
175 name = name.substring(0, index);
176 }
177
178 // check loaded JAR files
179 try {
180 return super.findClass(name);
181 } catch (ClassNotFoundException e) {
182 }
183
184 // Otherwise, try loading the class from the code base URL
185
186 // 4668479: Option to turn off codebase lookup in AppletClassLoader
187 // during resource requests. [stanley.ho]
188 if (codebaseLookup == false)
189 throw new ClassNotFoundException(name);
190
191// final String path = name.replace('.', '/').concat(".class").concat(cookie);
192 String encodedName = ParseUtil.encodePath(name.replace('.', '/'), false);
193 final String path = (new StringBuffer(encodedName)).append(".class").append(cookie).toString();
194 try {
195 byte[] b = (byte[]) AccessController.doPrivileged(
196 new PrivilegedExceptionAction() {
197 public Object run() throws IOException {
198 try {
199 URL finalURL = new URL(base, path);
200
201 // Make sure the codebase won't be modified
202 if (base.getProtocol().equals(finalURL.getProtocol()) &&
203 base.getHost().equals(finalURL.getHost()) &&
204 base.getPort() == finalURL.getPort()) {
205 return getBytes(finalURL);
206 }
207 else {
208 return null;
209 }
210 } catch (Exception e) {
211 return null;
212 }
213 }
214 }, acc);
215
216 if (b != null) {
217 return defineClass(name, b, 0, b.length, codesource);
218 } else {
219 throw new ClassNotFoundException(name);
220 }
221 } catch (PrivilegedActionException e) {
222 throw new ClassNotFoundException(name, e.getException());
223 }
224 }
225
226 /**
227 * Returns the permissions for the given codesource object.
228 * The implementation of this method first calls super.getPermissions,
229 * to get the permissions
230 * granted by the super class, and then adds additional permissions
231 * based on the URL of the codesource.
232 * <p>
233 * If the protocol is "file"
234 * and the path specifies a file, permission is granted to read all files
235 * and (recursively) all files and subdirectories contained in
236 * that directory. This is so applets with a codebase of
237 * file:/blah/some.jar can read in file:/blah/, which is needed to
238 * be backward compatible. We also add permission to connect back to
239 * the "localhost".
240 *
241 * @param codesource the codesource
242 * @return the permissions granted to the codesource
243 */
244 protected PermissionCollection getPermissions(CodeSource codesource)
245 {
246 final PermissionCollection perms = super.getPermissions(codesource);
247
248 URL url = codesource.getLocation();
249
250 String path = null;
251 Permission p;
252
253 try {
254 p = url.openConnection().getPermission();
255 } catch (java.io.IOException ioe) {
256 p = null;
257 }
258
259 if (p instanceof FilePermission) {
260 path = p.getName();
261 } else if ((p == null) && (url.getProtocol().equals("file"))) {
262 path = url.getFile().replace('/', File.separatorChar);
263 path = ParseUtil.decode(path);
264 }
265
266 if (path != null) {
267 final String rawPath = path;
268 if (!path.endsWith(File.separator)) {
269 int endIndex = path.lastIndexOf(File.separatorChar);
270 if (endIndex != -1) {
271 path = path.substring(0, endIndex + 1) + "-";
272 perms.add(new FilePermission(path,
273 SecurityConstants.FILE_READ_ACTION));
274 }
275 }
276 final File f = new File(rawPath);
277 final boolean isDirectory = f.isDirectory();
278 // grant codebase recursive read permission
279 // this should only be granted to non-UNC file URL codebase and
280 // the codesource path must either be a directory, or a file
281 // that ends with .jar or .zip
282 if (allowRecursiveDirectoryRead && (isDirectory ||
283 rawPath.toLowerCase().endsWith(".jar") ||
284 rawPath.toLowerCase().endsWith(".zip"))) {
285
286 Permission bperm;
287 try {
288 bperm = base.openConnection().getPermission();
289 } catch (java.io.IOException ioe) {
290 bperm = null;
291 }
292 if (bperm instanceof FilePermission) {
293 String bpath = bperm.getName();
294 if (bpath.endsWith(File.separator)) {
295 bpath += "-";
296 }
297 perms.add(new FilePermission(bpath,
298 SecurityConstants.FILE_READ_ACTION));
299 } else if ((bperm == null) && (base.getProtocol().equals("file"))) {
300 String bpath = base.getFile().replace('/', File.separatorChar);
301 bpath = ParseUtil.decode(bpath);
302 if (bpath.endsWith(File.separator)) {
303 bpath += "-";
304 }
305 perms.add(new FilePermission(bpath, SecurityConstants.FILE_READ_ACTION));
306 }
307
308 }
309 }
310 return perms;
311 }
312
313 /*
314 * Returns the contents of the specified URL as an array of bytes.
315 */
316 private static byte[] getBytes(URL url) throws IOException {
317 URLConnection uc = url.openConnection();
318 if (uc instanceof java.net.HttpURLConnection) {
319 java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc;
320 int code = huc.getResponseCode();
321 if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) {
322 throw new IOException("open HTTP connection failed.");
323 }
324 }
325 int len = uc.getContentLength();
326
327 // Fixed #4507227: Slow performance to load
328 // class and resources. [stanleyh]
329 //
330 // Use buffered input stream [stanleyh]
331 InputStream in = new BufferedInputStream(uc.getInputStream());
332
333 byte[] b;
334 try {
335 b = IOUtils.readFully(in, len, true);
336 } finally {
337 in.close();
338 }
339 return b;
340 }
341
342 // Object for synchronization around getResourceAsStream()
343 private Object syncResourceAsStream = new Object();
344 private Object syncResourceAsStreamFromJar = new Object();
345
346 // Flag to indicate getResourceAsStream() is in call
347 private boolean resourceAsStreamInCall = false;
348 private boolean resourceAsStreamFromJarInCall = false;
349
350 /**
351 * Returns an input stream for reading the specified resource.
352 *
353 * The search order is described in the documentation for {@link
354 * #getResource(String)}.<p>
355 *
356 * @param name the resource name
357 * @return an input stream for reading the resource, or <code>null</code>
358 * if the resource could not be found
359 * @since JDK1.1
360 */
361 public InputStream getResourceAsStream(String name)
362 {
363
364 if (name == null) {
365 throw new NullPointerException("name");
366 }
367
368 try
369 {
370 InputStream is = null;
371
372 // Fixed #4507227: Slow performance to load
373 // class and resources. [stanleyh]
374 //
375 // The following is used to avoid calling
376 // AppletClassLoader.findResource() in
377 // super.getResourceAsStream(). Otherwise,
378 // unnecessary connection will be made.
379 //
380 synchronized(syncResourceAsStream)
381 {
382 resourceAsStreamInCall = true;
383
384 // Call super class
385 is = super.getResourceAsStream(name);
386
387 resourceAsStreamInCall = false;
388 }
389
390 // 4668479: Option to turn off codebase lookup in AppletClassLoader
391 // during resource requests. [stanley.ho]
392 if (codebaseLookup == true && is == null)
393 {
394 // If resource cannot be obtained,
395 // try to download it from codebase
396 URL url = new URL(base, ParseUtil.encodePath(name, false));
397 is = url.openStream();
398 }
399
400 return is;
401 }
402 catch (Exception e)
403 {
404 return null;
405 }
406 }
407
408
409 /**
410 * Returns an input stream for reading the specified resource from the
411 * the loaded jar files.
412 *
413 * The search order is described in the documentation for {@link
414 * #getResource(String)}.<p>
415 *
416 * @param name the resource name
417 * @return an input stream for reading the resource, or <code>null</code>
418 * if the resource could not be found
419 * @since JDK1.1
420 */
421 public InputStream getResourceAsStreamFromJar(String name) {
422
423 if (name == null) {
424 throw new NullPointerException("name");
425 }
426
427 try {
428 InputStream is = null;
429 synchronized(syncResourceAsStreamFromJar) {
430 resourceAsStreamFromJarInCall = true;
431 // Call super class
432 is = super.getResourceAsStream(name);
433 resourceAsStreamFromJarInCall = false;
434 }
435
436 return is;
437 } catch (Exception e) {
438 return null;
439 }
440 }
441
442
443 /*
444 * Finds the applet resource with the specified name. First checks
445 * loaded JAR files then the applet code base for the resource.
446 */
447 public URL findResource(String name) {
448 // check loaded JAR files
449 URL url = super.findResource(name);
450
451 // 6215746: Disable META-INF/* lookup from codebase in
452 // applet/plugin classloader. [stanley.ho]
453 if (name.startsWith("META-INF/"))
454 return url;
455
456 // 4668479: Option to turn off codebase lookup in AppletClassLoader
457 // during resource requests. [stanley.ho]
458 if (codebaseLookup == false)
459 return url;
460
461 if (url == null)
462 {
463 //#4805170, if it is a call from Applet.getImage()
464 //we should check for the image only in the archives
465 boolean insideGetResourceAsStreamFromJar = false;
466 synchronized(syncResourceAsStreamFromJar) {
467 insideGetResourceAsStreamFromJar = resourceAsStreamFromJarInCall;
468 }
469
470 if (insideGetResourceAsStreamFromJar) {
471 return null;
472 }
473
474 // Fixed #4507227: Slow performance to load
475 // class and resources. [stanleyh]
476 //
477 // Check if getResourceAsStream is called.
478 //
479 boolean insideGetResourceAsStream = false;
480
481 synchronized(syncResourceAsStream)
482 {
483 insideGetResourceAsStream = resourceAsStreamInCall;
484 }
485
486 // If getResourceAsStream is called, don't
487 // trigger the following code. Otherwise,
488 // unnecessary connection will be made.
489 //
490 if (insideGetResourceAsStream == false)
491 {
492 // otherwise, try the code base
493 try {
494 url = new URL(base, ParseUtil.encodePath(name, false));
495 // check if resource exists
496 if(!resourceExists(url))
497 url = null;
498 } catch (Exception e) {
499 // all exceptions, including security exceptions, are caught
500 url = null;
501 }
502 }
503 }
504 return url;
505 }
506
507
508 private boolean resourceExists(URL url) {
509 // Check if the resource exists.
510 // It almost works to just try to do an openConnection() but
511 // HttpURLConnection will return true on HTTP_BAD_REQUEST
512 // when the requested name ends in ".html", ".htm", and ".txt"
513 // and we want to be able to handle these
514 //
515 // Also, cannot just open a connection for things like FileURLConnection,
516 // because they succeed when connecting to a nonexistent file.
517 // So, in those cases we open and close an input stream.
518 boolean ok = true;
519 try {
520 URLConnection conn = url.openConnection();
521 if (conn instanceof java.net.HttpURLConnection) {
522 java.net.HttpURLConnection hconn =
523 (java.net.HttpURLConnection) conn;
524
525 // To reduce overhead, using http HEAD method instead of GET method
526 hconn.setRequestMethod("HEAD");
527
528 int code = hconn.getResponseCode();
529 if (code == java.net.HttpURLConnection.HTTP_OK) {
530 return true;
531 }
532 if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) {
533 return false;
534 }
535 } else {
536 /**
537 * Fix for #4182052 - stanleyh
538 *
539 * The same connection should be reused to avoid multiple
540 * HTTP connections
541 */
542
543 // our best guess for the other cases
544 InputStream is = conn.getInputStream();
545 is.close();
546 }
547 } catch (Exception ex) {
548 ok = false;
549 }
550 return ok;
551 }
552
553 /*
554 * Returns an enumeration of all the applet resources with the specified
555 * name. First checks loaded JAR files then the applet code base for all
556 * available resources.
557 */
558 public Enumeration findResources(String name) throws IOException {
559
560 final Enumeration e = super.findResources(name);
561
562 // 6215746: Disable META-INF/* lookup from codebase in
563 // applet/plugin classloader. [stanley.ho]
564 if (name.startsWith("META-INF/"))
565 return e;
566
567 // 4668479: Option to turn off codebase lookup in AppletClassLoader
568 // during resource requests. [stanley.ho]
569 if (codebaseLookup == false)
570 return e;
571
572 URL u = new URL(base, ParseUtil.encodePath(name, false));
573 if (!resourceExists(u)) {
574 u = null;
575 }
576
577 final URL url = u;
578 return new Enumeration() {
579 private boolean done;
580 public Object nextElement() {
581 if (!done) {
582 if (e.hasMoreElements()) {
583 return e.nextElement();
584 }
585 done = true;
586 if (url != null) {
587 return url;
588 }
589 }
590 throw new NoSuchElementException();
591 }
592 public boolean hasMoreElements() {
593 return !done && (e.hasMoreElements() || url != null);
594 }
595 };
596 }
597
598 /*
599 * Load and resolve the file specified by the applet tag CODE
600 * attribute. The argument can either be the relative path
601 * of the class file itself or just the name of the class.
602 */
603 Class loadCode(String name) throws ClassNotFoundException {
604 // first convert any '/' or native file separator to .
605 name = name.replace('/', '.');
606 name = name.replace(File.separatorChar, '.');
607
608 // deal with URL rewriting
609 String cookie = null;
610 int index = name.indexOf(";");
611 if(index != -1) {
612 cookie = name.substring(index, name.length());
613 name = name.substring(0, index);
614 }
615
616 // save that name for later
617 String fullName = name;
618 // then strip off any suffixes
619 if (name.endsWith(".class") || name.endsWith(".java")) {
620 name = name.substring(0, name.lastIndexOf('.'));
621 }
622 try {
623 if(cookie != null)
624 name = (new StringBuffer(name)).append(cookie).toString();
625 return loadClass(name);
626 } catch (ClassNotFoundException e) {
627 }
628 // then if it didn't end with .java or .class, or in the
629 // really pathological case of a class named class or java
630 if(cookie != null)
631 fullName = (new StringBuffer(fullName)).append(cookie).toString();
632
633 return loadClass(fullName);
634 }
635
636 /*
637 * The threadgroup that the applets loaded by this classloader live
638 * in. In the sun.* implementation of applets, the security manager's
639 * (AppletSecurity) getThreadGroup returns the thread group of the
640 * first applet on the stack, which is the applet's thread group.
641 */
642 private AppletThreadGroup threadGroup;
643 private AppContext appContext;
644
645 public ThreadGroup getThreadGroup() {
646 synchronized (threadGroupSynchronizer) {
647 if (threadGroup == null || threadGroup.isDestroyed()) {
648 AccessController.doPrivileged(new PrivilegedAction() {
649 public Object run() {
650 threadGroup = new AppletThreadGroup(base + "-threadGroup");
651 // threadGroup.setDaemon(true);
652 // threadGroup is now destroyed by AppContext.dispose()
653
654 // Create the new AppContext from within a Thread belonging
655 // to the newly created ThreadGroup, and wait for the
656 // creation to complete before returning from this method.
657 AppContextCreator creatorThread = new AppContextCreator(threadGroup);
658
659 // Since this thread will later be used to launch the
660 // applet's AWT-event dispatch thread and we want the applet
661 // code executing the AWT callbacks to use their own class
662 // loader rather than the system class loader, explicitly
663 // set the context class loader to the AppletClassLoader.
664 creatorThread.setContextClassLoader(AppletClassLoader.this);
665
666 creatorThread.start();
667 try {
668 synchronized(creatorThread.syncObject) {
669 while (!creatorThread.created) {
670 creatorThread.syncObject.wait();
671 }
672 }
673 } catch (InterruptedException e) { }
674 appContext = creatorThread.appContext;
675 return null;
676 }
677 });
678 }
679 return threadGroup;
680 }
681 }
682
683 /*
684 * Get the AppContext, if any, corresponding to this AppletClassLoader.
685 */
686 public AppContext getAppContext() {
687 return appContext;
688 }
689
690 int usageCount = 0;
691
692 /**
693 * Grab this AppletClassLoader and its ThreadGroup/AppContext, so they
694 * won't be destroyed.
695 */
696public void grab() {
697 synchronized(grabReleaseSynchronizer) {
698 usageCount++;
699 }
700 getThreadGroup(); // Make sure ThreadGroup/AppContext exist
701 }
702
703 protected void setExceptionStatus()
704 {
705 exceptionStatus = true;
706 }
707
708 public boolean getExceptionStatus()
709 {
710 return exceptionStatus;
711 }
712
713 /**
714 * Release this AppletClassLoader and its ThreadGroup/AppContext.
715 * If nothing else has grabbed this AppletClassLoader, its ThreadGroup
716 * and AppContext will be destroyed.
717 *
718 * Because this method may destroy the AppletClassLoader's ThreadGroup,
719 * this method should NOT be called from within the AppletClassLoader's
720 * ThreadGroup.
721 *
722 * Changed modifier to protected in order to be able to overwrite this
723 * function in PluginClassLoader.java
724 */
725 protected void release() {
726
727 AppContext tempAppContext = null;
728
729 synchronized(grabReleaseSynchronizer) {
730 if (usageCount > 1) {
731 --usageCount;
732 } else {
733 synchronized(threadGroupSynchronizer) {
734 tempAppContext = resetAppContext();
735 }
736 }
737 }
738
739 // Dispose appContext outside any sync block to
740 // prevent potential deadlock.
741 if (tempAppContext != null) {
742 try {
743 tempAppContext.dispose(); // nuke the world!
744 } catch (IllegalThreadStateException e) { }
745 }
746 }
747
748 /*
749 * reset classloader's AppContext and ThreadGroup
750 * This method is for subclass PluginClassLoader to
751 * reset superclass's AppContext and ThreadGroup but do
752 * not dispose the AppContext. PluginClassLoader does not
753 * use UsageCount to decide whether to dispose AppContext
754 *
755 * @return previous AppContext
756 */
757 protected AppContext resetAppContext() {
758 AppContext tempAppContext = null;
759
760 synchronized(threadGroupSynchronizer) {
761 // Store app context in temp variable
762 tempAppContext = appContext;
763 usageCount = 0;
764 appContext = null;
765 threadGroup = null;
766 }
767 return tempAppContext;
768 }
769
770
771 // Hash map to store applet compatibility info
772 private HashMap jdk11AppletInfo = new HashMap();
773 private HashMap jdk12AppletInfo = new HashMap();
774
775 /**
776 * Set applet target level as JDK 1.1.
777 *
778 * @param clazz Applet class.
779 * @param bool true if JDK is targeted for JDK 1.1;
780 * false otherwise.
781 */
782 void setJDK11Target(Class clazz, boolean bool)
783 {
784 jdk11AppletInfo.put(clazz.toString(), Boolean.valueOf(bool));
785 }
786
787 /**
788 * Set applet target level as JDK 1.2.
789 *
790 * @param clazz Applet class.
791 * @param bool true if JDK is targeted for JDK 1.2;
792 * false otherwise.
793 */
794 void setJDK12Target(Class clazz, boolean bool)
795 {
796 jdk12AppletInfo.put(clazz.toString(), Boolean.valueOf(bool));
797 }
798
799 /**
800 * Determine if applet is targeted for JDK 1.1.
801 *
802 * @param applet Applet class.
803 * @return TRUE if applet is targeted for JDK 1.1;
804 * FALSE if applet is not;
805 * null if applet is unknown.
806 */
807 Boolean isJDK11Target(Class clazz)
808 {
809 return (Boolean) jdk11AppletInfo.get(clazz.toString());
810 }
811
812 /**
813 * Determine if applet is targeted for JDK 1.2.
814 *
815 * @param applet Applet class.
816 * @return TRUE if applet is targeted for JDK 1.2;
817 * FALSE if applet is not;
818 * null if applet is unknown.
819 */
820 Boolean isJDK12Target(Class clazz)
821 {
822 return (Boolean) jdk12AppletInfo.get(clazz.toString());
823 }
824
825 private static AppletMessageHandler mh =
826 new AppletMessageHandler("appletclassloader");
827
828 /*
829 * Prints a class loading error message.
830 */
831 private static void printError(String name, Throwable e) {
832 String s = null;
833 if (e == null) {
834 s = mh.getMessage("filenotfound", name);
835 } else if (e instanceof IOException) {
836 s = mh.getMessage("fileioexception", name);
837 } else if (e instanceof ClassFormatError) {
838 s = mh.getMessage("fileformat", name);
839 } else if (e instanceof ThreadDeath) {
840 s = mh.getMessage("filedeath", name);
841 } else if (e instanceof Error) {
842 s = mh.getMessage("fileerror", e.toString(), name);
843 }
844 if (s != null) {
845 System.err.println(s);
846 }
847 }
848}
849
850/*
851 * The AppContextCreator class is used to create an AppContext from within
852 * a Thread belonging to the new AppContext's ThreadGroup. To wait for
853 * this operation to complete before continuing, wait for the notifyAll()
854 * operation on the syncObject to occur.
855 */
856class AppContextCreator extends Thread {
857 Object syncObject = new Object();
858 AppContext appContext = null;
859 volatile boolean created = false;
860
861 AppContextCreator(ThreadGroup group) {
862 super(group, "AppContextCreator");
863 }
864
865 public void run() {
866 appContext = SunToolkit.createNewAppContext();
867 created = true;
868 synchronized(syncObject) {
869 syncObject.notifyAll();
870 }
871 } // run()
872
873} // class AppContextCreator