📄 launchclassloader.java
字号:
package de.fhm.jkf.launch.cl;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.List;
import java.util.zip.InflaterInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import de.fhm.jkf.launch.clsv.ArchiveInfo;
import de.fhm.jkf.launch.clsv.LaunchLogger;
import de.fhm.jkf.launch.clsv.LaunchParameter;
/**
* <br><br><center><table border="1" width="80%"><hr>
* <strong><a href="http://jkf.sourceforge.net">The JKF Project</a></strong>
* <p>
* Copyright (C) 2002 by Theodor Willax
* <p>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* <p>
* This library 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
* Lesser General Public License for more details.
* <p>
* You should have received a copy of the <a href="http://www.gnu.org/copyleft/lesser.html">
* GNU Lesser General Public License</a> along with this library; if not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
* <hr></table></center>
*
* The <code>ClassLoader</code> every jkf_launcher based application starts with.
* The <code>LaunchClassLoader</code> is responsible for providing the necessary
* archives respective classes to run the application. His strategy is do get at startup
* a list of known classes and archives from the server and uses this information for
* retrieving the class bytes from the right archive. It stores archives in the local
* <code>Cache</code>, so future startups are faster.
* <br>
* Archives are only downloaded, if needed (lazy downloading).
*
* @author Theodor Willax
*/
public class LaunchClassLoader extends ClassLoader implements Runnable {
/** The <code>Cache</code> where local archives are stored. */
private Cache cache = null;
/** <code>URL</code> where to get archives from. */
private URL servletURL = null;
/**
* This <code>List</code> is read from the server
* at construction time. It contains all archives
* and containing classes of the archives.
*/
private List archiveInfo = null;
/**
* Creates an new class loader, initializes the <code>Cache</code> and
* the configuration for the jkf framework.
*
* @param appName The name of the application this class loader is for.
* @param url The url the archives for this application can be loaded from.
*
* @exception IOException if no cache could be created.
* @exception MalformedURLException if the url to the server is incorrect.
* @exception ClassNotFoundException if the class the archiveInfo is sent
* with is not found (should never happen).
*/
public LaunchClassLoader(String appName, String url, ClassLoader parent)
throws MalformedURLException, IOException, ClassNotFoundException {
super(parent);
servletURL = new URL(url);
cache = new Cache(appName);
// @todo progress bar with completion status
URL u =
new URL(
servletURL.toExternalForm()
+ "?"
+ LaunchParameter.GET_ARCH_LIST
+ "=1");
ObjectInputStream in =
new ObjectInputStream(new InflaterInputStream(u.openStream()));
archiveInfo = (List) in.readObject();
in.close();
cache.init(archiveInfo);
loadConfiguration();
}
/**
* Starts the application. Reads the parameter <tt>mainClass</tt>
* from the <tt>application.properties</tt> file. This class is
* invoked in this <code>Thread</code>.
*/
public void run() {
TextResource tr = new TextResource();
String mainClassName = tr.getString("mainClass");
// Call main
try {
LaunchLogger.info("Try to load " + mainClassName);
Class main = loadClass(mainClassName);
// Close launch indicator
// if( launchIndicator != null )
// launchIndicator.close();
Method mainMain =
main.getMethod("main", new Class[] { String[].class });
// @todo: main arguments
mainMain.invoke(null, new Object[] { new String[] {
}
});
} catch (Exception e) {
new ErrorFrame(e).setVisible(true);
e.printStackTrace();
}
}
/**
* Searches the archive which contains the wanted class.
*
* @param className the class to search for
* @return String the archive name which contains the class,
* <code>null</code> otherwise.
*/
private String getArchiveForClass(String className) {
LaunchLogger.debug("searching archive for: " + className);
Iterator it = archiveInfo.iterator();
while (it.hasNext()) {
ArchiveInfo ai = (ArchiveInfo) it.next();
Iterator jt = ai.getClassList().iterator();
LaunchLogger.debug("archive: " + ai.getName());
while (jt.hasNext()) {
LaunchLogger.debug(jt.next().toString());
}
}
it = archiveInfo.iterator();
while (it.hasNext()) {
ArchiveInfo ai = (ArchiveInfo) it.next();
if (ai.getClassList().contains(className)) {
LaunchLogger.debug("found archive: " + ai.getName());
return ai.getName();
}
}
LaunchLogger.debug("did not found archive for: " + className);
return null;
}
/**
* This method is called if resources like images or text files
* are searched. Because we only use jar archives on the client,
* this method only returns jar urls pointing to the resources!
*
* @param name The wanted resource.
* @return URL JAR-URL pointing to the wanted resource.
*/
public URL findResource(String name) {
String arch = getArchiveForClass(name);
File file;
try {
file = cache.getFile(arch);
// a jar:-URL *could* change even between minor releases, but
// didn't between JVM's 1.1.6 and 1.3beta. Tested on JVM's from
// IBM, Blackdown, Microsoft, Sun @ Windows and Sun @ Solaris
System.err.println(file.getAbsolutePath());
ZipFile zf = new ZipFile(file.getAbsolutePath());
ZipEntry ze = zf.getEntry(name);
if (ze != null) {
try {
return new URL(
"jar:file:" + file.getAbsolutePath() + "!/" + name);
} catch (java.net.MalformedURLException badurl) {
badurl.printStackTrace();
return null;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return null;
}
/**
* Searches the <code>Class</code> with the specified name.
*
* @exception ClassNotFoundException if <code>Class</code> is
* not available in the classpath, <code>Cache</code> or on
* the server.
*/
public Class findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
/**
* Tries to load the <code>byte</code>S for the wanted
* class.
*
* @param name The class to load (complete specified with package path).
* @return the <code>byte</code>S which represent the class.
* @exception ClassNotFoundException if the wanted class cant
* be found.
*/
private byte[] loadClassData(String name) throws ClassNotFoundException {
// try to load the class data from the cache
ByteArray b = cache.getBytesForClass(name);
// or load archive from server
if (b == null) {
String arch = getArchiveForClass(name);
if (arch == null) {
throw new ClassNotFoundException(
"archive for class " + name + " not found");
}
try {
URL url =
new URL(
servletURL.toExternalForm()
+ "?"
+ LaunchParameter.GET_ARCHIVE
+ "="
+ arch);
URLConnection con = url.openConnection();
con.setDoInput(true);
con.setUseCaches(false);
InputStream in = con.getInputStream();
long size =
Long.parseLong(con.getHeaderField("archive-length"));
ArchiveLoader loader = new ArchiveLoader(in, size, arch);
loader.loadArchive();
cache.put(new Archive(arch, loader.getData()));
} catch (IOException e) {
LaunchLogger.error(
getClass().getName()
+ ".loadClassData(): "
+ e.getMessage());
e.printStackTrace();
throw new ClassNotFoundException(
"class " + name + " could not be loaded");
}
// retry to get the bytes
b = cache.getBytesForClass(name);
}
return b.getBytes();
}
/**
* Loads the configuration file from the server. Sets the
* system property <code>jkf.client.config.path</code>, which
* is necessery to start the jkf client framework. It points
* to the directory, where the configuration files where
* extraced to.
*/
private void loadConfiguration()
throws MalformedURLException, IOException {
URL u =
new URL(
servletURL.toExternalForm()
+ "?"
+ LaunchParameter.GET_CONFIG_FILES
+ "=1");
InputStream in = u.openStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len;
byte[] buf = new byte[4096];
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
cache.putConfiguration(
new Archive("jkf-client-configuration-archive", out.toByteArray()));
out.close();
System.setProperty("jkf.client.config.path", cache.getCacheDir());
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -