package org.nutz.ioc.aop;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.nutz.aop.MethodInterceptor;
import org.nutz.aop.matcher.SimpleMethodMatcher;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.IocException;
import org.nutz.ioc.IocLoader;
import org.nutz.ioc.IocLoading;
import org.nutz.ioc.Iocs;
import org.nutz.ioc.ObjectLoadException;
import org.nutz.ioc.aop.config.AopConfigration;
import org.nutz.ioc.aop.config.InterceptorPair;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.ioc.meta.IocEventSet;
import org.nutz.ioc.meta.IocObject;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;
import org.nutz.lang.util.AbstractLifeCycle;
import org.nutz.log.Logs;
import org.nutz.log.Log;
/**
* 简化Aop扩展:
* <p/>
* <p>
* 1. 声明一个自定义注解
* <p/>
* <p>
* 2. 声明一个AopLoader类,继承本类,实现makeIt方法
* </p>
* <p>
* 3. 在@IocBy中引用即可该AopLoader类即可
* </p>
*
* @author wendal
*
* @param <T>
* 注解类,记得声明@Retention(RetentionPolicy.RUNTIME)哦
*/
public abstract class SimpleAopMaker<T extends Annotation> extends AbstractLifeCycle
implements IocLoader, AopConfigration {
private static final Log log = Logs.get();
protected Class<T> annoClass;
protected String iocName;
public String _name() {
return Strings.lowerFirst(_anno().getSimpleName());
}
public Class<T> _anno() {
return annoClass;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public SimpleAopMaker() {
annoClass = (Class<T>) (Class) Mirror.getTypeParam(getClass(), 0);
IocBean iocBean = getClass().getAnnotation(IocBean.class);
if (iocBean != null) {
if (Strings.isBlank(iocBean.name()))
iocName = Strings.lowerFirst(getClass().getSimpleName());
else
iocName = iocBean.name();
if (!iocName.startsWith("$aop_"))
// 如果声明了@IocBean,那么应该用@IocBean(name="$aop_xxx") 不然会有问题
throw new IocException(iocName,
getClass().getName()
+ " using @IocBean but not start with @IocBean(name=\"$aop_xxx\")");
}
if (log.isDebugEnabled())
log.debugf("Load AopConfigure for anno=%s by type=%s",
annoClass.getName(),
getClass().getName());
}
public abstract List<? extends MethodInterceptor> makeIt(T t, Method method, Ioc ioc);
public boolean checkMethod(Method method) {
int mod = method.getModifiers();
if (mod == 0
|| Modifier.isStatic(mod)
|| Modifier.isPrivate(mod)
|| Modifier.isFinal(mod)
|| Modifier.isAbstract(mod))
return false;
return true;
}
public boolean checkClass(Class<?> klass) {
return !(klass.isInterface()
|| klass.isArray()
|| klass.isEnum()
|| klass.isPrimitive()
|| klass.isMemberClass()
|| klass.isAnnotation()
|| klass.isAnonymousClass());
}
@Override
public List<InterceptorPair> getInterceptorPairList(Ioc ioc, Class<?> klass) {
if (!checkClass(klass))
return null;
List<InterceptorPair> list = new ArrayList<InterceptorPair>();
for (Method method : klass.getDeclaredMethods()) {
if (!checkMethod(method))
continue;
T t = method.getAnnotation(_anno());
if (t != null) {
List<? extends MethodInterceptor> _list = makeIt(t, method, ioc);
if (_list != null) {
for (MethodInterceptor mi : _list) {
list.add(new InterceptorPair(mi, new SimpleMethodMatcher(method)));
}
}
}
}
if (list.isEmpty())
return null;
return list;
}
public String[] getName() {
if (iocName != null)
return new String[]{iocName};
return new String[]{"$aop_" + _name()};
}
public IocObject load(IocLoading loading, String name) throws ObjectLoadException {
IocObject iobj = Iocs.wrap(this);
iobj.setType(getClass());
IocEventSet events = new IocEventSet();
events.setDepose("depose");
events.setCreate("init");
events.setFetch("fetch");
iobj.setEvents(events);
return iobj;
}
public boolean has(String name) {
if (iocName != null)
return iocName.equals(name);
return ("$aop_" + _name()).equals(name);
}
}