package org.nutz.dao.impl.ext;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import javax.sql.DataSource;
import org.nutz.aop.ClassAgent;
import org.nutz.aop.DefaultClassDefiner;
import org.nutz.aop.InterceptorChain;
import org.nutz.aop.MethodInterceptor;
import org.nutz.aop.asm.AsmClassAgent;
import org.nutz.aop.matcher.MethodMatcherFactory;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.entity.LinkField;
import org.nutz.dao.impl.EntityHolder;
import org.nutz.dao.impl.entity.AnnotationEntityMaker;
import org.nutz.dao.impl.entity.NutEntity;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.ioc.aop.config.InterceptorPair;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;
import org.nutz.lang.born.BornContext;
import org.nutz.lang.born.Borns;
import org.nutz.log.Log;
import org.nutz.log.Logs;
/**
* 支持简单的懒加载机制的AnnotationEntityMaker
*
* @author wendal(wendal1985@gmail.com)
*
*/
public class LazyAnnotationEntityMaker extends AnnotationEntityMaker {
private static final Log log = Logs.get();
private Dao dao;
public LazyAnnotationEntityMaker(DataSource datasource,
JdbcExpert expert,
EntityHolder holder,
Dao dao) {
super(datasource, expert, holder);
this.dao = dao;
}
protected <T> NutEntity<T> _createNutEntity(Class<T> type) {
return new LazyNutEntity<T>(type);
}
@Override
public <T> Entity<T> make(Class<T> type) {
LazyNutEntity<T> en = (LazyNutEntity<T>) super.make(type);
en.init();
return en;
}
class LazyNutEntity<T> extends NutEntity<T> {
public LazyNutEntity(Class<T> type) {
super(type);
}
@SuppressWarnings({"rawtypes", "unchecked"})
public void init() {
List<LinkField> lfs = new ArrayList<LinkField>();
lfs.addAll(ones.getAll());
lfs.addAll(manys.getAll());
lfs.addAll(manymanys.getAll());
if (lfs.isEmpty())
return;
if (log.isDebugEnabled())
log.debug("Found links , enable lazy!! -->" + type);
Mirror<T> mirror = Mirror.me(type);
List<InterceptorPair> interceptorPairs = new ArrayList<InterceptorPair>();
// 准备拦截器
for (LinkField lf : lfs) {
String fieldName = lf.getName();
try {
Method setter = mirror.getSetter(mirror.getField(fieldName));
LazyMethodInterceptor lmi = new LazyMethodInterceptor(setter,
fieldName);
interceptorPairs.add(new InterceptorPair(lmi,
MethodMatcherFactory.matcher("^(get|set)"
+ Strings.upperFirst(fieldName)
+ "$")));
}
catch (Throwable e) {
if (log.isWarnEnabled())
log.warn("Not setter found for LazyLoading ?!", e);
}
}
// 生成Aop化的类
ClassAgent agent = new AsmClassAgent();
for (InterceptorPair interceptorPair : interceptorPairs)
agent.addInterceptor(interceptorPair.getMethodMatcher(),
interceptorPair.getMethodInterceptor());
Class lazyClass = agent.define(DefaultClassDefiner.defaultOne(), type);
// 检查对象的创建方法
BornContext<T> bc = Borns.evalByArgTypes(type, ResultSet.class);
if (null == bc)
this.bornByDefault = Mirror.me(lazyClass)
.getBorningByArgTypes();
else
this.bornByRS = bc.getBorning();
}
}
class LazyMethodInterceptor implements MethodInterceptor {
private WeakHashMap<Object, LazyStatus> status = new WeakHashMap<Object, LazyAnnotationEntityMaker.LazyStatus>();
private Method setter;
private String fieldName;
public LazyMethodInterceptor(Method setter, String fieldName) {
this.setter = setter;
this.fieldName = fieldName;
}
public void filter(InterceptorChain chain) throws Throwable {
LazyStatus stat = status.get(chain.getCallingObj());
if (stat == null) {
if (!chain.getCallingMethod().equals(setter)) {
dao.fetchLinks(chain.getCallingObj(), fieldName);// 这里会触发setter被调用
}
status.put(chain.getCallingObj(), LazyStatus.NO_NEED); // 如果setter被调用,那么也就不再需要懒加载了
}
chain.doChain();
}
}
enum LazyStatus {
CAN_FETCH, FETCHED, NO_NEED
}
}