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

Save This Page
Home » openjdk-7 » sun » applet » [javadoc | source]