xapi.bytecode.ClassPoolTail Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xapi-dev Show documentation
Show all versions of xapi-dev Show documentation
Everything needed to run a comprehensive dev environment.
Just type X_ and pick a service from autocomplete;
new dev modules will be added as they are built.
The only dev service not included in the uber jar is xapi-dev-maven,
as it includes all runtime dependencies of maven, adding ~4 seconds to build time,
and 6 megabytes to the final output jar size (without xapi-dev-maven, it's ~1MB).
The newest version!
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* MODIFIED BY James Nelson of We The Internet, 2013.
* Repackaged to avoid conflicts with different versions of Javassist,
* and modified Javassist APIs to make them more accessible to outside code.
*/
package xapi.bytecode;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Hashtable;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
final class ClassPathList {
ClassPathList next;
ClassPath path;
ClassPathList(ClassPath p, ClassPathList n) {
next = n;
path = p;
}
}
final class DirClassPath implements ClassPath {
String directory;
DirClassPath(String dirName) {
directory = dirName;
}
@Override
public InputStream openClassfile(String classname) {
try {
char sep = File.separatorChar;
String filename = directory + sep
+ classname.replace('.', sep) + ".class";
return new FileInputStream(filename.toString());
}
catch (FileNotFoundException e) {}
catch (SecurityException e) {}
return null;
}
@Override
public URL find(String classname) {
char sep = File.separatorChar;
String filename = directory + sep
+ classname.replace('.', sep) + ".class";
File f = new File(filename);
if (f.exists()) {
try {
return f.getCanonicalFile().toURI().toURL();
}
catch (MalformedURLException e) {}
catch (IOException e) {}
}
return null;
}
@Override
public void close() {}
@Override
public String toString() {
return directory;
}
}
final class JarDirClassPath implements ClassPath {
JarClassPath[] jars;
JarDirClassPath(String dirName) throws NotFoundException {
File[] files = new File(dirName).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
name = name.toLowerCase();
return name.endsWith(".jar") || name.endsWith(".zip");
}
});
if (files != null) {
jars = new JarClassPath[files.length];
for (int i = 0; i < files.length; i++) {
jars[i] = new JarClassPath(files[i].getPath());
}
}
}
@Override
public InputStream openClassfile(String classname) throws NotFoundException {
if (jars != null) {
for (int i = 0; i < jars.length; i++) {
InputStream is = jars[i].openClassfile(classname);
if (is != null) {
return is;
}
}
}
return null; // not found
}
@Override
public URL find(String classname) {
if (jars != null) {
for (int i = 0; i < jars.length; i++) {
URL url = jars[i].find(classname);
if (url != null) {
return url;
}
}
}
return null; // not found
}
@Override
public void close() {
if (jars != null) {
for (int i = 0; i < jars.length; i++) {
jars[i].close();
}
}
}
}
final class JarClassPath implements ClassPath {
JarFile jarfile;
String jarfileURL;
JarClassPath(String pathname) throws NotFoundException {
try {
jarfile = new JarFile(pathname);
jarfileURL = new File(pathname).getCanonicalFile()
.toURI().toURL().toString();
return;
}
catch (IOException e) {}
throw new NotFoundException(pathname);
}
@Override
public InputStream openClassfile(String classname)
throws NotFoundException
{
try {
String jarname = classname.replace('.', '/') + ".class";
JarEntry je = jarfile.getJarEntry(jarname);
if (je != null) {
return jarfile.getInputStream(je);
}
else {
return null; // not found
}
}
catch (IOException e) {}
throw new NotFoundException("broken jar file?: "
+ jarfile.getName());
}
@Override
public URL find(String classname) {
String jarname = classname.replace('.', '/') + ".class";
JarEntry je = jarfile.getJarEntry(jarname);
if (je != null) {
try {
return new URL("jar:" + jarfileURL + "!/" + jarname);
}
catch (MalformedURLException e) {}
}
return null; // not found
}
@Override
public void close() {
try {
jarfile.close();
jarfile = null;
}
catch (IOException e) {}
}
@Override
public String toString() {
return jarfile == null ? "" : jarfile.toString();
}
}
final class ClassPoolTail {
protected ClassPathList pathList;
private Hashtable packages; // should be synchronized.
public ClassPoolTail() {
pathList = null;
packages = new Hashtable();
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
buf.append("[class path: ");
ClassPathList list = pathList;
while (list != null) {
buf.append(list.path.toString());
buf.append(File.pathSeparatorChar);
list = list.next;
}
buf.append(']');
return buf.toString();
}
public synchronized ClassPath insertClassPath(ClassPath cp) {
pathList = new ClassPathList(cp, pathList);
return cp;
}
public synchronized ClassPath appendClassPath(ClassPath cp) {
ClassPathList tail = new ClassPathList(cp, null);
ClassPathList list = pathList;
if (list == null) {
pathList = tail;
} else {
while (list.next != null) {
list = list.next;
}
list.next = tail;
}
return cp;
}
public synchronized void removeClassPath(ClassPath cp) {
ClassPathList list = pathList;
if (list != null) {
if (list.path == cp) {
pathList = list.next;
} else {
while (list.next != null) {
if (list.next.path == cp) {
list.next = list.next.next;
} else {
list = list.next;
}
}
}
}
cp.close();
}
public ClassPath appendSystemPath() {
return appendClassPath(new ClassClassPath());
}
public ClassPath insertClassPath(String pathname)
throws NotFoundException
{
return insertClassPath(makePathObject(pathname));
}
public ClassPath appendClassPath(String pathname)
throws NotFoundException
{
return appendClassPath(makePathObject(pathname));
}
private static ClassPath makePathObject(String pathname)
throws NotFoundException
{
String lower = pathname.toLowerCase();
if (lower.endsWith(".jar") || lower.endsWith(".zip")) {
return new JarClassPath(pathname);
}
int len = pathname.length();
if (len > 2 && pathname.charAt(len - 1) == '*'
&& (pathname.charAt(len - 2) == '/'
|| pathname.charAt(len - 2) == File.separatorChar)) {
String dir = pathname.substring(0, len - 2);
return new JarDirClassPath(dir);
}
return new DirClassPath(pathname);
}
/**
* You can record "System" so that java.lang.System can be quickly
* found although "System" is not a package name.
*/
public void recordInvalidClassName(String name) {
packages.put(name, name);
}
/**
* This method does not close the output stream.
*/
void writeClassfile(String classname, OutputStream out)
throws NotFoundException, IOException
{
InputStream fin = openClassfile(classname);
if (fin == null) {
throw new NotFoundException(classname);
}
try {
copyStream(fin, out);
}
finally {
fin.close();
}
}
/*
-- faster version --
void checkClassName(String classname) throws NotFoundException {
if (find(classname) == null)
throw new NotFoundException(classname);
}
-- slower version --
void checkClassName(String classname) throws NotFoundException {
InputStream fin = openClassfile(classname);
try {
fin.close();
}
catch (IOException e) {}
}
*/
/**
* Opens the class file for the class specified by
* classname
.
*
* @param classname a fully-qualified class name
* @return null if the file has not been found.
* @throws NotFoundException if any error is reported by ClassPath.
*/
InputStream openClassfile(String classname)
throws NotFoundException
{
if (packages.get(classname) != null)
{
return null; // not found
}
ClassPathList list = pathList;
InputStream ins = null;
NotFoundException error = null;
while (list != null) {
try {
ins = list.path.openClassfile(classname);
}
catch (NotFoundException e) {
if (error == null) {
error = e;
}
}
if (ins == null) {
list = list.next;
} else {
return ins;
}
}
if (error != null) {
throw error;
}
else {
return null; // not found
}
}
/**
* Searches the class path to obtain the URL of the class file
* specified by classname. It is also used to determine whether
* the class file exists.
*
* @param classname a fully-qualified class name.
* @return null if the class file could not be found.
*/
public URL find(String classname) {
if (packages.get(classname) != null) {
return null;
}
ClassPathList list = pathList;
URL url = null;
while (list != null) {
url = list.path.find(classname);
if (url == null) {
list = list.next;
} else {
return url;
}
}
return null;
}
/**
* Reads from an input stream until it reaches the end.
*
* @return the contents of that input stream
*/
public static byte[] readStream(InputStream fin) throws IOException {
byte[][] bufs = new byte[10][];
int bufsize = 4096;
for (int i = 0; i < 10; ++i) {
bufs[i] = new byte[bufsize];
int size = 0;
int len = 0;
do {
len = fin.read(bufs[i], size, bufsize - size);
if (len >= 0) {
size += len;
} else {
byte[] result = new byte[bufsize - 4096 + size];
int s = 0;
for (int j = 0; j < i; ++j) {
System.arraycopy(bufs[j], 0, result, s, s + 4096);
s = s + s + 4096;
}
System.arraycopy(bufs[i], 0, result, s, size);
return result;
}
} while (size < bufsize);
bufsize *= 2;
}
throw new IOException("too much data");
}
/**
* Reads from an input stream and write to an output stream
* until it reaches the end. This method does not close the
* streams.
*/
public static void copyStream(InputStream fin, OutputStream fout)
throws IOException
{
int bufsize = 4096;
for (int i = 0; i < 8; ++i) {
byte[] buf = new byte[bufsize];
int size = 0;
int len = 0;
do {
len = fin.read(buf, size, bufsize - size);
if (len >= 0) {
size += len;
} else {
fout.write(buf, 0, size);
return;
}
} while (size < bufsize);
fout.write(buf);
bufsize *= 2;
}
throw new IOException("too much data");
}
}