} } } return url; } private boolean resourceExists(URL url) { // Check if the resource exists. // It almost works to just try to do an openConnection() but // HttpURLConnection will return true on HTTP_BAD_REQUEST // when the requested name ends in ".html", ".htm", and ".txt" // and we want to be able to handle these // // Also, cannot just open a connection for things like FileURLConnection, // because they succeed when connecting to a nonexistent file. // So, in those cases we open and close an input stream. boolean ok = true; try { URLConnection conn = url.openConnection(); if (conn instanceof java.net.HttpURLConnection) { java.net.HttpURLConnection hconn = (java.net.HttpURLConnection) conn; // To reduce overhead, using http HEAD method instead of GET method hconn.setRequestMethod("HEAD"); int code = hconn.getResponseCode(); if (code == java.net.HttpURLConnection.HTTP_OK) { return true; } if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) { return false; } } else { /** * Fix for #4182052 - stanleyh * * The same connection should be reused to avoid multiple * HTTP connections */ // our best guess for the other cases InputStream is = conn.getInputStream(); is.close(); } } catch (Exception ex) { ok = false; } return ok; } /* * Returns an enumeration of all the applet resources with the specified * name. First checks loaded JAR files then the applet code base for all * available resources. */ public Enumeration findResources(String name) throws IOException { final Enumeration e = super.findResources(name); // 6215746: Disable META-INF/* lookup from codebase in // applet/plugin classloader. [stanley.ho] if (name.startsWith("META-INF/")) return e; // 4668479: Option to turn off codebase lookup in AppletClassLoader // during resource requests. [stanley.ho] if (codebaseLookup == false) return e; URL u = new URL(base, ParseUtil.encodePath(name, false)); if (!resourceExists(u)) { u = null; } final URL url = u; return new Enumeration() { private boolean done; public Object nextElement() { if (!done) { if (e.hasMoreElements()) { return e.nextElement(); } done = true; if (url != null) { return url; } } throw new NoSuchElementException(); } public boolean hasMoreElements() { return !done && (e.hasMoreElements() || url != null); } }; } /* * Load and resolve the file specified by the applet tag CODE * attribute. The argument can either be the relative path * of the class file itself or just the name of the class. */ Class loadCode(String name) throws ClassNotFoundException { // first convert any '/' or native file separator to . name = name.replace('/', '.'); name = name.replace(File.separatorChar, '.'); // deal with URL rewriting String cookie = null; int index = name.indexOf(";"); if(index != -1) { cookie = name.substring(index, name.length()); name = name.substring(0, index); } // save that name for later String fullName = name; // then strip off any suffixes if (name.endsWith(".class") || name.endsWith(".java")) { name = name.substring(0, name.lastIndexOf('.')); } try { if(cookie != null) name = (new StringBuffer(name)).append(cookie).toString(); return loadClass(name); } catch (ClassNotFoundException e) { } // then if it didn't end with .java or .class, or in the // really pathological case of a class named class or java if(cookie != null) fullName = (new StringBuffer(fullName)).append(cookie).toString(); return loadClass(fullName); } /* * The threadgroup that the applets loaded by this classloader live * in. In the sun.* implementation of applets, the security manager's * (AppletSecurity) getThreadGroup returns the thread group of the * first applet on the stack, which is the applet's thread group. */ private AppletThreadGroup threadGroup; private AppContext appContext; public ThreadGroup getThreadGroup() { synchronized (threadGroupSynchronizer) { if (threadGroup == null || threadGroup.isDestroyed()) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { threadGroup = new AppletThreadGroup(base + "-threadGroup"); // threadGroup.setDaemon(true); // threadGroup is now destroyed by AppContext.dispose() // Create the new AppContext from within a Thread belonging // to the newly created ThreadGroup, and wait for the // creation to complete before returning from this method. AppContextCreator creatorThread = new AppContextCreator(threadGroup); // Since this thread will later be used to launch the // applet's AWT-event dispatch thread and we want the applet // code executing the AWT callbacks to use their own class // loader rather than the system class loader, explicitly // set the context class loader to the AppletClassLoader. creatorThread.setContextClassLoader(AppletClassLoader.this); creatorThread.start(); try { synchronized(creatorThread.syncObject) { while (!creatorThread.created) { creatorThread.syncObject.wait(); } } } catch (InterruptedException e) { } appContext = creatorThread.appContext; return null; } }); } return threadGroup; } } /* * Get the AppContext, if any, corresponding to this AppletClassLoader. */ public AppContext getAppContext() { return appContext; } int usageCount = 0; /** * Grab this AppletClassLoader and its ThreadGroup/AppContext, so they * won't be destroyed. */public void grab() { synchronized(grabReleaseSynchronizer) { usageCount++; } getThreadGroup(); // Make sure ThreadGroup/AppContext exist } protected void setExceptionStatus() { exceptionStatus = true; } public boolean getExceptionStatus() { return exceptionStatus; } /** * Release this AppletClassLoader and its ThreadGroup/AppContext. * If nothing else has grabbed this AppletClassLoader, its ThreadGroup * and AppContext will be destroyed. * * Because this method may destroy the AppletClassLoader's ThreadGroup, * this method should NOT be called from within the AppletClassLoader's * ThreadGroup. * * Changed modifier to protected in order to be able to overwrite this * function in PluginClassLoader.java */ protected void release() { AppContext tempAppContext = null; synchronized(grabReleaseSynchronizer) { if (usageCount > 1) { --usageCount; } else { synchronized(threadGroupSynchronizer) { tempAppContext = resetAppContext(); } } } // Dispose appContext outside any sync block to // prevent potential deadlock. if (tempAppContext != null) { try { tempAppContext.dispose(); // nuke the world! } catch (IllegalThreadStateException e) { } } } /* * reset classloader's AppContext and ThreadGroup * This method is for subclass PluginClassLoader to * reset superclass's AppContext and ThreadGroup but do * not dispose the AppContext. PluginClassLoader does not * use UsageCount to decide whether to dispose AppContext * * @return previous AppContext */ protected AppContext resetAppContext() { AppContext tempAppContext = null; synchronized(threadGroupSynchronizer) { // Store app context in temp variable tempAppContext = appContext; usageCount = 0; appContext = null; threadGroup = null; } return tempAppContext; } // Hash map to store applet compatibility info private HashMap jdk11AppletInfo = new HashMap(); private HashMap jdk12AppletInfo = new HashMap(); /** * Set applet target level as JDK 1.1. * * @param clazz Applet class. * @param bool true if JDK is targeted for JDK 1.1; * false otherwise. */ void setJDK11Target(Class clazz, boolean bool) { jdk11AppletInfo.put(clazz.toString(), Boolean.valueOf(bool)); } /** * Set applet target level as JDK 1.2. * * @param clazz Applet class. * @param bool true if JDK is targeted for JDK 1.2; * false otherwise. */ void setJDK12Target(Class clazz, boolean bool) { jdk12AppletInfo.put(clazz.toString(), Boolean.valueOf(bool)); } /** * Determine if applet is targeted for JDK 1.1. * * @param applet Applet class. * @return TRUE if applet is targeted for JDK 1.1; * FALSE if applet is not; * null if applet is unknown. */ Boolean isJDK11Target(Class clazz) { return (Boolean) jdk11AppletInfo.get(clazz.toString()); } /** * Determine if applet is targeted for JDK 1.2. * * @param applet Applet class. * @return TRUE if applet is targeted for JDK 1.2; * FALSE if applet is not; * null if applet is unknown. */ Boolean isJDK12Target(Class clazz) { return (Boolean) jdk12AppletInfo.get(clazz.toString()); } private static AppletMessageHandler mh = new AppletMessageHandler("appletclassloader"); /* * Prints a class loading error message. */ private static void printError(String name, Throwable e) { String s = null; if (e == null) { s = mh.getMessage("filenotfound", name); } else if (e instanceof IOException) { s = mh.getMessage("fileioexception", name); } else if (e instanceof ClassFormatError) { s = mh.getMessage("fileformat", name); } else if (e instanceof ThreadDeath) { s = mh.getMessage("filedeath", name); } else if (e instanceof Error) { s = mh.getMessage("fileerror", e.toString(), name); } if (s != null) { System.err.println(s); } }} /* * The AppContextCreator class is used to create an AppContext from within * a Thread belonging to the new AppContext's ThreadGroup. To wait for * this operation to complete before continuing, wait for the notifyAll() * operation on the syncObject to occur. */class AppContextCreator extends Thread { Object syncObject = new Object(); AppContext appContext = null; volatile boolean created = false; AppContextCreator(ThreadGroup group) { super(group, "AppContextCreator"); } public void run() { appContext = SunToolkit.createNewAppContext(); created = true; synchronized(syncObject) { syncObject.notifyAll(); } } // run() } // class AppContextCreatorLines 501–873 of 873. Previous lines
} } } return url; } private boolean resourceExists(URL url) { // Check if the resource exists. // It almost works to just try to do an openConnection() but // HttpURLConnection will return true on HTTP_BAD_REQUEST // when the requested name ends in ".html", ".htm", and ".txt" // and we want to be able to handle these // // Also, cannot just open a connection for things like FileURLConnection, // because they succeed when connecting to a nonexistent file. // So, in those cases we open and close an input stream. boolean ok = true; try { URLConnection conn = url.openConnection(); if (conn instanceof java.net.HttpURLConnection) { java.net.HttpURLConnection hconn = (java.net.HttpURLConnection) conn; // To reduce overhead, using http HEAD method instead of GET method hconn.setRequestMethod("HEAD"); int code = hconn.getResponseCode(); if (code == java.net.HttpURLConnection.HTTP_OK) { return true; } if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) { return false; } } else { /** * Fix for #4182052 - stanleyh * * The same connection should be reused to avoid multiple * HTTP connections */ // our best guess for the other cases InputStream is = conn.getInputStream(); is.close(); } } catch (Exception ex) { ok = false; } return ok; } /* * Returns an enumeration of all the applet resources with the specified * name. First checks loaded JAR files then the applet code base for all * available resources. */ public Enumeration findResources(String name) throws IOException { final Enumeration e = super.findResources(name); // 6215746: Disable META-INF/* lookup from codebase in // applet/plugin classloader. [stanley.ho] if (name.startsWith("META-INF/")) return e; // 4668479: Option to turn off codebase lookup in AppletClassLoader // during resource requests. [stanley.ho] if (codebaseLookup == false) return e; URL u = new URL(base, ParseUtil.encodePath(name, false)); if (!resourceExists(u)) { u = null; } final URL url = u; return new Enumeration() { private boolean done; public Object nextElement() { if (!done) { if (e.hasMoreElements()) { return e.nextElement(); } done = true; if (url != null) { return url; } } throw new NoSuchElementException(); } public boolean hasMoreElements() { return !done && (e.hasMoreElements() || url != null); } }; } /* * Load and resolve the file specified by the applet tag CODE * attribute. The argument can either be the relative path * of the class file itself or just the name of the class. */ Class loadCode(String name) throws ClassNotFoundException { // first convert any '/' or native file separator to . name = name.replace('/', '.'); name = name.replace(File.separatorChar, '.'); // deal with URL rewriting String cookie = null; int index = name.indexOf(";"); if(index != -1) { cookie = name.substring(index, name.length()); name = name.substring(0, index); } // save that name for later String fullName = name; // then strip off any suffixes if (name.endsWith(".class") || name.endsWith(".java")) { name = name.substring(0, name.lastIndexOf('.')); } try { if(cookie != null) name = (new StringBuffer(name)).append(cookie).toString(); return loadClass(name); } catch (ClassNotFoundException e) { } // then if it didn't end with .java or .class, or in the // really pathological case of a class named class or java if(cookie != null) fullName = (new StringBuffer(fullName)).append(cookie).toString(); return loadClass(fullName); } /* * The threadgroup that the applets loaded by this classloader live * in. In the sun.* implementation of applets, the security manager's * (AppletSecurity) getThreadGroup returns the thread group of the * first applet on the stack, which is the applet's thread group. */ private AppletThreadGroup threadGroup; private AppContext appContext; public ThreadGroup getThreadGroup() { synchronized (threadGroupSynchronizer) { if (threadGroup == null || threadGroup.isDestroyed()) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { threadGroup = new AppletThreadGroup(base + "-threadGroup"); // threadGroup.setDaemon(true); // threadGroup is now destroyed by AppContext.dispose() // Create the new AppContext from within a Thread belonging // to the newly created ThreadGroup, and wait for the // creation to complete before returning from this method. AppContextCreator creatorThread = new AppContextCreator(threadGroup); // Since this thread will later be used to launch the // applet's AWT-event dispatch thread and we want the applet // code executing the AWT callbacks to use their own class // loader rather than the system class loader, explicitly // set the context class loader to the AppletClassLoader. creatorThread.setContextClassLoader(AppletClassLoader.this); creatorThread.start(); try { synchronized(creatorThread.syncObject) { while (!creatorThread.created) { creatorThread.syncObject.wait(); } } } catch (InterruptedException e) { } appContext = creatorThread.appContext; return null; } }); } return threadGroup; } } /* * Get the AppContext, if any, corresponding to this AppletClassLoader. */ public AppContext getAppContext() { return appContext; } int usageCount = 0; /** * Grab this AppletClassLoader and its ThreadGroup/AppContext, so they * won't be destroyed. */ public void grab() { synchronized(grabReleaseSynchronizer) { usageCount++; } getThreadGroup(); // Make sure ThreadGroup/AppContext exist } protected void setExceptionStatus() { exceptionStatus = true; } public boolean getExceptionStatus() { return exceptionStatus; } /** * Release this AppletClassLoader and its ThreadGroup/AppContext. * If nothing else has grabbed this AppletClassLoader, its ThreadGroup * and AppContext will be destroyed. * * Because this method may destroy the AppletClassLoader's ThreadGroup, * this method should NOT be called from within the AppletClassLoader's * ThreadGroup. * * Changed modifier to protected in order to be able to overwrite this * function in PluginClassLoader.java */ protected void release() { AppContext tempAppContext = null; synchronized(grabReleaseSynchronizer) { if (usageCount > 1) { --usageCount; } else { synchronized(threadGroupSynchronizer) { tempAppContext = resetAppContext(); } } } // Dispose appContext outside any sync block to // prevent potential deadlock. if (tempAppContext != null) { try { tempAppContext.dispose(); // nuke the world! } catch (IllegalThreadStateException e) { } } } /* * reset classloader's AppContext and ThreadGroup * This method is for subclass PluginClassLoader to * reset superclass's AppContext and ThreadGroup but do * not dispose the AppContext. PluginClassLoader does not * use UsageCount to decide whether to dispose AppContext * * @return previous AppContext */ protected AppContext resetAppContext() { AppContext tempAppContext = null; synchronized(threadGroupSynchronizer) { // Store app context in temp variable tempAppContext = appContext; usageCount = 0; appContext = null; threadGroup = null; } return tempAppContext; } // Hash map to store applet compatibility info private HashMap jdk11AppletInfo = new HashMap(); private HashMap jdk12AppletInfo = new HashMap(); /** * Set applet target level as JDK 1.1. * * @param clazz Applet class. * @param bool true if JDK is targeted for JDK 1.1; * false otherwise. */ void setJDK11Target(Class clazz, boolean bool) { jdk11AppletInfo.put(clazz.toString(), Boolean.valueOf(bool)); } /** * Set applet target level as JDK 1.2. * * @param clazz Applet class. * @param bool true if JDK is targeted for JDK 1.2; * false otherwise. */ void setJDK12Target(Class clazz, boolean bool) { jdk12AppletInfo.put(clazz.toString(), Boolean.valueOf(bool)); } /** * Determine if applet is targeted for JDK 1.1. * * @param applet Applet class. * @return TRUE if applet is targeted for JDK 1.1; * FALSE if applet is not; * null if applet is unknown. */ Boolean isJDK11Target(Class clazz) { return (Boolean) jdk11AppletInfo.get(clazz.toString()); } /** * Determine if applet is targeted for JDK 1.2. * * @param applet Applet class. * @return TRUE if applet is targeted for JDK 1.2; * FALSE if applet is not; * null if applet is unknown. */ Boolean isJDK12Target(Class clazz) { return (Boolean) jdk12AppletInfo.get(clazz.toString()); } private static AppletMessageHandler mh = new AppletMessageHandler("appletclassloader"); /* * Prints a class loading error message. */ private static void printError(String name, Throwable e) { String s = null; if (e == null) { s = mh.getMessage("filenotfound", name); } else if (e instanceof IOException) { s = mh.getMessage("fileioexception", name); } else if (e instanceof ClassFormatError) { s = mh.getMessage("fileformat", name); } else if (e instanceof ThreadDeath) { s = mh.getMessage("filedeath", name); } else if (e instanceof Error) { s = mh.getMessage("fileerror", e.toString(), name); } if (s != null) { System.err.println(s); } } } /* * The AppContextCreator class is used to create an AppContext from within * a Thread belonging to the new AppContext's ThreadGroup. To wait for * this operation to complete before continuing, wait for the notifyAll() * operation on the syncObject to occur. */ class AppContextCreator extends Thread { Object syncObject = new Object(); AppContext appContext = null; volatile boolean created = false; AppContextCreator(ThreadGroup group) { super(group, "AppContextCreator"); } public void run() { appContext = SunToolkit.createNewAppContext(); created = true; synchronized(syncObject) { syncObject.notifyAll(); } } // run() } // class AppContextCreator