package com.openkm.util.cl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BinaryClassLoader extends ClassLoader implements MultipleClassLoader {
private static Logger log = LoggerFactory.getLogger(BinaryClassLoader.class);
private Hashtable<String, Class<?>> classes = new Hashtable<String, Class<?>>();
private Hashtable<String, byte[]> resources = new Hashtable<String, byte[]>();
private String mainClassName = null;
public BinaryClassLoader(byte[] buf) throws IOException {
super();
createCache(buf);
}
public BinaryClassLoader(byte[] buf, ClassLoader parent) throws IOException {
super(parent);
createCache(buf);
}
/**
* Create internal classes and resources cache
*/
private void createCache(byte[] buf) throws IOException {
ByteArrayInputStream bais = null;
JarInputStream jis = null;
byte[] buffer = new byte[1024 * 4];
try {
bais = new ByteArrayInputStream(buf);
jis = new JarInputStream(bais);
Attributes attr = jis.getManifest().getMainAttributes();
mainClassName = attr != null ? attr.getValue(Attributes.Name.MAIN_CLASS) : null;
for (JarEntry entry = null; (entry = jis.getNextJarEntry()) != null; ) {
String name = entry.getName();
if (!entry.isDirectory()) {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
for (int n = 0; -1 != (n = jis.read(buffer)); ) {
byteStream.write(buffer, 0, n);
}
if (name.endsWith(".class")) {
String className = name.substring(0, name.indexOf('.')).replace('/', '.');
resources.put(className, byteStream.toByteArray());
} else {
resources.put(name, byteStream.toByteArray());
}
byteStream.close();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(jis);
IOUtils.closeQuietly(bais);
}
}
/**
* Get main class name
*/
@Override
public String getMainClassName() throws IOException {
log.debug("getMainClassName()");
return mainClassName;
}
/**
* Find class
*/
@Override
public Class<?> findClass(String className) {
log.debug("findClass({})", className);
Class<?> ret = classes.get(className);
if (ret != null) {
return ret;
}
// Check for system class
try {
return findSystemClass(className);
} catch (ClassNotFoundException e) {
// Ignore
}
byte[] classByte = resources.get(className);
if (classByte != null) {
ret = defineClass(className, classByte, 0, classByte.length, null);
classes.put(className, ret);
resources.remove(className);
return ret;
}
return null;
}
/**
* Get resource input stream
*/
@Override
public InputStream getResourceAsStream(String name) {
log.debug("getResourceAsStream({})", name);
byte[] bytes = resources.get(name);
if (bytes != null) {
return new ByteArrayInputStream(bytes);
}
return null;
}
}