package openmods.source;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.API;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.discovery.ASMDataTable;
import cpw.mods.fml.common.discovery.ModCandidate;
import java.io.File;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import openmods.Log;
public class ClassSourceCollector {
public static class ApiInfo {
public final String api;
public final String owner;
public final String version;
public ApiInfo(Map<String, Object> data) {
this.api = (String)data.get("provides");
this.owner = (String)data.get("owner");
this.version = (String)data.get("apiVersion");
}
public ApiInfo(API api) {
this.api = api.provides();
this.owner = api.owner();
this.version = api.apiVersion();
}
}
public static class ClassMeta {
public final Class<?> cls;
public final URL loadedSource;
public final ApiInfo api;
public final Map<File, Set<String>> providerMods;
public ClassMeta(Class<?> cls, URL loadedSource, ApiInfo api, Map<File, Set<String>> providerMods) {
this.cls = cls;
this.loadedSource = loadedSource;
this.api = api;
this.providerMods = ImmutableMap.copyOf(providerMods);
}
public String source() {
return loadedSource != null? loadedSource.toString() : "?";
}
}
private final ASMDataTable table;
public ClassSourceCollector(ASMDataTable table) {
this.table = table;
}
public ClassMeta getClassInfo(String clsName) throws ClassNotFoundException {
try {
Class<?> cls = Class.forName(clsName);
return getClassInfo(cls);
} catch (ClassNotFoundException e) {
throw e;
} catch (Throwable t) {
throw Throwables.propagate(t);
}
}
public ClassMeta getClassInfo(Class<?> cls) {
final Package pkg = cls.getPackage();
URL loadedFrom = null;
try {
loadedFrom = cls.getProtectionDomain().getCodeSource().getLocation();
} catch (Throwable t) {
Log.warn(t, "Failed to get source for %s", cls);
}
final API apiAnnotation = pkg.getAnnotation(API.class);
final ApiInfo apiInfo = apiAnnotation != null? new ApiInfo(apiAnnotation) : null;
Map<File, Set<String>> mods = Maps.newHashMap();
for (ModCandidate candidate : table.getCandidatesFor(pkg.getName())) {
if (!candidate.getClassList().contains(cls.getName().replace('.', '/'))) continue;
final File candidateFile = candidate.getModContainer();
Set<String> modIds = Sets.newHashSet();
mods.put(candidateFile, modIds);
for (ModContainer mod : candidate.getContainedMods())
modIds.add(mod.getModId());
}
return new ClassMeta(cls, loadedFrom, apiInfo, mods);
}
}