package com.coding2017.jvm.loader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.coding2017.jvm.clz.ClassFile;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
public class ClassFileLoader {
private static Joiner SEMICOLON_JOINER = Joiner.on(";").skipNulls();
private static Splitter DOT_SPLITTER = Splitter.on(".").trimResults();
private static Joiner SLASH_JOINER = Joiner.on("/").skipNulls();
private static String CLASS_SUFFIX = ".class";
private List<String> clzPaths = new ArrayList<String>();
public byte[] readBinaryCode(String className) {
List<String> list = DOT_SPLITTER.splitToList(className);
String childDirectory = SLASH_JOINER.join(list);
for (String clzPath : clzPaths) {
String fullPath = makeFullPath(clzPath, childDirectory);
if (fileExist(fullPath)) {
return readFileBytes(fullPath);
}
}
System.out.println("no this class file: " + className);
return null;
}
private byte[] readFileBytes(String filePath) {
try {
File file = new File(filePath);
long length = file.length();
byte[] fileBytes = new byte[(int) length];
int readLength = new FileInputStream(filePath).read(fileBytes);
if (readLength != length) {
System.out.println("read file error. read length: " + readLength + ", full length : " + length);
return null;
}
return fileBytes;
} catch (IOException e) {
System.out.println("read file error. " + filePath);
return null;
}
}
private boolean fileExist(String fullPath) {
File classFile = new File(fullPath);
return classFile.exists() && classFile.isFile();
}
private String makeFullPath(String clzPath, String childDirectory) {
if (clzPath.endsWith("/") || clzPath.endsWith("\\")) {
return clzPath + childDirectory + CLASS_SUFFIX;
} else {
return clzPath + "/" + childDirectory + CLASS_SUFFIX;
}
}
public void addClassPath(String path) {
if (!clzPaths.contains(path)) {
clzPaths.add(path);
}
}
public String getClassPath() {
return SEMICOLON_JOINER.join(clzPaths);
}
public ClassFile loadClass(String className) {
byte[] codes = this.readBinaryCode(className);
ClassFileParser parser = new ClassFileParser();
return parser.parse(codes);
}
}