|
What this is
Other links
The source code
/*
* JARClassLoader.java - Loads classes from JAR files
* Copyright (C) 1999 Slava Pestov
* Portions copyright (C) 1999 mike dillon, (C) 2000 Romain Guy
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.jext;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
import javax.swing.JOptionPane;
import java.lang.reflect.Modifier;
/**
* A class loader implementation that loads classes from JAR files.
* @author Slava Pestov
*/
public class JARClassLoader extends ClassLoader
{
public static ArrayList pluginsNames = new ArrayList();
//public static ArrayList pluginsRealNames = new ArrayList();
/* This is the prefix for entries inside .jar's containing only translations.
* I.e., .xml files for translations must be inside trans/<languagecode>/
* folder. Note that any file which name starts with "trans" will be ignored.
* The prefix here was "trans" + File.separator, but entries were always read
* with forward slashes(I don't know why, it's a characteristic of ZIP file,
* it seems)*/
private static final String langsPrefix = "trans";
public JARClassLoader(String path) throws IOException
{
this(path, true, null);
}
//Now I've added the parameter isPlugin(which defaults to true) to use the code
//for the plugin downloader, which hot-loads a JAR.
public JARClassLoader(String path, boolean isPlugin, ClassLoader parent) throws IOException
{
super(parent);
url = new File(path).toURL();
zipFile = new ZipFile(path);
if (isPlugin)
{
String langSearchPrefix = langsPrefix + File.separator + Jext.getLanguage() + File.separator;
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements())
{
ZipEntry entry = (ZipEntry) entries.nextElement();
String name = entry.getName();
String lowName = name.toLowerCase();
//the files in trans/* dirs must be loaded only as translations;
//this loop over entries elements must not iterate over them.
if (lowName.startsWith(langsPrefix))
continue;
if (lowName.endsWith(".props")) {
Jext.loadProps(zipFile.getInputStream(entry));//This could be removed(no plugin using it).
} else if (lowName.endsWith(".props.xml")) {
InputStream in;
//We load first the untranslated one, then the translated which contains
//only some properties!
in = zipFile.getInputStream(entry);
Jext.loadXMLProps(in, name, false); //not to translate.
//First search translation inside the plugin's jar
ZipEntry translEntry = zipFile.getEntry(langSearchPrefix + name);
if (translEntry != null)
in = zipFile.getInputStream(translEntry);
else
//fall back to old search method.
in = Jext.getLanguageStream(zipFile.getInputStream(entry), name);
Jext.loadXMLProps(in, name, false);//already translated.
} else if (lowName.endsWith(".actions.xml")) {
Jext.loadXMLActions(zipFile.getInputStream(entry), name);
} else if (name.endsWith("Plugin.class")) {
pluginClasses.add(name);
pluginsNames.add(name);
//pluginsRealNames.add(baseName);
}
}
// If this is done before the above while() statement
// and an exception is thrown while the ZIP file is
// being loaded, weird things happen...
index = classLoaders.size();
classLoaders.add(this);
}
}
private static ArrayList disabledPlugins = new ArrayList();
public static void setEnabled(String name, boolean toEnable) {
/*int i = disabledPlugins.indexOf(name);
if (toEnable) {
if (i != -1)
disabledPlugins.remove(i);
} else {
if (i == -1)
disabledPlugins.add(name);
}*/
Jext.setProperty("plugin." + name + ".disabled", toEnable? "no" : "yes");
}
public static boolean isEnabled(String name) {
return ! ("yes".equals(Jext.getProperty("plugin." + name + ".disabled")));
//return disabledPlugins.indexOf(name) == -1;
}
/*private final static String DISABLED_LIST_PATH = Jext.SETTINGS_DIRECTORY +
".disabledPlugins";
static {
try {
File f = new File(DISABLED_LIST_PATH);
if (f.exists()) {
BufferedReader in = new BufferedReader(new FileReader(f));
String line;
while ( (line = in.readLine()) != null)
disabledPlugins.add(line);
in.close();
}
} catch (IOException ioe) {ioe.printStackTrace();}
}
static void saveDisabledList() {
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(DISABLED_LIST_PATH)));
for (Iterator i = disabledPlugins.iterator(); i.hasNext(); ) {
out.println((String) i.next());
}
out.close();
} catch (IOException ioe) {}
}*/
/**
* @exception ClassNotFoundException if the class could not be found
*/
public Class loadClass(String clazz, boolean resolveIt) throws ClassNotFoundException
{
return loadClassFromZip(clazz, resolveIt, true);
}
public InputStream getResourceAsStream(String name)
{
try
{
ZipEntry entry = zipFile.getEntry(name);
if (entry == null)
return getSystemResourceAsStream(name);
else
return zipFile.getInputStream(entry);
} catch (IOException io) {
return null;
}
}
public URL getResource(String name)
{
try
{
return new URL(getResourceAsPath(name));
} catch (MalformedURLException mu) {
return null;
}
}
public String getResourceAsPath(String name)
{
return "jextresource:" + index + "/" + name;
}
public String getPath()
{
return zipFile.getName();
}
public static void initPlugins()
{
for (int i = 0; i < classLoaders.size(); i++)
{
JARClassLoader classLoader = (JARClassLoader) classLoaders.get(i);
classLoader.loadAllPlugins();
}
}
public static JARClassLoader getClassLoader(int index)
{
return (JARClassLoader) classLoaders.get(index);
}
public static int getClassLoaderCount()
{
return classLoaders.size();
}
public static void reloadPluginsProperties() throws IOException
{
for (int i = 0; i < classLoaders.size(); i++) {
JARClassLoader classLoader = (JARClassLoader) classLoaders.get(i);
ZipFile zipFile = classLoader.getZipFile();
Enumeration entries = zipFile.entries();
String langSearchPrefix = langsPrefix + File.separator + Jext.getLanguage() + File.separator;
while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement();
String name = entry.getName();
String lowName = name.toLowerCase();
if (! lowName.startsWith(langsPrefix)) {//the files in trans/* dirs must be loaded only as translations;
//this loop over entries elements must not iterate over them.
if (lowName.endsWith(".props"))
Jext.loadProps(zipFile.getInputStream(entry));
else if (lowName.endsWith(".props.xml")) {
InputStream in;
//We load first the untranslated one, then the translated which contains
//only some properties!
in = zipFile.getInputStream(entry);
Jext.loadXMLProps(in, name, false); //not to translate.
//First search translation inside the plugin's jar
ZipEntry translEntry = zipFile.getEntry(langSearchPrefix + name);
if (translEntry != null)
in = zipFile.getInputStream(translEntry);
else
//fall back to old search method.
in = Jext.getLanguageStream(zipFile.getInputStream(entry), name);
Jext.loadXMLProps(in, name, false);//already translated.
}
}
}
}
}
public static void executeScripts(JextFrame parent)
{
for (int i = 0; i < classLoaders.size(); i++)
{
JARClassLoader classLoader = (JARClassLoader) classLoaders.get(i);
ZipFile zipFile = classLoader.getZipFile();
Enumeration entries = zipFile.entries();
while (entries.hasMoreElements())
{
ZipEntry entry = (ZipEntry) entries.nextElement();
String name = entry.getName().toLowerCase();
if (name.endsWith(".jext-script") || name.endsWith(".py"))
{
try
{
BufferedReader in = new BufferedReader(
new InputStreamReader(zipFile.getInputStream(entry)));
String line;
StringBuffer buf = new StringBuffer();
while ((line = in.readLine()) != null)
buf.append(line).append('\n');
if (name.endsWith(".jext-script"))
org.jext.scripting.dawn.Run.execute(buf.toString(), parent, false);
else
org.jext.scripting.python.Run.execute(buf.toString(), parent);
} catch (IOException ioe) { }
}
}
}
}
public ZipFile getZipFile()
{
return zipFile;
}
// private members
/*
* Loading of plugin classes is deferred until all JARs
* are loaded - this is necessary because a plugin might
* depend on classes stored in other JARs.
*/
private static ArrayList classLoaders = new ArrayList();
private int index;
private ArrayList pluginClasses = new ArrayList();
// replaced fileName attribute with URL as fileName was not used, and URL is now used for package sealing.
private URL url;
private ZipFile zipFile;
private void loadAllPlugins()
{
for (int i = 0; i < pluginClasses.size(); i++)
{
String name = (String) pluginClasses.get(i);
try
{
loadPluginClass(name);
} catch (Throwable t) {
String[] args = { name };
System.err.println(Jext.getProperty("jar.error.init", args));
t.printStackTrace();
}
}
}
private void loadPluginClass(String name) throws Exception
{
name = Utilities.fileToClass(name);
//if ("yes".equals(Jext.getProperty("plugin." + name + ".disabled")))
if (!isEnabled(name))
{
String[] args = { Jext.getProperty("plugin." + name + ".name") };
System.err.println(Jext.getProperty("jar.disabled", args));
return;
}
Plugin[] plugins = Jext.getPlugins();
for (int i = 0; i < plugins.length; i++)
{
if (plugins[i].getClass().getName().equals(name))
{
String[] args = { name };
System.err.println(Jext.getProperty("jar.error.duplicateName", args));
return;
}
}
// Check dependencies
if (!checkDependencies(name))
return;
Class clazz = loadClass(name, true);
int modifiers = clazz.getModifiers();
if (Plugin.class.isAssignableFrom(clazz) &&
!Modifier.isInterface(modifiers) &&
!Modifier.isAbstract(modifiers))
{
Plugin plugin = (Plugin) clazz.newInstance();
Jext.addPlugin(plugin);
int dot = name.lastIndexOf('.');
name = name.substring((dot == -1 ? 0 : dot + 1));
String[] args = { Jext.getProperty("plugin." + name + ".name") };
System.out.println(Jext.getProperty("jar.loaded", args));
}
}
private boolean checkDependencies(String name)
{
int i = 0;
StringBuffer deps = new StringBuffer();
boolean ok = true;
String dep;
while ((dep = Jext.getProperty("plugin." + name + ".depend." + i++)) != null)
{
int index = dep.indexOf(' ');
if (index == -1)
{
deps.append(dep);
deps.append('\n');
ok = false;
continue;
}
String what = dep.substring(0, index);
String arg = dep.substring(index + 1);
String[] args2 = new String[1];
if (what.equals("jext"))
args2[0] = Jext.BUILD; //Utilities.buildToVersion(arg);
else
args2[0] = arg;
deps.append(Jext.getProperty("jar.what." + what, args2));
deps.append('\n');
if (what.equals("jdk"))
{
if (System.getProperty("java.version").compareTo(arg) < 0)
ok = false;
} else if (what.equals("deprecateJDK")) {
if (System.getProperty("java.version").compareTo(arg) >= 0)
ok = false;
} else if (what.equals("jext")) {
if (Jext.BUILD.compareTo(arg) < 0)
ok = false;
} else if (what.equals("os")) {
ok = (System.getProperty("os.name").indexOf(arg) != -1);
} else if (what.equals("class")) {
try
{
loadClass(arg, false);
} catch (Exception e) {
ok = false;
}
} else
ok = false;
}
if (!ok && Jext.getProperty("plugin." + name + ".disabled") == null)
{
int dot = name.lastIndexOf('.');
name = name.substring((dot == -1 ? 0 : dot + 1));
String[] _args = { Jext.getProperty("plugin." + name + ".name"), deps.toString() };
int response = JOptionPane.showConfirmDialog(null,
Jext.getProperty("plugin.disable.question", _args),
Jext.getProperty("plugin.disable.title"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
//Jext.setProperty("plugin." + name + ".disabled", response == 0 ? "yes" : "no");
setEnabled(name, response == 0 ? false : true);
}
return ok;
}
private Class findOtherClass(String clazz, boolean resolveIt) throws ClassNotFoundException
{
for (int i = 0; i < classLoaders.size(); i++)
{
JARClassLoader loader = (JARClassLoader) classLoaders.get(i);
Class cls = loader.loadClassFromZip(clazz, resolveIt, false);
if (cls != null)
return cls;
}
/* Defer to whoever loaded us (such as JShell, Echidna, etc) */
ClassLoader loader = getClass().getClassLoader();
if (loader != null)
return loader.loadClass(clazz);
/* Doesn't exist in any other plugin, look in system classes */
return findSystemClass(clazz);
}
private Class loadClassFromZip(String clazz, boolean resolveIt,
boolean doDepencies) throws ClassNotFoundException
{
Class cls = findLoadedClass(clazz);
if (cls != null)
{
if (resolveIt)
resolveClass(cls);
return cls;
}
String name = Utilities.classToFile(clazz);
try
{
ZipEntry entry = zipFile.getEntry(name);
if (entry == null)
{
if (doDepencies)
return findOtherClass(clazz, resolveIt);
else
return null;
}
InputStream in = zipFile.getInputStream(entry);
int len = (int) entry.getSize();
byte[] data = new byte[len];
int success = 0;
int offset = 0;
while (success < len)
{
len -= success;
offset += success;
success = in.read(data, offset, len);
if (success == -1)
{
String[] args = { clazz, zipFile.getName()};
System.err.println(Jext.getProperty("jar.error.zip", args));
throw new ClassNotFoundException(clazz);
}
}
int dot = clazz.lastIndexOf('.');
String pkgName = (dot < 0) ? null : name.replace('/', '.').substring(0, dot);
if (pkgName != null && getPackage(pkgName) == null)
{
Package p = definePackage(pkgName, null, null, null, null, null, null, url);
}//end if there is a Package but it has not yet been defined
cls = defineClass(clazz, data, 0, data.length);
if (resolveIt)
resolveClass(cls);
return cls;
} catch (IOException io) {
throw new ClassNotFoundException(clazz);
}
}
}
// End of JARCLassLoader.java
|
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.