package org.kde.kjas.server; import java.net.*; import java.io.*; import java.util.*; import java.util.zip.*; import java.util.jar.*; import java.security.*; /** * ClassLoader used to download and instantiate Applets. *
* NOTE: The class loader extends Java 1.2 specific class. */ public final class KJASAppletClassLoader extends URLClassLoader { private static Hashtable loaders = new Hashtable(); public static synchronized void removeLoaders() { loaders.clear(); } public static synchronized KJASAppletClassLoader getLoader( String docBase, String codeBase, String archives ) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } URL docBaseURL; KJASAppletClassLoader loader = null; try { docBaseURL = new URL( docBase ); URL codeBaseURL = getCodeBaseURL( docBaseURL, codeBase ); String key = codeBaseURL.toString(); if (archives != null) key += archives; Main.debug( "CL: getLoader: key = " + key ); loader = (KJASAppletClassLoader) loaders.get( key ); if( loader == null ) { URL [] urlList = {}; loader = new KJASAppletClassLoader( urlList, docBaseURL, codeBaseURL); loaders.put( key, loader ); } else { Main.debug( "CL: reusing classloader" ); } } catch( MalformedURLException e ) { Main.kjas_err( "bad DocBase URL", e ); } return loader; } public static URL getCodeBaseURL( URL docBaseURL, String codeBase ) { URL codeBaseURL = null; try { //first determine what the real codeBase is: 3 cases //#1. codeBase is absolute URL- use that //#2. codeBase is relative to docBase, create url from those //#3. last resort, use docBase as the codeBase if(codeBase != null) { //we need to do this since codeBase should be a directory if( !codeBase.endsWith("/") ) codeBase = codeBase + "/"; try { codeBaseURL = new URL( codeBase ); } catch( MalformedURLException mue ) { try { codeBaseURL = new URL( docBaseURL, codeBase ); } catch( MalformedURLException mue2 ) {} } } if(codeBaseURL == null) { //fall back to docBase but fix it up... String file = docBaseURL.getFile(); if( file == null || (file.length() == 0) ) codeBaseURL = docBaseURL; else if( file.endsWith( "/" ) ) codeBaseURL = docBaseURL; else { //delete up to the ending '/' String urlString = docBaseURL.toString(); int dot_index = urlString.lastIndexOf( '/' ); String newfile = urlString.substring( 0, dot_index+1 ); codeBaseURL = new URL( newfile ); } } }catch( Exception e ) { Main.kjas_err( "CL: exception ", e ); } return codeBaseURL; } public static KJASAppletClassLoader getLoader( String key ) { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkCreateClassLoader(); } if( loaders.containsKey( key ) ) return (KJASAppletClassLoader) loaders.get( key ); return null; } /********************************************************************************* ****************** KJASAppletClassLoader Implementation ************************* **********************************************************************************/ private URL docBaseURL; private URL codeBaseURL; private Vector archives; private String dbgID; private static int globalId = 0; private int myId = 0; private Vector statusListeners = new Vector(); private AccessControlContext acc; // a mapping JS referenced Java objects private Hashtable jsReferencedObjects = new Hashtable(); final static RuntimePermission kjas_access = new RuntimePermission("accessClassInPackage.org.kde.kjas.server"); public KJASAppletClassLoader( URL[] urlList, URL _docBaseURL, URL _codeBaseURL) { super(urlList); acc = AccessController.getContext(); synchronized(KJASAppletClassLoader.class) { myId = ++globalId; } docBaseURL = _docBaseURL; codeBaseURL = _codeBaseURL; archives = new Vector(); dbgID = "CL-" + myId + "(" + codeBaseURL.toString() + "): "; } protected void addURL(URL url) { Main.debug(this + " add URL: " + url); super.addURL(url); } public void addStatusListener(StatusListener lsnr) { statusListeners.add(lsnr); } public void removeStatusListener(StatusListener lsnr) { statusListeners.remove(lsnr); } public void showStatus(String msg) { Enumeration en = statusListeners.elements(); while (en.hasMoreElements()) { StatusListener lsnr = (StatusListener)en.nextElement(); lsnr.showStatus(msg); } } public void paramsDone() { // simply builds up the search path // put the archives first because they are // cached. for( int i = 0; i < archives.size(); ++i ) { String jar = (String)archives.elementAt( i ); try { URL jarURL = new URL(codeBaseURL, jar); addURL(jarURL); Main.debug("added archive URL \"" + jarURL + "\" to KJASAppletClassLoader"); } catch (MalformedURLException e) { Main.kjas_err("Could not construct URL for jar file: " + codeBaseURL + " + " + jar, e); } } // finally add code base url and docbase url addURL(codeBaseURL); // the docBaseURL has to be fixed. // strip file part from end otherwise this // will be interpreted as an archive // (should this perhaps be done generally ??) String dbs = docBaseURL.toString(); int idx = dbs.lastIndexOf("/"); if (idx > 0) { dbs = dbs.substring(0, idx+1); } URL docDirURL = null; try { docDirURL = new URL(dbs); } catch (MalformedURLException e) { Main.debug("Could not make a new URL from docBaseURL=" + docBaseURL); } if (docDirURL != null && !codeBaseURL.equals(docDirURL)) { addURL(docDirURL); } } void addArchiveName( String jarname ) { if( !archives.contains( jarname ) ) { archives.add( jarname ); } } public URL getDocBase() { return docBaseURL; } public URL getCodeBase() { return codeBaseURL; } Hashtable getJSReferencedObjects() { return jsReferencedObjects; } /*************************************************************************** **** Class Loading Methods **************************************************************************/ public synchronized Class findClass( String name ) throws ClassNotFoundException { Class rval = null; //check the loaded classes rval = findLoadedClass( name ); if( rval == null ) { try { rval = super.findClass(name); } catch (ClassFormatError cfe) { Main.debug(name + ": Catched " + cfe + ". Trying to repair..."); rval = loadFixedClass( name ); } catch (Exception ex) { Main.debug("findClass " + name + " " + ex.getMessage()); } } if (rval == null) { throw new ClassNotFoundException("Class: " + name); } return rval; } public Class loadClass(String name) throws ClassNotFoundException { if (name.startsWith("org.kde.kjas.server")) { SecurityManager sec = System.getSecurityManager(); if (sec != null) sec.checkPermission(kjas_access); } return super.loadClass(name); } private Hashtable loadedClasses = new Hashtable(); private synchronized final Class loadFixedClass(String name) throws ClassNotFoundException { final String fileName = name.replace('.', '/') + ".class"; try { // try to get the class as resource final URL u = getResource(fileName); Main.debug(dbgID + name + ": got URL: " + u); if (u == null) { throw new ClassNotFoundException(fileName + ": invalid resource URL."); } java.security.cert.Certificate[] certs = {}; // FIXME CodeSource cs = new CodeSource(u, certs); InputStream instream = (InputStream)AccessController.doPrivileged( new PrivilegedAction() { public Object run() { try { return u.openStream(); } catch (IOException ioe) { ioe.printStackTrace(); return null; } } }, acc ); if (instream == null) { throw new ClassNotFoundException(name + ": could not be loaded."); } ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); int cnt; int total = 0; int bufSize = 1024; byte [] buffer = new byte[bufSize]; while ((cnt = instream.read(buffer, 0, bufSize)) > 0) { total += cnt; byteStream.write(buffer, 0, cnt); } Main.debug(dbgID + name + ": " + total + " bytes"); Class cl = fixAndDefineClass(name, byteStream.toByteArray(), 0, total, cs); if (cl != null) { loadedClasses.put(name, cl); } return cl; } catch (Throwable e) { e.printStackTrace(); throw new ClassNotFoundException("triggered by " + e); } } public URL findResource( String name) { Main.debug( dbgID + "findResource, name = " + name ); String displayName = name; try { URL u = new URL(name); String filename = u.getFile(); if (filename != null && filename.length() > 0) { displayName = filename; } } catch (Throwable e) { } showStatus("Loading: " + displayName); URL url = super.findResource( name ); Main.debug("findResource for " + name + " returns " + url); return url; } protected PermissionCollection getPermissions(CodeSource cs) { Main.debug(dbgID + " getPermissions(" + cs + ")"); PermissionCollection permissions = super.getPermissions(cs); Enumeration perms_enum = permissions.elements(); while (perms_enum.hasMoreElements()) { Main.debug(this + " Permission: " + perms_enum.nextElement()); } return permissions; } /** * define the class name. If name is broken, try to fix it. */ private final Class fixAndDefineClass( String name, byte[] b, int off, int len, CodeSource cs) throws ClassFormatError { KJASBrokenClassFixer fixer = new KJASBrokenClassFixer(); if (fixer.process(b, off, len)) { Main.debug(name + " fixed"); } else { Main.info(name + " could not be fixed"); } return defineClass(name, fixer.getProcessedData(), fixer.getProcessedDataOffset(), fixer.getProcessedDataLength(), cs); } }