You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/tdehtml/java/org/kde/kjas/server/KJASAppletClassLoader.java

361 lines
12 KiB

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.
* <P>
* 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 <b>name</b>. If <b>name</b> 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);
}
}