/** * Loads class from a JAR and searches for all jar-in-jar. * * @param sClassName class to load. * @return Loaded class. * @throws JarClassLoaderException. */ private Class<?> findJarClass(String sClassName) throws JarClassLoaderException { // http://java.sun.com/developer/onlineTraining/Security/Fundamentals // /magercises/ClassLoader/solution/FileClassLoader.java Class<?> c = hmClass.get(sClassName); if (c != null) { return c; } // Char '/' works for Win32 and Unix. String sName = sClassName.replace('.', '/') + ".class"; JarEntryInfo inf = findJarEntry(sName); String jarSimpleName = null; if (inf != null) { jarSimpleName = inf.jarFileInfo.simpleName; definePackage(sClassName, inf); byte[] a_by = inf.getJarBytes(); try { c = defineClass(sClassName, a_by, 0, a_by.length, pd); } catch (ClassFormatError e) { throw new JarClassLoaderException(null, e); } } if (c == null) { throw new JarClassLoaderException(sClassName); } hmClass.put(sClassName, c); logInfo( LogArea.CLASS, "Loaded %s by %s from JAR %s", sClassName, getClass().getName(), jarSimpleName); return c; } // findJarClass()
/** * Using temp files (one per inner JAR/DLL) solves many issues: 1. There are no ways to load JAR * defined in a JarEntry directly into the JarFile object (see also #6 below). 2. Cannot use * memory-mapped files because they are using nio channels, which are not supported by JarFile * ctor. 3. JarFile object keeps opened JAR files handlers for fast access. 4. Deep resource in a * jar-in-jar does not have well defined URL. Making temp file with JAR solves this problem. 5. * Similar issues with native libraries: <code>ClassLoader.findLibrary()</code> accepts ONLY * string with absolute path to the file with native library. 6. Option * "java.protocol.handler.pkgs" does not allow access to nested JARs(?). * * @param inf JAR entry information. * @return temporary file object presenting JAR entry. * @throws JarClassLoaderException */ private File createTempFile(JarEntryInfo inf) throws JarClassLoaderException { // Temp files directory: // WinXP: C:/Documents and Settings/username/Local Settings/Temp/JarClassLoader // Unix: /var/tmp/JarClassLoader if (dirTemp == null) { File dir = new File(System.getProperty("java.io.tmpdir"), TMP_SUB_DIRECTORY); if (!dir.exists()) { dir.mkdir(); } chmod777(dir); // Unix - allow temp directory RW access to all users. if (!dir.exists() || !dir.isDirectory()) { throw new JarClassLoaderException("Cannot create temp directory " + dir.getAbsolutePath()); } dirTemp = dir; } File fileTmp = null; try { fileTmp = File.createTempFile(inf.getName() + ".", null, dirTemp); fileTmp.deleteOnExit(); chmod777(fileTmp); // Unix - allow temp file deletion by any user byte[] a_by = inf.getJarBytes(); BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(fileTmp)); os.write(a_by); os.close(); return fileTmp; } catch (IOException e) { throw new JarClassLoaderException( String.format("Cannot create temp file '%s' for %s", fileTmp, inf.jarEntry), e); } } // createTempFile()