/**
* Copyright (c) Lambda Innovation, 2013-2015
* 本作品版权由Lambda Innovation所有。
* http://www.li-dev.cn/
*
* This project is open-source, and it is distributed under
* the terms of GNU General Public License. You can modify
* and distribute freely as long as you follow the license.
* 本项目是一个开源项目,且遵循GNU通用公共授权协议。
* 在遵照该协议的情况下,您可以自由传播和修改。
* http://www.gnu.org/licenses/gpl.html
*/
package cn.annoreg.core;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import cn.annoreg.ARModContainer;
import cn.annoreg.base.RegistrationEmpty;
import cn.annoreg.mc.BlockRegistration;
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData;
public class RegistrationManager {
public static final RegistrationManager INSTANCE = new RegistrationManager();
private Set<String> unloadedClass = new HashSet();
private Set<Class<?>> loadedClass = new HashSet();
private Set<ASMData> unloadedRegType;
private Map<Class<? extends Annotation>, RegistryType> regByClass = new HashMap();
private Map<String, RegistryType> regByName = new HashMap();
private Map<String, RegModInformation> modMap = new HashMap();
private Set<RegModInformation> mods = new HashSet();
private Map<String, List<String>> innerClassList = new HashMap();
public void annotationList(Set<ASMData> data) {
for (ASMData asm : data) {
unloadedClass.add(asm.getClassName());
}
}
private void loadClasses() {
loadRegistryTypes();
for (String name : unloadedClass) {
try {
prepareClass(Class.forName(name));
} catch (Exception e) {
ARModContainer.log.warn("Can not load class {}, maybe a SideOnly class.", name);
//TODO check whether it's really caused by sideonly
} catch (Throwable e) {
ARModContainer.log.fatal("Error on loading class {}. Please check the implementation.", name);
e.printStackTrace();
}
}
unloadedClass.clear();
}
private void prepareClass(Class<?> clazz) {
//First check loadedClass to avoid infinite recursion (when extending the enclosing class).
if (loadedClass.contains(clazz)) {
return;
}
loadedClass.add(clazz);
//Class annotations
for (Annotation anno : clazz.getAnnotations()) {
Class<? extends Annotation> annoclazz = anno.annotationType();
if (regByClass.containsKey(annoclazz)) {
regByClass.get(annoclazz).visitClass(clazz);
}
}
//Field annotations
for (Field field : clazz.getDeclaredFields()) {
for (Annotation anno : field.getAnnotations()) {
Class<? extends Annotation> annoclazz = anno.annotationType();
if (regByClass.containsKey(annoclazz)) {
regByClass.get(annoclazz).visitField(field);
}
}
}
//Inner classes
if (innerClassList.containsKey(clazz.getName())) {
for (String inner : innerClassList.get(clazz.getName())) {
try {
prepareClass(Class.forName(inner));
} catch (Exception e) {
ARModContainer.log.warn("Can not load class {}, maybe a SideOnly class.", inner);
} catch (Throwable e) {
ARModContainer.log.fatal("Error on loading class {}. Please check the implementation.", inner);
e.printStackTrace();
}
}
}
}
RegModInformation findMod(AnnotationData data) {
for (RegModInformation mod : mods) {
Class<?> clazz = data.type == AnnotationData.Type.CLASS ?
data.getTheClass() : data.getTheField().getDeclaringClass();
if (clazz.getCanonicalName().startsWith(mod.getPackage())) {
data.mod = mod;
return mod;
}
}
return null;
}
public void addRegType(RegistryType type) {
if (type.annoClass == null) {
if (regByName.containsKey(type.name)) {
ARModContainer.log.error("Unable to add the registry type {}.", type.name);
Thread.dumpStack();
return;
}
regByName.put(type.name, type);
} else {
if (regByClass.containsKey(type.annoClass) ||
regByName.containsKey(type.name)) {
ARModContainer.log.error("Unable to add the registry type {}.", type.name);
Thread.dumpStack();
return;
}
regByClass.put(type.annoClass, type);
regByName.put(type.name, type);
}
}
private RegModInformation createModFromObj(String modClassName) {
if (modMap.containsKey(modClassName)) {
return modMap.get(modClassName);
}
RegModInformation ret = new RegModInformation(modClassName);
modMap.put(modClassName, ret);
return ret;
}
public void addAnnotationMod(Set<ASMData> data) {
for (ASMData asm : data) {
mods.add(createModFromObj(asm.getClassName()));
}
}
private void registerAll(RegModInformation mod, String type) {
//First load all classes that have not been loaded.
loadClasses();
RegistryType rt = regByName.get(type);
if (rt == null) {
ARModContainer.log.error("RegistryType {} not found.", type);
//TODO side only type go here.
return;
}
rt.registerAll(mod);
}
public void registerAll(Object mod, String type) {
registerAll(createModFromObj(mod.getClass().getName()), type);
}
public void addRegistryTypes(Set<ASMData> data) {
unloadedRegType = data;
}
private void loadRegistryTypes() {
for (ASMData asm : unloadedRegType) {
try {
Class<?> clazz = Class.forName(asm.getClassName());
RegistryType rt = (RegistryType) clazz.newInstance();
addRegType(rt);
} catch (Exception e) {
ARModContainer.log.warn("No registry type {}. Might be a SideOnly regtype.", asm.getClassName()); //TODO side only type will go here
//e.printStackTrace();
}
}
unloadedRegType.clear();
}
public void addSideOnlyRegAnnotation(Set<ASMData> data) {
for (ASMData asm : data) {
try {
Class<?> clazz = Class.forName(asm.getClassName());
} catch (Exception e) {
ARModContainer.log.error("Error on adding registry annotation {}.", asm.getClassName());
}
}
}
public void checkLoadState() {
for (RegistryType rt : regByName.values()) {
rt.checkLoadState();
}
}
public Set<RegModInformation> getMods() {
return mods;
}
public void addDependencyFor(String type, String dep) {
regByName.get(type).addDependency(dep);
}
public void addInnerClassList(String outer, List<String> inner) {
if (innerClassList.containsKey(outer)) {
innerClassList.get(outer).addAll(inner);
} else {
innerClassList.put(outer, inner);
}
}
static {
for (LoadStage ls : LoadStage.values()) {
INSTANCE.addRegType(new RegistrationEmpty(ls.name));
}
}
}