package org.nutz.mvc.adaptor;

import java.io.InputStream;
import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.nutz.castor.Castors;
import org.nutz.ioc.Ioc;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.util.MethodParamNamesScaner;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.HttpAdaptor2;
import org.nutz.mvc.Scope;
import org.nutz.mvc.ViewModel;
import org.nutz.mvc.adaptor.injector.AllAttrInjector;
import org.nutz.mvc.adaptor.injector.AppAttrInjector;
import org.nutz.mvc.adaptor.injector.ArrayInjector;
import org.nutz.mvc.adaptor.injector.CookieInjector;
import org.nutz.mvc.adaptor.injector.HttpInputStreamInjector;
import org.nutz.mvc.adaptor.injector.HttpReaderInjector;
import org.nutz.mvc.adaptor.injector.IocInjector;
import org.nutz.mvc.adaptor.injector.IocObjInjector;
import org.nutz.mvc.adaptor.injector.NameInjector;
import org.nutz.mvc.adaptor.injector.PathArgInjector;
import org.nutz.mvc.adaptor.injector.ReqHeaderInjector;
import org.nutz.mvc.adaptor.injector.RequestAttrInjector;
import org.nutz.mvc.adaptor.injector.RequestInjector;
import org.nutz.mvc.adaptor.injector.ResponseInjector;
import org.nutz.mvc.adaptor.injector.ServletContextInjector;
import org.nutz.mvc.adaptor.injector.SessionAttrInjector;
import org.nutz.mvc.adaptor.injector.SessionInjector;
import org.nutz.mvc.adaptor.injector.ViewModelInjector;
import org.nutz.mvc.adaptor.injector.VoidInjector;
import org.nutz.mvc.annotation.Attr;
import org.nutz.mvc.annotation.Cookie;
import org.nutz.mvc.annotation.IocObj;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.annotation.ReqHeader;
import org.nutz.mvc.impl.AdaptorErrorContext;

/**
 *
 * @author zozoh(zozohtnt@gmail.com)
 * @author wendal(wendal1985@gmail.com)
 * @author juqkai(juqkai@gmail.com)
 * @author MingzFan(Mingz.Fan@gmail.com)
 */
public abstract class AbstractAdaptor implements HttpAdaptor2 {

    private static final Log log = Logs.get();

    protected ParamInjector[] injs;

    protected Method method;

    protected Class<?>[] argTypes;

    protected String[] defaultValues;

    protected String[] paramNames;

    protected int curIndex;

    protected int errCtxIndex;

    public void init(ActionInfo ai) {
        init(ai.getMethod(), ai.getParamNames());
    }

    public void init(Method method) {
        init(method, Lang.collection2array(MethodParamNamesScaner.getParamNames(method), String.class));
    }

    protected void init(Method method, String[] paramNames) {
        this.method = method;
        this.paramNames = paramNames;
        argTypes = method.getParameterTypes();
        injs = new ParamInjector[argTypes.length];
        defaultValues = new String[argTypes.length];
        errCtxIndex = -1;
        Annotation[][] annss = method.getParameterAnnotations();
        Type[] types = method.getGenericParameterTypes();
        for (int i = 0; i < annss.length; i++) {
            curIndex = i;

            // AdaptorErrorContext 类型的参数不需要生成注入器，记录下参数的下标就好了
            if (AdaptorErrorContext.class.isAssignableFrom(argTypes[i])) {
                // 多个 AdaptorErrorContext 类型的参数时，以第一个为准
                if (errCtxIndex == -1)
                    errCtxIndex = i;

                continue;
            }

            Annotation[] anns = annss[i];
            Param param = null;
            Attr attr = null;
            IocObj iocObj = null;
            ReqHeader reqHeader = null;
            Cookie cookie = null;

            // find @Param & @Attr & @IocObj in current annotations
            for (int x = 0; x < anns.length; x++)
                if (anns[x] instanceof Param) {
                    param = (Param) anns[x];
                    break;
                } else if (anns[x] instanceof Attr) {
                    attr = (Attr) anns[x];
                    break;
                } else if (anns[x] instanceof IocObj) {
                    iocObj = (IocObj) anns[x];
                    break;
                } else if (anns[x] instanceof ReqHeader) {
                    reqHeader = (ReqHeader) anns[x];
                    break;
                } else if (anns[x] instanceof Cookie) {
                    cookie = (Cookie) anns[x];
                }
            // If has @Attr
            if (null != attr) {
                injs[i] = evalInjectorByAttrScope(attr);
                continue;
            }

            // If has @IocObj
            if (null != iocObj) {
                injs[i] = new IocObjInjector(method.getParameterTypes()[i],
                        iocObj.value());
                continue;
            }

            if (null != reqHeader) {
                injs[i] = new ReqHeaderInjector(reqHeader.value(), argTypes[i]);
                continue;
            }
            if (null != cookie) {
                injs[i] = new CookieInjector(cookie.value(), argTypes[i]);
                continue;
            }

            // And eval as default suport types
            injs[i] = evalInjectorByParamType(argTypes[i]);
            if (null != injs[i])
                continue;
            // Eval by sub-classes
            injs[i] = evalInjector(types[i], param);
            // 子类也不能确定，如何适配这个参数，那么做一个标记，如果
            // 这个参数被 ParamInjector 适配到，就会抛错。
            // 这个设计是因为了 "路径参数"
            if (null == injs[i]) {
                injs[i] = paramNameInject(method, i);
            }
            if (param != null) {
            	String tmp = param.df();
            	if (tmp != null && !tmp.equals(Params.ParamDefaultTag))
            		defaultValues[i] = tmp;
            }
        }
    }

    private static ParamInjector evalInjectorByAttrScope(Attr attr) {
        if (attr.scope() == Scope.APP)
            return new AppAttrInjector(attr.value());
        if (attr.scope() == Scope.SESSION)
            return new SessionAttrInjector(attr.value());
        if (attr.scope() == Scope.REQUEST)
            return new RequestAttrInjector(attr.value());
        return new AllAttrInjector(attr.value());
    }

    private static ParamInjector evalInjectorByParamType(Class<?> type) {
        // Request
        if (ServletRequest.class.isAssignableFrom(type)) {
            return new RequestInjector();
        }
        // Response
        else if (ServletResponse.class.isAssignableFrom(type)) {
            return new ResponseInjector();
        }
        // Session
        else if (HttpSession.class.isAssignableFrom(type)) {
            return new SessionInjector();
        }
        // ServletContext
        else if (ServletContext.class.isAssignableFrom(type)) {
            return new ServletContextInjector();
        }
        // Ioc
        else if (Ioc.class.isAssignableFrom(type)) {
            return new IocInjector();
        }
        // InputStream
        else if (InputStream.class.isAssignableFrom(type)) {
            return new HttpInputStreamInjector();
        }
        // Reader
        else if (Reader.class.isAssignableFrom(type)) {
            return new HttpReaderInjector();
        }
        // ViewModel
        else if (ViewModel.class.isAssignableFrom(type))
            return new ViewModelInjector();
        return null;
    }

    protected ParamInjector evalInjector(Type type, Param param) {
        return evalInjectorBy(type, param);
    }

    /**
     * 子类实现这个方法根据自己具体的逻辑来生产一个参数注入器
     *
     * @param type
     *            参数类型
     * @param param
     *            参数的注解
     * @return 一个新的参数注入器实例
     */
    protected abstract ParamInjector evalInjectorBy(Type type, Param param);

    public Object[] adapt(ServletContext sc,
                          HttpServletRequest req,
                          HttpServletResponse resp,
                          String[] pathArgs) {

        Object[] args = new Object[argTypes.length];

        if (args.length != injs.length)
            throw new IllegalArgumentException("args.length != injs.length , You get a bug, pls report it!!");

        AdaptorErrorContext errCtx = null;
        // 也许用户有自己的AdaptorErrorContext实现哦
        if (errCtxIndex > -1)
            errCtx = (AdaptorErrorContext) Mirror.me(argTypes[errCtxIndex])
                    .born(argTypes.length);

        Object obj = req.getAttribute(ActionContext.REFER_OBJECT);
        try {
            if (obj == null) {
                obj = getReferObject(sc, req, resp, pathArgs);
                req.setAttribute(ActionContext.REFER_OBJECT, obj);
            }
        }
        catch (Throwable e) {
            if (errCtx != null) {
                if (log.isInfoEnabled())
                    log.info("Adapter Error catched , but I found AdaptorErrorContext param, so, set it to args, and continue", e);
                errCtx.setAdaptorError(e, this);
                for (int i = 0; i < args.length - 1; i++) {
                	if (args[i] == null) {
                    	if (defaultValues[i] != null) {
                    		args[i] = Castors.me().castTo(defaultValues[i], argTypes[i]);
                    	} else if (argTypes[i].isPrimitive()) {
                    		args[i] = Lang.getPrimitiveDefaultValue(argTypes[i]);
                    	}
                    }
				}
                args[args.length - 1] = errCtx;
                return args;
            }
            throw Lang.wrapThrow(e);
        }

        // 当前路径参数的索引
        int curPathArgIdx = 0;
        int len = null == pathArgs ? 0 : pathArgs.length;
        for (int i = 0; i < args.length; i++) {
            // 如果这个参数是 AdaptorErrorContext 类型的，就跳过
            if (AdaptorErrorContext.class.isAssignableFrom(argTypes[i]))
                continue;

            Object value = null;
            if (curPathArgIdx < len) { // 路径参数
                value = pathArgs[curPathArgIdx];
                curPathArgIdx++;
            } else { // 普通参数
                value = obj;
            }
            try {
                args[i] = injs[i].get(sc, req, resp, value);
            }
            catch (Throwable e) {
                if (errCtx != null) {
                	log.infof("Adapter Param Error(%s) index=%d", method, i, e);
                    errCtx.setError(i, e, method, value, injs[i]); // 先错误保存起来,全部转好了,再判断是否需要抛出
                } else
                    throw Lang.wrapThrow(e);
            }
            if (args[i] == null) {
            	if (defaultValues[i] != null) {
            		args[i] = Castors.me().castTo(defaultValues[i], argTypes[i]);
            	} else if (argTypes[i].isPrimitive()) {
            		args[i] = Lang.getPrimitiveDefaultValue(argTypes[i]);
            	}
            }
        }

        // 看看是否有任何错误
        if (errCtx == null)
            return args;
        for (Throwable err : errCtx.getErrors()) {
            if (err == null)
                continue;
            if (errCtxIndex > -1) {
                if (log.isInfoEnabled())
                    log.info("Adapter Param Error catched , but I found AdaptorErrorContext param, so, set it to args, and continue");
                args[errCtxIndex] = errCtx;
                return args;
            }
            // 没有AdaptorErrorContext参数? 那好吧,按之前的方式,抛出异常
            throw Lang.wrapThrow(err);
        }

        return args;
    }

    protected Object getReferObject(ServletContext sc,
                                    HttpServletRequest req,
                                    HttpServletResponse resp,
                                    String[] pathArgs) {
        return null;
    }

    /**
     * 这是最后的大招了,查一下形参的名字,作为@Param("形参名")进行处理
     */
    protected ParamInjector paramNameInject(Method method, int index) {
        if (!Lang.isAndroid) {
            String paramName = getParamRealName(index);
            if (paramName != null) {
                Class<?> type = argTypes[index];
                if (type.isArray()) {
                    return new ArrayInjector(paramName,
                            null,
                            type,
                            null,
                            null,
                            true);
                }
                if (Modifier.isInterface(type.getModifiers()))
                    return new VoidInjector();
                return new NameInjector(paramName,
                        null,
                        argTypes[index],
                        null, null);
            }
            else if (log.isInfoEnabled())
                log.infof("Complie without debug info? can't deduce param name. fail back to PathArgInjector!! index=%d > %s",
                          index,
                          method);
    	}

        return new PathArgInjector(method.getParameterTypes()[index]);
    }

    protected String getParamRealName(int index) {
        if (paramNames == null || paramNames.length <= index)
            return "arg" + index;
        return paramNames[index];
    }
}


package org.nutz.el;

import java.util.Map;
import java.util.Queue;

import org.nutz.el.arithmetic.ShuntingYard;
import org.nutz.el.arithmetic.RPN;
import org.nutz.lang.Lang;
import org.nutz.lang.segment.CharSegment;
import org.nutz.lang.util.Context;

public class El {
    private RPN rc = null;
    private CharSequence elstr = "";

    public El(){}
    /**
     * 预编译
     */
    public El(CharSequence cs){
        elstr = cs;
        ShuntingYard sy = new ShuntingYard();
        Queue<Object> rpn = sy.parseToRPN(cs.toString());
        rc = new RPN(rpn);
    }
    /**
     * 解析预编译后的EL表达式
     */
    public Object eval(Context context) {
        if(rc == null){
            throw new ElException("没有进行预编译!");
        }
        return rc.calculate(context);
    }

    /**
     * 对参数代表的表达式进行运算
     */
    public static Object eval(String val) {
        //逆波兰表示法（Reverse Polish notation，RPN，或逆波兰记法）
        return eval(null, val);
    }

    public static Object eval(Context context, String val) {
        ShuntingYard sy = new ShuntingYard();
        RPN rc = new RPN();
        Queue<Object> rpn = sy.parseToRPN(val);
        return rc.calculate(context, rpn);
    }

    public String toString() {
        return elstr.toString();
    }

    /**
     * 说明:
     * 1. 操作符优先级参考<Java运算符优先级参考图表>, 但不完全遵守,比如"()"
     * 2. 使用Queue 的原因是,调用peek()方法不会读取串中的数据.
     * 因为我希望达到的效果是,我只读取我需要的,我不需要的数据我不读出来.
     */

    //@ JKTODO 删除原来的EL包,并修改当前为EL
    //@ JKTODO 自己实现一个QUEUE接口, 主要是实现队列,头部检测,头部第几个元素检测

    public static String render(String seg, Context ctx) {
        return render(new CharSegment(seg), ctx);
    }

    public static String render(CharSegment seg, Context ctx) {
        Context main = Lang.context();
        for (String key : seg.keys()) {
            main.putAll(key, new El(key).eval(ctx));
        }
        return seg.render(main).toString();
    }

    public static String render(CharSegment seg, Map<String, El> els, Context ctx) {
        Context main = Lang.context();
        for (String key : seg.keys()) {
            El el = els.get(key);
            if (el == null)
                el = new El(key);
            main.putAll(key, el.eval(ctx));
        }
        return seg.render(main).toString();
    }
}


package org.nutz.lang.util;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import org.nutz.castor.Castors;
import org.nutz.el.El;
import org.nutz.lang.Each;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;
import org.nutz.lang.born.Borning;

/**
 * 对于 LinkedHashMap 的一个友好封装
 * <p>
 * 同 TreeMap 不同的是，如果 get(null)，它不会抛错，就是返回 null 或默认值
 *
 * @author zozoh(zozohtnt@gmail.com)
 */
public class NutMap extends LinkedHashMap<String, Object> implements NutBean {

    /**
	 *
	 */
	private static final long serialVersionUID = 1L;

	public static NutMap WRAP(Map<String, Object> map) {
        if (null == map)
            return null;
        if (map instanceof NutMap)
            return (NutMap) map;
        return new NutMap(map);
    }

    public NutMap() {
        super();
    }

    public NutMap(Map<String, Object> map) {
        super();
        this.putAll(map);
    }

    public NutMap(String json) {
        super();
        this.putAll(Lang.map(json));
    }

    public NutMap(String key, Object value) {
        super();
        put(key, value);
    }

    /**
     * 设置一个字段，如果值为 null 则表示移除
     *
     * @param key
     *            键
     * @param v
     *            值
     */
    @Override
    public void setOrRemove(String key, Object v) {
        if (null == v) {
            this.remove(key);
        } else {
            this.put(key, v);
        }
    }

    public static NutMap NEW() {
        return new NutMap();
    }

    public static NutMap WRAP(String json) {
        return new NutMap(json);
    }

    @Override
    public boolean has(String key) {
        return null != get(key);
    }

    @Override
    public boolean is(String key, Object val) {
        Object obj = this.get(key);
        if (null == obj && null == val)
            return true;
        if (null == obj || null == val)
            return false;
        return obj.equals(val);
    }

    public NutMap duplicate() {
        NutMap map = new NutMap();
        map.putAll(this);
        return map;
    }

    /**
     * 从 Map 里挑选一些键生成一个新的 Map
     *
     * @param keys
     *            键
     * @return 新 Map
     */
    @Override
    public NutMap pick(String... keys) {
        if (keys.length == 0)
            return new NutMap();
        NutMap re = new NutMap();
        for (String key : keys) {
            Object val = this.get(key);
            if (null != val)
                re.put(key, val);
        }
        return re;
    }

    /**
     * 从 Map 里挑选一些键生成一个新的 Map，自己同时删除这些键
     *
     * @param keys
     *            键
     * @return 新 Map
     */
    @Override
    public NutMap pickAndRemove(String... keys) {
        if (keys.length == 0)
            return new NutMap();
        NutMap re = new NutMap();
        for (String key : keys) {
            Object val = this.remove(key);
            re.put(key, val);
        }
        return re;
    }

    /**
     * 从 Map 里挑选一些键生成一个新的 Map
     *
     * @param regex
     *            匹配键的正则表达式，"!" 开头，表示取反
     * @return 新 Map
     */
    @Override
    public NutMap pickBy(String regex) {
        if (Strings.isBlank(regex))
            return this.duplicate();
        boolean isNot = regex.startsWith("!");
        Pattern p = Regex.getPattern(isNot ? regex.substring(1) : regex);
        return pickBy(p, isNot);
    }

    /**
     * 从 Map 里挑选一些键生成一个新的 Map
     *
     * @param p
     *            匹配键的正则表达式，null 不会匹配任何一个键
     * @param isNot
     *            true 表示被匹配上的会被忽略，false 表示被匹配上的才加入到返回的集合里
     * @return 新 Map
     */
    @Override
    public NutMap pickBy(Pattern p, boolean isNot) {
        // 一定不匹配
        if (null == p) {
            return isNot ? this.duplicate() : new NutMap();
        }

        // 挑选
        NutMap re = new NutMap();
        for (Map.Entry<String, Object> en : this.entrySet()) {
            String key = en.getKey();
            boolean matched = p.matcher(key).find();
            if (matched) {
                if (!isNot) {
                    re.put(key, en.getValue());
                }
            } else if (isNot) {
                re.put(key, en.getValue());
            }
        }

        // 返回
        return re;
    }

    /**
     * 就是 pickAndRemoveBy 的一个便利写法
     *
     * @param regex
     *            正则表达式，! 开头表示取反
     * @return 新 Map
     *
     * @see #pickAndRemoveBy(Pattern, boolean)
     */
    public NutMap pickAndRemoveBy(String regex) {
        if (Strings.isBlank(regex))
            return new NutMap();
        boolean isNot = regex.startsWith("!");
        Pattern p = Pattern.compile(isNot ? regex.substring(1) : regex);
        return pickAndRemoveBy(p, isNot);
    }

    /**
     * 从 Map 里挑选一些键生成一个新的 Map，自己同时删除这些键
     *
     * @param p
     *            匹配键的正则表达式，null 不会匹配任何一个键
     * @param isNot
     *            true 表示被匹配上的会被忽略，false 表示被匹配上的才加入到返回的集合里
     * @return 新 Map
     */
    @Override
    public NutMap pickAndRemoveBy(Pattern p, boolean isNot) {
        // 一定不匹配
        if (null == p) {
            if (isNot) {
                NutMap re = this.duplicate();
                this.clear();
                return re;
            } else {
                return new NutMap();
            }
        }

        // 挑选
        NutMap re = new NutMap();
        List<String> delKeys = new ArrayList<String>(this.size());
        for (Map.Entry<String, Object> en : this.entrySet()) {
            String key = en.getKey();
            boolean matched = p.matcher(key).find();
            if (matched) {
                if (!isNot) {
                    delKeys.add(key);
                    re.put(key, en.getValue());
                }
            } else if (isNot) {
                delKeys.add(key);
                re.put(key, en.getValue());
            }
        }

        // 删除 Key
        for (String key : delKeys)
            this.remove(key);

        // 返回
        return re;
    }

    /**
     * 从 Map 里将指定的键过滤，生成一个新的 Map
     *
     * @param keys
     *            键
     * @return 新 Map
     */
    @Override
    public NutMap omit(String... keys) {
        NutMap re = new NutMap();
        for (Map.Entry<String, Object> en : this.entrySet()) {
            String key = en.getKey();
            if (!Lang.contains(keys, key)) {
                re.put(key, en.getValue());
            }
        }
        return re;
    }

    /**
     * 如果一个键的值无效（has(key) 返回 false)，那么为其设置默认值
     *
     * @param key
     *            键
     * @param dft
     *            值
     * @return 自身以便链式赋值
     */
    @Override
    public NutMap putDefault(String key, Object dft) {
        if (!this.has(key)) {
            this.put(key, dft);
        }
        return this;
    }

    @Override
    public boolean containsValue(Object value) {
        if (null == _map)
            return super.containsValue(value);
        return super.containsValue(value) || _map.containsValue(value);
    }

    @Override
    public boolean containsKey(Object key) {
        if (null == _map)
            return super.containsKey(key);
        return super.containsKey(key) || _map.containsKey(key);
    }

    @Override
    public Set<String> keySet() {
        if (null == _map)
            return super.keySet();
        HashSet<String> keys = new HashSet<String>();
        keys.addAll(super.keySet());
        keys.addAll(_map.keySet());
        return keys;
    }

    @Override
    public Collection<Object> values() {
        if (null == _map)
            return super.values();
        List<Object> vals = new LinkedList<Object>();
        for (String key : this.keySet()) {
            vals.add(this.get(key));
        }
        return vals;
    }

    @Override
    public Set<Entry<String, Object>> entrySet() {
        if (null == _map)
            return super.entrySet();
        HashSet<Entry<String, Object>> vals = new HashSet<Entry<String, Object>>();
        vals.addAll(_map.entrySet());
        vals.addAll(super.entrySet());
        return vals;
    }

    @Override
    public void clear() {
        super.clear();
        if (null != _map)
            _map.clear();
    }

    private NutMap _map;

    public NutMap attach(NutMap map) {
        _map = map;
        return this;
    }

    public NutMap detach() {
        NutMap re = _map;
        _map = null;
        return re;
    }

    @Override
    public Object get(Object key) {
        if (_map == null)
            return super.get(key);

        if (super.containsKey(key)) {
            return super.get(key);
        }

        return _map.get(key);
    }

    @Override
    public Object get(String key, Object dft) {
        Object v = get(key);
        return null == v ? dft : v;
    }

    @Override
    public int getInt(String key) {
        return getInt(key, -1);
    }

    @Override
    public int getInt(String key, int dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, int.class);
    }

    @Override
    public float getFloat(String key) {
        return getFloat(key, Float.NaN);
    }

    @Override
    public float getFloat(String key, float dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, float.class);
    }

    @Override
    public long getLong(String key) {
        return getLong(key, -1);
    }

    @Override
    public long getLong(String key, long dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, long.class);
    }

    @Override
    public double getDouble(String key) {
        return getDouble(key, 0.0);
    }

    @Override
    public double getDouble(String key, double dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, double.class);
    }

    @Override
    public boolean getBoolean(String key) {
        return getBoolean(key, false);
    }

    @Override
    public boolean getBoolean(String key, boolean dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, boolean.class);
    }

    @Override
    public String getString(String key) {
        return getString(key, null);
    }

    @Override
    @SuppressWarnings("rawtypes")
    public String getString(String key, String dft) {
        Object v = get(key);
        if (v == null)
            return dft;
        if (v instanceof CharSequence)
            return v.toString();
        if (v instanceof List) {
            v = ((List) v).iterator().next();
        }
        // by wendal : 这还有必要castTo么?
        // zozoh: 当然有啦，比如日期对象，要变成字符串的话 ...
        return Castors.me().castTo(v, String.class);
    }

    @Override
    public Date getTime(String key) {
        return getTime(key, null);
    }

    @Override
    public Date getTime(String key, Date dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, Date.class);
    }

    @Override
    public <T extends Enum<T>> T getEnum(String key, Class<T> classOfEnum) {
        String s = getString(key);
        if (Strings.isBlank(s))
            return null;
        return Enum.valueOf(classOfEnum, s);
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean isEnum(String key, Enum<?>... eus) {
        if (null == eus || eus.length == 0)
            return false;
        try {
            Enum<?> v = getEnum(key, eus[0].getClass());
            for (Enum<?> eu : eus)
                if (!v.equals(eu))
                    return false;
            return true;
        }
        catch (Exception e) {
            return false;
        }
    }

    @Override
    public <T> T getAs(String key, Class<T> classOfT) {
        return getAs(key, classOfT, null);
    }

    @Override
    public <T> T getAs(String key, Class<T> classOfT, T dft) {
        Object v = get(key);
        return null == v ? dft : Castors.me().castTo(v, classOfT);
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public <T> List<T> getAsList(String key, Class<T> eleType) {
        Object v = get(key);
        if (null == v)
            return null;
        List list = (List) v;
        ListIterator it = list.listIterator();
        while (it.hasNext()) {
            Object ele = it.next();
            if (null != ele && !eleType.isAssignableFrom(ele.getClass())) {
                Object ele2 = Castors.me().castTo(ele, eleType);
                it.set(ele2);
            }
        }
        return list;
    }

    /**
     * @see #getList(String, Class, List)
     */
    @Override
    public <T> List<T> getList(String key, final Class<T> eleType) {
        return getList(key, eleType, new ArrayList<T>());
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> List<T> getList(String key, final Class<T> eleType, List<T> dft) {
        Object v = get(key);
        if (null == v)
            return dft;

        if (v instanceof CharSequence) {
            return Lang.list(Castors.me().castTo(v, eleType));
        }

        int len = Lang.eleSize(v);
        final List<T> list = new ArrayList<T>(len);
        Lang.each(v, new Each<Object>() {
            @Override
            public void invoke(int index, Object ele, int length) {
                list.add(Castors.me().castTo(ele, eleType));
            }
        });

        return list;

    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T[] getArray(String key, Class<T> eleType) {
        return getArray(key, eleType, (T[]) Array.newInstance(eleType, 0));
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T[] getArray(String key, final Class<T> eleType, T[] dft) {
        Object v = get(key);
        if (null == v)
            return dft;

        if (v instanceof CharSequence) {
            return Lang.array(Castors.me().castTo(v, eleType));
        }

        int len = Lang.eleSize(v);
        final Object arr = Array.newInstance(eleType, len);
        final int[] i = new int[]{0};
        Lang.each(v, new Each<Object>() {
            @Override
            public void invoke(int index, Object ele, int length) {
                Array.set(arr, i[0]++, Castors.me().castTo(ele, eleType));
            }
        });

        return (T[]) arr;

    }

    /**
     * 为 Map 增加一个名值对。如果同名已经有值了，那么会将两个值合并成一个列表
     *
     * @param key
     * @param value
     */
    @Override
    @SuppressWarnings("unchecked")
    public NutMap addv(String key, Object value) {
        Object obj = get(key);
        if (null == obj) {
            put(key, value);
        } else if (obj instanceof List<?>)
            ((List<Object>) obj).add(value);
        else {
            List<Object> list = new LinkedList<Object>();
            list.add(obj);
            list.add(value);
            put(key, list);
        }
        return this;
    }

    /**
     * 为 Map 增加一个名值对。强制设置为一个列表，如果有同名则合并
     *
     * @param key
     * @param value
     */
    @Override
    @SuppressWarnings("unchecked")
    public NutMap addv2(String key, Object value) {
        List<Object> list = (List<Object>) get(key);
        if (null == list) {
            list = new LinkedList<Object>();
            put(key, list);
        }
        list.add(value);
        return this;
    }

    /**
     * 向某个键增加一组值，如果原来就有值，是集合的话，会被合并，否则原来的值用列表包裹后再加入新值
     *
     * @param key
     *            键
     * @param values
     *            值列表
     * @return 自身
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public <T> NutMap pushTo(String key, T... values) {
        if (null != values && values.length > 0) {
            Object v = get(key);
            // 不存在的话，增加列表
            if (null == v) {
                List<Object> list = new LinkedList<Object>();
                for (Object val : values)
                    list.add(val);
                this.put(key, list);
            }
            // 如果是集合的话，就增加
            else if (v instanceof Collection) {
                for (Object val : values)
                    ((Collection) v).add(val);
            }
            // 否则将原来的值变成列表再增加
            else {
                List<Object> list = new LinkedList<Object>();
                list.add(v);
                for (Object val : values)
                    list.add(val);
                this.put(key, list);
            }
        }
        // 返回自身以便链式赋值
        return this;
    }

    /**
     * 是 pushTo 函数的另一个变种（可以接受集合）
     *
     * @param key
     *            键
     * @param values
     *            值列表
     * @return 自身
     *
     * @see #pushTo(String, Collection)
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public NutMap pushTo(String key, Collection<?> values) {
        if (null != values && values.size() > 0) {
            Object v = get(key);
            // 不存在的话，增加列表
            if (null == v) {
                List<Object> list = new LinkedList<Object>();
                list.addAll(values);
                this.put(key, list);
            }
            // 如果是集合的话，就增加
            else if (v instanceof Collection) {
                ((Collection) v).addAll(values);
            }
            // 否则将原来的值变成列表再增加
            else {
                List<Object> list = new LinkedList<Object>();
                list.add(v);
                list.addAll(values);
                this.put(key, list);
            }
        }
        // 返回自身以便链式赋值
        return this;
    }

    /**
     * @deprecated 本函数意义容易发生混淆，已经改名成 addv，下个版将被删除
     * @since 1.b.51
     */
    @Deprecated
    public NutMap putv(String key, Object value) {
        return addv(key, value);
    }

    @Override
    public NutMap setv(String key, Object value) {
        this.put(key, value);
        return this;
    }

    @Override
    public void unset(String key) {
        this.remove(key);
    }

    @Override
    public NutBean setAll(Map<String, Object> map) {
        this.putAll(map);
        return this;
    }

    @Override
    public NutMap setMap(Map<?, ?> map, boolean ignoreNullValue) {
        for (Map.Entry<?, ?> en : map.entrySet()) {
            Object key = en.getKey();
            Object val = en.getValue();

            if (null == key)
                continue;

            if (null == val && ignoreNullValue)
                continue;

            this.put(key.toString(), val);
        }
        return this;
    }

    /**
     * 相当于 mergeWith(map, false)
     *
     * @see #mergeWith(Map, boolean)
     */
    @Override
    public NutMap mergeWith(Map<String, Object> map) {
        return this.mergeWith(map, false);
    }

    /**
     * 与一个给定的 Map 融合，如果有子 Map 递归
     *
     * @param map
     *            要合并进来的 Map
     * @param onlyAbsent
     *            true 表示只有没有 key 才设置值
     * @return 自身以便链式赋值
     */
    @Override
    @SuppressWarnings("unchecked")
    public NutMap mergeWith(Map<String, Object> map, boolean onlyAbsent) {
        for (Map.Entry<String, Object> en : map.entrySet()) {
            String key = en.getKey();
            Object val = en.getValue();

            if (null == key || null == val)
                continue;

            Object myVal = this.get(key);

            // 如果两边都是 Map ，则融合
            if (null != myVal && myVal instanceof Map && val instanceof Map) {
                Map<String, Object> m0 = (Map<String, Object>) myVal;
                Map<String, Object> m1 = (Map<String, Object>) val;
                NutMap m2 = NutMap.WRAP(m0).mergeWith(m1, onlyAbsent);
                // 搞出了新 Map，设置一下
                if (m2 != m0)
                    this.put(key, m2);
            }
            // 只有没有的时候才设置
            else if (onlyAbsent) {
                this.setnx(key, val);
            }
            // 否则直接替换
            else {
                this.put(key, val);
            }
        }

        return this;
    }

    /**
     * 与JDK8+的 putIfAbsent(key, val)一致, 当且仅当值不存在时设置进去,但与putIfAbsent返回值有不一样
     *
     * @param key
     *            键
     * @param val
     *            值
     * @return 当前的NutMap实例
     */
    @Override
    public NutMap setnx(String key, Object val) {
        if (!containsKey(key))
            setv(key, val);
        return this;
    }

    /**
     * 将一个集合与自己补充（相当于针对每个 key 调用 setnx)
     *
     * @param map
     *            集合
     * @return 自身
     *
     * @see #setnx(String, Object)
     */
    @Override
    public NutMap setnxAll(Map<String, Object> map) {
        if (null != map && map.size() > 0) {
            for (Map.Entry<String, Object> en : map.entrySet()) {
                this.setnx(en.getKey(), en.getValue());
            }
        }
        return this;
    }

    /**
     * 获取对应的值,若不存在,用factory创建一个,然后设置进去,返回之
     *
     * @param key
     *            键
     * @param factory
     *            若不存在的话用于生成实例
     * @return 已存在的值或新的值
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getOrBorn(String key, Borning<T> factory) {
        T t = (T) get(key);
        if (t == null) {
            t = factory.born(key);
            put(key, t);
        }
        return t;
    }

    /**
     * 将自身作为一个条件，看看给定的 Map 是否全部满足这个条件
     * <p>
     * 注意，字符串型的值有下列意义
     * <ul>
     * <li>"^xxxxx" : 正则表达式
     * <li>"" : 相当于 Blank
     * </ul>
     *
     * @param map
     *            给定的 Map
     * @return 是否匹配
     */
    @Override
    public boolean match(Map<String, Object> map) {
        // 空 map 一定是不匹配的
        if (null == map)
            return false;

        // 本 Map 如果没值，表示全匹配
        if (this.size() == 0)
            return true;

        // 逐个匹配键
        for (Map.Entry<String, Object> en : this.entrySet()) {
            String key = en.getKey();
            Object mtc = en.getValue();

            // null 表示对方不能包括这个键
            if (null == mtc) {
                if (map.containsKey(key))
                    return false;
            }
            // 其他的值，匹配一下
            else {
                Object val = map.get(key);
                if (!__match_val(mtc, val)) {
                    return false;
                }
            }
        }
        // 都检查过了 ...
        return true;
    }

    private boolean __match_val(final Object mtc, Object val) {
        Mirror<?> mi = Mirror.me(mtc);

        // 如果为 null，则只有空串能匹配
        if (null == val) {
            return mi.isStringLike() && Strings.isEmpty(mtc.toString());
        }

        // 字符串的话
        Pattern regex = mi.is(Pattern.class) ? (Pattern) mtc : null;
        if (mi.isStringLike()) {

            final String s = mtc.toString();
            if (s.startsWith("^")) {
                regex = Regex.getPattern(s);
            }
            // 不是正则表达式，那么精确匹配字符串
            else {
                final boolean[] re = new boolean[1];
                Lang.each(val, new Each<Object>() {
                    @Override
                    public void invoke(int index, Object ele, int length) {
                        if (null != ele && ele.equals(s)) {
                            re[0] = true;
                            Lang.Break();
                        }
                    }
                });
                return re[0];
            }
        }

        // 正则表达式
        if (null != regex) {
            final boolean[] re = new boolean[1];
            final Pattern REG = regex;
            Lang.each(val, new Each<Object>() {
                @Override
                public void invoke(int index, Object ele, int length) {
                    if (null != ele && REG.matcher(ele.toString()).matches()) {
                        re[0] = true;
                        Lang.Break();
                    }
                }
            });
            return re[0];
        }

        // 简单类型的比较
        if (mi.isSimple()) {
            final boolean[] re = new boolean[1];
            Lang.each(val, new Each<Object>() {
                @Override
                public void invoke(int index, Object ele, int length) {
                    if (null != ele && ele.equals(mtc)) {
                        re[0] = true;
                        Lang.Break();
                    }
                }
            });
            return re[0];
        }
        // 范围的话...
        else if (mi.is(Region.class)) {
            throw Lang.noImplement();
        }
        // 其他的统统为不匹配
        return false;
    }

    public Object eval(String el) {
        return El.eval(Lang.context(this), el);
    }

    public int evalInt(String el) {
        Object obj = El.eval(Lang.context(this), el);
        if (obj == null)
            return 0;
        if (obj instanceof Number)
            return ((Number) obj).intValue();
        return Integer.parseInt(obj.toString());
    }

    /**
     * 指定key进行自增操作，并返回结果
     *
     * @param key
     *            键
     * @return 自增后结果
     */
    public int intIncrement(String key) {
        return intIncrement(key, 1);
    }

    /**
     * 指定key进行增操作，并返回结果
     *
     * @param key
     *            键
     * @param number
     *            数值
     * @return 增后结果
     */
    public int intIncrement(String key, int number) {
        int val = getInt(key, 0);
        val += number;
        setv(key, val);
        return val;
    }

    /**
     * 指定key进行自减操作，并返回结果
     *
     * @param key
     *            键
     * @return 自减后结果
     */
    public int intDecrement(String key) {
        return intDecrement(key, 1);
    }

    /**
     * 指定key进行减操作，并返回结果
     *
     * @param key
     *            键
     * @param number
     *            数值
     * @return 减后结果
     */
    public int intDecrement(String key, int number) {
        int val = getInt(key, 0);
        val -= number;
        setv(key, val);
        return val;
    }

    /**
     * 指定key进行自增操作，并返回结果
     *
     * @param key
     *            键
     * @return 自增后结果
     */
    public long longIncrement(String key) {
        return longIncrement(key, 1);
    }

    /**
     * 指定key进行增操作，并返回结果
     *
     * @param key
     *            键
     * @param number
     *            数值
     * @return 增后结果
     */
    public long longIncrement(String key, long number) {
        long val = getLong(key, 0);
        val += number;
        setv(key, val);
        return val;
    }

    /**
     * 指定key进行自减操作，并返回结果
     *
     * @param key
     *            键
     * @return 自减后结果
     */
    public long longDecrement(String key) {
        return longDecrement(key, 1);
    }

    /**
     * 指定key进行减操作，并返回结果
     *
     * @param key
     *            键
     * @param number
     *            数值
     * @return 减后结果
     */
    public long longDecrement(String key, long number) {
        long val = getLong(key, 0);
        val -= number;
        setv(key, val);
        return val;
    }
}


package org.nutz.mvc.upload.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

class RingItem {

    byte[] buffer;

    int max;
    /**
     * 左标记，DUMP 时包含
     */
    int l;
    /**
     * 右标记，DUMP 时不包含
     */
    int r;
    /**
     * 下一次 Mark 是开始的位置
     */
    int nextmark;

    RingItem next;

    boolean isLoaded;
    boolean isStreamEnd;

    RingItem(int width) {
        this.buffer = new byte[width];
        this.next = this;
    }

    RingItem createNext() {
        RingItem ri = new RingItem(buffer.length);
        ri.next = next;
        next = ri;
        return ri;
    }

    void load(InputStream ins) throws IOException {
        if (isLoaded) {
            throw new ReloadLoadedRingItemException();
        }
        int bufferSize = buffer.length;
        max = ins.read(buffer, 0, bufferSize);

        // 流里不在有内容了
        if (max < 0) {
            max = 0;
            isStreamEnd = true;
        }
        // 没有读全，继续读，直至read方法返回 -1, 或者读满.
        else {
            while (max < bufferSize) {
                int re = ins.read(buffer, max, bufferSize - max);
                if (re == -1) {
                    isStreamEnd = true;
                    break;
                }
                max += re;
            }
        }

        l = 0;
        r = 0;
        nextmark = 0;
        isLoaded = true;
    }

    void dump(OutputStream ops) throws IOException {
        if (l < r) {
            ops.write(buffer, l, r - l);
        }
        l = nextmark;
        r = l;
        isLoaded = (l < max);
    }

    /**
     * 试图从缓冲开头匹配，如果匹配失败，移动 'r' 并返回 false

     * 如果匹配成功，则移动 'l'（匹配的内容不需要读取） 并返回 true
     *

     * 这个函数，在 BufferRing 发现当前的环节点返回 '>0' 时，需要调用 next 的这个函数，看看是不是可以完整被匹配
     *
     * @param bs
     *            数组
     * @param offs
     *            偏移量
     * @return 本节点开头是否匹配剩余的部分
     */
    boolean matchHeadingWithRemain(byte[] bs, int offs) {
        int i = 0;
        for (; offs < bs.length; offs++) {
            if (buffer[i++] != bs[offs]) {
                r = i;
                return false;
            }
        }
        // Matched, skip it
        l = i;
        r = i;
        nextmark = i;
        return true;
    }

    boolean isDone4Mark() {
        return nextmark == max;
    }

    /**
     * 从给定 offs 尽力匹配给出的数组。
     *

     * 需要注意的是，如果返回的是 >0 的数，内部的标志位将被设置到第一个匹配字符，以便 DUMP 内容。

     * 所以，如果下一个节点给出的结论是 -1，但是 'l' 并不是0，那么说明这个匹配是失败的，需要将 本节点的 r 置到 max 处。
     *

     * 返回值
     *

     *
-1 - 全部被匹配
     *
0 - 未发现匹配
     *
大于 0 - 在缓冲的末尾发现匹配，但是没有匹配全，希望下一个节点继续从这个位置匹配
     *

     *
     * @param bs
     *            数组
     * @return -1, 0 或者 +n
     */
    int mark(byte[] bs, int[] fails) {
        if (!isLoaded)
            throw new MarkUnloadedRingItemException();

        byte start = bs[0];

        for (; r < max; r++) {
            // 可能是边界，开始匹配
            if (buffer[r] == start) {
                int re = 0; // 已经匹配长度
                int j = r; // 在内容值字节数组中的指针
                while (true) {
                    re++;
                    j++;
                    // 全部匹配
                    if (re == bs.length) {
                        nextmark = j;
                        return -1;
                    }
                    // 到达本项目的结尾，但是并不确定是否是边界，因为还未匹配完
                    // 因此暂时假设这个不会被匹配
                    if (j == max) {
                        nextmark = max;
                        if (isStreamEnd) {
                            r = max;
                            return 0;
                        }
                        return re;
                    }
                    // 如果字符不相等，那么查看一下回退数组
                    // 如果回退到 0，则退出循环，因为这不是边界，否则继续循环匹配边界
                    if (bs[re] != buffer[j]) {
                        re = fails[re];
                        // 再次判断回退后位置，如果还是不相同，则退出循环
                        if (bs[re] != buffer[j]) {
                            break;
                        }
                        // 如果已经回退到了 0，你这么右边界置为 j，表示从头搜索
                        else if (re == 0) {
                            r = j;
                        }
                        // 否则扩大边界，并继续循环
                        else {
                            r += re == 0 ? 1 : re;
                        }

                    }
                }
                // make 'r' jump to 'j'
                r = j;
            }
        }
        // Fail to found
        nextmark = max;
        return 0;
    }
}


package org.nutz.ioc.loader.map;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.nutz.ioc.IocLoader;
import org.nutz.ioc.IocLoading;
import org.nutz.ioc.Iocs;
import org.nutz.ioc.ObjectLoadException;
import org.nutz.ioc.meta.IocObject;
import org.nutz.json.Json;
import org.nutz.lang.Lang;

/**
 * 从一个 Map 对象中读取配置信息，支持 Parent
 *
 * @author zozoh(zozohtnt@gmail.com)
 * @author wendal(wendal1985@gmail.com)
 */
public class MapLoader implements IocLoader {

    protected Map<String, Map<String, Object>> map;

    protected MapLoader() {
        map = new HashMap<String, Map<String, Object>>();
    }

    @SuppressWarnings("unchecked")
    public MapLoader(String json) {
        this((Map<String, Map<String, Object>>) Json.fromJson(json));
    }

    public MapLoader(Map<String, Map<String, Object>> map) {
        this.map = map;
    }

    public Map<String, Map<String, Object>> getMap() {
        return map;
    }

    public void setMap(Map<String, Map<String, Object>> map) {
        this.map = map;
    }

    public String[] getName() {
        return map.keySet().toArray(new String[map.size()]);
    }

    public boolean has(String name) {
        return map.containsKey(name);
    }

    /**
     * {@link ObjectLoadException}
     */
    public IocObject load(IocLoading loading, String name) throws ObjectLoadException {
        Map<String, Object> m = getMap(name);
        if (null == m)
            throw new ObjectLoadException("Object '" + name + "' without define!");
        // If has parent
        Object p = m.get("parent");
        if (null != p) {
            checkParents(name);
            IocObject parent = load(loading, p.toString());
            // create new map without parent
            Map<String, Object> newMap = new HashMap<String, Object>();
            for (Entry<String, Object> en : m.entrySet()) {
                if ("parent".equals(en.getKey()))
                    continue;
                newMap.put(en.getKey(), en.getValue());
            }
            // Create self IocObject
            IocObject self = loading.map2iobj(newMap);

            // Merge with parent
            return Iocs.mergeWith(self, parent);
        }
        return loading.map2iobj(m);
    }

    /**
     * 检查继承关系,如果发现循环继承,或其他错误的继承关系,则抛出ObjectLoadException
     *
     * @param name
     *            beanId
     * @throws ObjectLoadException
     *             if Inheritance errors or Inheritance cycle founded.
     */
    @SuppressWarnings("unchecked")
    private void checkParents(String name) throws ObjectLoadException {
        ArrayList<String> list = new ArrayList<String>();
        list.add(name);
        String currentParent = map.get(name).get("parent").toString();
        while (true) {
            if (currentParent == null)
                break;
            if (list.contains(currentParent))
                throw Lang.makeThrow(    ObjectLoadException.class,
                                        "!!!Inheritance cycle! id = %s",
                                        name);
            list.add(currentParent);
            Object obj = map.get(currentParent);
            if (obj != null && obj instanceof Map)
                currentParent = (String) ((Map<String, Object>) obj).get("parent");
            else
                throw Lang.makeThrow(    ObjectLoadException.class,
                                        "!!!Inheritance errors! id = %s",
                                        name);
        }
    }

    /**
     * Inner Object can not support 'parent'.
     *
     * @param name
     *            object Map name
     * @return object Map
     */
    private Map<String, Object> getMap(String name) {
        return map.get(name);
    }

    @Override
    public String toString() {
        return "/*" + getClass().getSimpleName() + "*/\n" + Json.toJson(map);
    }
}


package org.nutz.lang.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentHashMap;

import org.nutz.aop.DefaultClassDefiner;
import org.nutz.lang.Lang;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.repo.org.objectweb.asm.ClassWriter;
import org.nutz.repo.org.objectweb.asm.Label;
import org.nutz.repo.org.objectweb.asm.Opcodes;
import org.nutz.repo.org.objectweb.asm.Type;
import org.nutz.repo.org.objectweb.asm.commons.GeneratorAdapter;

public class FastMethodFactory implements Opcodes {

    protected static ConcurrentHashMap<String, FastMethod> cache = new ConcurrentHashMap<String, FastMethod>();
    protected static final Log log = Logs.get();

    protected static org.nutz.repo.org.objectweb.asm.commons.Method _M;
    protected static org.nutz.repo.org.objectweb.asm.Type Exception_TYPE;
    static {
        _M = _Method("invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
        Exception_TYPE = Type.getType(Throwable.class);
    }

    protected static FastMethod make(final Method method) {
        Class<?> klass = method.getDeclaringClass();
        String descriptor = Type.getMethodDescriptor(method) + method.getDeclaringClass().getClassLoader();
        String key = "$FM$" + method.getName() + "$" + Lang.md5(descriptor);
        String className = klass.getName() + key;
        if (klass.getName().startsWith("java"))
            className = FastMethod.class.getPackage().getName() + ".fast." + className;
        FastMethod fm = cache.get(className);
        if (fm != null)
            return fm;
        // fix issue #1382 : 非public类的方法,统统做成FallbackFastMethod
        if (!Modifier.isPublic(klass.getModifiers())) {
            fm = new FallbackFastMethod(method);
            cache.put(className, fm);
            return fm;
        }
        try {
            fm = (FastMethod) klass.getClassLoader().loadClass(className).newInstance();
            cache.put(className, fm);
            return fm;
        }
        catch (Throwable e) {}
        try {
            byte[] buf = _make(klass,
                               method.getModifiers(),
                               method.getParameterTypes(),
                               _Method(method),
                               method.getReturnType(),
                               className,
                               descriptor);
            Class<?> t = DefaultClassDefiner.defaultOne().define(className,
                                                                 buf,
                                                                 klass.getClassLoader());
            fm = (FastMethod) t.newInstance();
        }
        catch (Throwable e) {
            if (log.isTraceEnabled())
                log.trace("Fail to create FastMethod for " + method, e);
            fm = new FallbackFastMethod(method);
        }
        cache.put(className, fm);
        return fm;
    }

    protected static FastMethod make(Constructor<?> constructor) {
        Class<?> klass = constructor.getDeclaringClass();
        String descriptor = Type.getConstructorDescriptor(constructor) + constructor.getDeclaringClass().getClassLoader();;
        String key = Lang.md5(descriptor);
        String className = klass.getName() + "$FC$" + key;
        if (klass.getName().startsWith("java"))
            className = FastMethod.class.getPackage().getName() + ".fast." + className;
        FastMethod fm = (FastMethod) cache.get(className);
        if (fm != null)
            return fm;
        try {
            fm = (FastMethod) klass.getClassLoader().loadClass(className).newInstance();
            cache.put(key, fm);
            return fm;
        }
        catch (Throwable e) {}
        try {
            byte[] buf = _make(klass,
                               constructor.getModifiers(),
                               constructor.getParameterTypes(),
                               _Method(constructor),
                               null,
                               className,
                               descriptor);
            Class<?> t = DefaultClassDefiner.defaultOne().define(className,
                                                                 buf,
                                                                 klass.getClassLoader());
            fm = (FastMethod) t.newInstance();
        }
        catch (Throwable e) {
            if (log.isTraceEnabled())
                log.trace("Fail to create FastMethod for " + constructor, e);
            fm = new FallbackFastMethod(constructor);
        }
        cache.put(className, fm);
        return fm;
    }

    /**
     * 生成两种FastClass实例: 创建对象, 和执行普通方法的. 区分的点就是returnType是否为null. 模式为创建对象,returnType总是null, 模式为执行方法,returnType总不是null, 要么Void要么是某个类.
     * @param klass 被代理的类
     * @param mod 方法的modify数据
     * @param params 参数列表
     * @param method asm下的方法签名
     * @param returnType 返回值. 如果执行的是构造方法,那么它是null,否则肯定不是null.
     * @param className 目标类名,FastClass实现类的类名
     * @param descriptor 类签名
     */
    public static byte[] _make(Class<?> klass,
                               int mod,
                               Class<?>[] params,
                               org.nutz.repo.org.objectweb.asm.commons.Method method,
                               Class<?> returnType,
                               String className,
                               String descriptor) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        cw.visit(V1_5,
                 ACC_PUBLIC,
                 className.replace('.', '/'),
                 null,
                 "java/lang/Object",
                 new String[]{FastMethod.class.getName().replace('.', '/')});

        Type klassType = Type.getType(klass);

        // 首先, 定义默认构造方法
        addConstructor(cw, Type.getType(Object.class), org.nutz.repo.org.objectweb.asm.commons.Method.getMethod("void <init> ()"));

        // 然后定义执行方法, _M就是invoke方法的签名
        GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, _M, null, new Type[]{Exception_TYPE}, cw);
        if (returnType == null) { // 没有返回值,是代表这里模式是 "构造方法"
            mg.newInstance(klassType); // 相当于 new User . 注意, 没有括号哦,因为构造方法参数还没传
            mg.dup();
        }
        else if (!Modifier.isStatic(mod)) { // 有返回值, 那么, 模式是"执行方法". 然后呢, 非静态方法的话,需要载入对象
            mg.loadThis();
            mg.loadArg(0); // 代表 Object invoke(Object obj, Object ... args) 中的 obj
            mg.checkCast(klassType); // 因为invoke方法的签名中, obj的类型是Object, 需要cast为目标类型.
            // 相当于执行了 ((User)obj)
        }
        // 准备参数列表. 根据被执行的方法或构造方法的签名,可以推测出参数列表.
        // invoke方法得到的是一个 Object[], 需要一一展开
        if (params.length > 0) {
            for (int i = 0; i < params.length; i++) {
                mg.loadArg(1); // 代表 Object invoke(Object obj, Object ... args) 中的 args
                mg.push(i); // 数组下标
                mg.arrayLoad(Type.getType(Object.class)); // 读取数组. 上面三句相当于 args[i]
                Type paramType = Type.getType(params[i]); // 读取目标方法/构造方法的参数的类型
                if (params[i].isPrimitive()) {
                    mg.unbox(paramType); // 如果是基本数据类型,需要开箱. Object --> Integer --> int . 在Java源文件里面有自动封箱/自动开箱,asm可没这种东西.
                } else {
                    mg.checkCast(paramType); // 其他类型? 直接cast一下就好了
                }
            }
            // 上面的代码转换为java写法的话,就是
            // ((Integer)args[0], (String)args[1], ....)
            // 注意, 没有 对象在前面, 因为还没执行
        }
        if (returnType == null) { // 模式是
            mg.invokeConstructor(klassType, method);
            // 跟前面的代码合并在一起        new User((Integer)args[0], (String)args[1], ....);
        } else {
            if (Modifier.isStatic(mod)) {
                mg.invokeStatic(klassType, method);
                // 跟前面的代码合并在一起,假设方法名称是create,静态方法
                // User.create((Integer)args[0], (String)args[1], ....);
            } else if (Modifier.isInterface(klass.getModifiers())) {
                mg.invokeInterface(klassType, method);
                // 跟前面的代码合并在一起,假设方法名称是create, User是一个接口
                // ((User)obj).create((Integer)args[0], (String)args[1], ....);
            } else {
                mg.invokeVirtual(klassType, method);
                // 跟前面的代码合并在一起,假设方法名称是create, User是一个普通类
                // ((User)obj).create((Integer)args[0], (String)args[1], ....);
            }
            // 处理方法返回值的特殊情况
            if (Void.class.equals(returnType)) {
                // 如果method没有返回值(void),那么,塞入一个null做invoke方法返回值
                mg.visitInsn(ACONST_NULL);
            } else if (returnType.isPrimitive()) {
                // method有返回值,而且是基本数据类型? 那么就要封箱了,因为invoke方法返回的是Object, 基本数据类型可不是Object.
                mg.box(Type.getType(returnType));
            } else {
                // 其余的情况就是没情况, method的返回值已经在堆栈里面,等着返回就行
            }
        }
        // 伪造一下行号, 这样eclipse就不会抱怨
        Label tmp = new Label();
        mg.visitLabel(tmp);
        mg.visitLineNumber(1, tmp);

        // 把堆栈中的返回值给弹出去.
        mg.returnValue();
        // 完整整个方法
        mg.endMethod();
        // 再注册一下源文件名称, 结合行号, 日志里面会显示 (User.java:1)
        cw.visitSource(klass.getSimpleName() + ".java", null);
        // 整个类结束
        cw.visitEnd();
        // 字节码生成完成, 返回byte[]
        return cw.toByteArray();
    }

    public static org.nutz.repo.org.objectweb.asm.commons.Method _Method(String name, String desc) {
        return new org.nutz.repo.org.objectweb.asm.commons.Method(name, desc);
    }

    public static org.nutz.repo.org.objectweb.asm.commons.Method _Method(Method method) {
        return org.nutz.repo.org.objectweb.asm.commons.Method.getMethod(method);
    }

    public static org.nutz.repo.org.objectweb.asm.commons.Method _Method(String method) {
        return org.nutz.repo.org.objectweb.asm.commons.Method.getMethod(method);
    }

    private static org.nutz.repo.org.objectweb.asm.commons.Method _Method(Constructor<?> constructor) {
        return org.nutz.repo.org.objectweb.asm.commons.Method.getMethod(constructor);
    }

    public static void addConstructor(ClassWriter cw,
                                      Type parent,
                                      org.nutz.repo.org.objectweb.asm.commons.Method m) {
        GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
        mg.loadThis();
        mg.loadArgs();
        mg.invokeConstructor(parent, m);
        mg.returnValue();
        mg.endMethod();
    }

    public static class FallbackFastMethod implements FastMethod {

        public Method method;

        public Constructor<?> constructor;

        public FallbackFastMethod(Method method) {
            this.method = method;
            if (!this.method.isAccessible())
                this.method.setAccessible(true);
        }

        public FallbackFastMethod(Constructor<?> constructor) {
            this.constructor = constructor;
            if (!this.constructor.isAccessible())
                this.constructor.setAccessible(true);
        }

        public Object invoke(Object obj, Object... args) throws Exception {
            if (method == null)
                return constructor.newInstance(args);
            return method.invoke(obj, args);
        }

    }
}


package org.nutz.dao.jdbc;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import org.nutz.dao.DaoException;
import org.nutz.filepool.FilePool;
import org.nutz.filepool.NutFilePool;
import org.nutz.filepool.SynchronizedFilePool;
import org.nutz.lang.Mirror;
import org.nutz.lang.util.Disks;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;

public class JdbcExpertConfigFile {

    private Map<String, Class<? extends JdbcExpert>> experts;

    private Map<Pattern, Class<? extends JdbcExpert>> _experts;

    private Map<String, Object> config;

    private boolean isInit = false;

    private FilePool pool;

    private static final Log log = Logs.get();

    private Object lock = new Object();

    JdbcExpertConfigFile init() {
    	//文件池改为延迟加载
        return this;
    }

    public JdbcExpert getExpert(String str) {
        Class<? extends JdbcExpert> type = experts.get(str);
        return Mirror.me(type).born(config);
    }

    public JdbcExpert matchExpert(String dbName) {
        for (Entry<Pattern, Class<? extends JdbcExpert>> entry : _experts.entrySet()) {
            if (entry.getKey().matcher(dbName).find())
                return Mirror.me(entry.getValue()).born(this);
        }
        return null;
    }

    /**
     * 注意,返回的Map实例不允许被修改
     */
    public Map<String, Class<? extends JdbcExpert>> getExperts() {
        return Collections.unmodifiableMap(experts);
    }

    public Map<String, Object> getConfig() {
        return config;
    }

    public FilePool getPool() {
    	if (!isInit)
    		synchronized (lock) {
    			if (!isInit)
    				initFilePool();
    		}
        if (pool == null) {
            if (log.isWarnEnabled())
                log.warnf("NutDao FilePool create fail!! Blob and Clob Support is DISABLE!!");
            throw new DaoException("NutDao FilePool create fail!! Blob and Clob Support is DISABLE!!");
        }
        return pool;
    }

    // 在 fromJson 的时候，会被调用
    public void setExperts(Map<String, Class<? extends JdbcExpert>> experts) {
        this.experts = experts;
        this._experts = new LinkedHashMap<Pattern, Class<? extends JdbcExpert>>();
        for (Entry<String, Class<? extends JdbcExpert>> entry : experts.entrySet()) {
            //忽略大小写,并且让换行符与.能够匹配
            _experts.put(Pattern.compile(entry.getKey(), Pattern.DOTALL & Pattern.CASE_INSENSITIVE), entry.getValue());
        }
    }

    public void setConfig(Map<String, Object> config) {
        this.config = config;
    }

    public void setPool(FilePool pool) {
        this.pool = pool;
        isInit = true;
    }

    //初始化文件池，即使初始化失败,也继续执行
  	private void initFilePool() {
  		String home = config.get("pool-home").toString();
  		try {
  			home = Disks.normalize(home);
  			if (home == null)
  				home = config.get("pool-home").toString();
  			long max = config.containsKey("pool-max") ? ((Number) config.get("pool-max")).longValue() : 2000;
  			if (home.contains("${app.home}")) {
  				try {
  					// 这里引用了Mvcs类, 不太舒服,但应该还是有益处的
  					home = home.replace("${app.home}", Mvcs.getServletContext().getRealPath("/"));
  				} catch (Throwable e) {
  				}
  			}
  			try {
  				pool = NutFilePool.getOrCreatePool(home, max);
  			} catch (Exception e) {
  				// 看看是不是Mvc环境,尝试在WebContent下创建
  				if (!home.startsWith("~/") || Mvcs.getServletContext() == null)
  					throw e;
  				try {
  					String tmp = Mvcs.getServletContext().getRealPath("/") + home.substring(2);
  					pool = NutFilePool.getOrCreatePool(tmp, max);
  					log.info("had created filepool under webapp root path");
  				} catch (Exception e1) {
  					throw e; // 抛出原本的异常好了,哎...
  				}
  			}
  			pool = new SynchronizedFilePool(pool);
  		} catch (Throwable e) {
  			if (log.isWarnEnabled())
  				log.warnf("NutDao FilePool create fail!! Blob and Clob Support is DISABLE!! Home=" + home, e);
  		}
  		isInit = true;
  	}
}


package org.nutz.dao.impl.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.nutz.dao.Dao;
import org.nutz.dao.DaoException;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.entity.EntityField;
import org.nutz.dao.entity.EntityIndex;
import org.nutz.dao.entity.LinkField;
import org.nutz.dao.entity.MappingField;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.PK;
import org.nutz.dao.impl.entity.field.ManyManyLinkField;
import org.nutz.dao.impl.entity.macro.SqlFieldMacro;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.dao.jdbc.JdbcExpertConfigFile;
import org.nutz.dao.jdbc.Jdbcs;
import org.nutz.dao.jdbc.ValueAdaptor;
import org.nutz.dao.sql.DaoStatement;
import org.nutz.dao.sql.Pojo;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlContext;
import org.nutz.dao.sql.SqlType;
import org.nutz.dao.util.Daos;
import org.nutz.lang.Configurable;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;
import org.nutz.lang.segment.CharSegment;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;

/**
 * 对于所有数据库的抽象实现
 *
 * @author zozoh(zozohtnt@gmail.com)
 */
public abstract class AbstractJdbcExpert implements JdbcExpert, Configurable {

    private static final Log log = Logs.get();

    private static String DEFAULT_COMMENT_TABLE = "comment on table $table is '$tableComment'";

    private static String DEFAULT_COMMENT_COLUMN = "comment on column $table.$column is '$columnComment'";

    protected Set<String> keywords;

    /**
     * 提供给子类使用的配置文件对象
     */
    protected JdbcExpertConfigFile conf;

    // ====================================================================
    // 构造函数：子类需要将重载
    public AbstractJdbcExpert(JdbcExpertConfigFile conf) {
        this.conf = conf;
    }

    // ====================================================================
    // 下面为子类默认实现几个接口函数

    public void setupEntityField(Connection conn, Entity<?> en) {
        List<MappingField> mfs = new ArrayList<MappingField>();
        for (MappingField mf : en.getMappingFields()) {
            if (mf.getTypeMirror().isEnum()) {
                mfs.add(mf);
            }
        }
        if (mfs.isEmpty())
            return;
        Statement stat = null;
        ResultSet rs = null;
        ResultSetMetaData rsmd = null;
        try {
            // 获取数据库元信息
            stat = conn.createStatement();
            rs = stat.executeQuery(createResultSetMetaSql(en));
            rsmd = rs.getMetaData();
            // 循环字段检查
            List<String> columnNames = new ArrayList<String>();
            List<String> columnLabels = new ArrayList<String>();
            int columnCount = rsmd.getColumnCount();
            for (int i = 1; i <= columnCount; i++) {
                columnNames.add(rsmd.getColumnName(i));
                columnLabels.add(rsmd.getColumnLabel(i));
            }
            for (MappingField mf : mfs) {
                try {
                    int ci = columnNames.indexOf(mf.getColumnName()) + 1;
                    if (ci == 0) {
                        log.debugf("Can not find @Column(%s) in table/view (%s), skip checking", mf.getColumnName(), rsmd.getTableName(1));
                        continue;
                    }
                    // 枚举类型在数据库中的值
                    if (Daos.isIntLikeColumn(rsmd, ci)) {
                        mf.setColumnType(ColType.INT);
                    } else {
                        mf.setColumnType(ColType.VARCHAR);
                    }
                }
                catch (Exception e) {
                }
            }
        }
        catch (Exception e) {
            if (log.isDebugEnabled())
                log.debugf("Table '%s' doesn't exist! class=%s", en.getViewName(), en.getType().getName());
        }
        // Close ResultSet and Statement
        finally {
            Daos.safeClose(stat, rs);
        }
    }

    public ValueAdaptor getAdaptor(MappingField ef) {
        Mirror<?> mirror = ef.getTypeMirror();
        // 为数字型枚举的特殊判断
        if (mirror.isEnum() && ColType.INT == ef.getColumnType())
            return Jdbcs.Adaptor.asEnumInt;
        // 用普通逻辑返回适配器
        return Jdbcs.getAdaptor(mirror);
    }

    public Pojo createPojo(SqlType type) {
        return new NutPojo().setSqlType(type);
    }

    public boolean dropEntity(Dao dao, Entity<?> en) {
        String tableName = en.getTableName();
        String viewName = en.getViewName();

        try {
            dropRelation(dao, en);
            if (!tableName.equals(viewName) && dao.exists(viewName)) {
                dao.execute(Sqls.create("DROP VIEW " + viewName));
            }
            dao.execute(Sqls.create("DROP TABLE " + tableName));
        }
        catch (Exception e) {
            return false;
        }
        return true;
    }

    public Map<String, Object> getConf() {
        return this.conf.getConfig();
    }

    // ====================================================================
    // 下面是提供给子类使用的一些帮助函数

    protected String createResultSetMetaSql(Entity<?> en) {
        return "SELECT * FROM " + en.getViewName() + " where 1!=1";
    }

    public void createRelation(Dao dao, Entity<?> en) {
        final List<Sql> sqls = new ArrayList<Sql>(5);
        for (LinkField lf : en.visitManyMany(null, null, null)) {
            Sql sql = createRelation(dao, lf);
            if (sql != null)
                sqls.add(sql);
        }
        dao.execute(sqls.toArray(new Sql[sqls.size()]));
    }

    protected Sql createRelation(Dao dao, LinkField lf) {
        ManyManyLinkField mm = (ManyManyLinkField) lf;
        if (dao.exists(mm.getRelationName()))
            return null;
        String sql = "CREATE TABLE " + mm.getRelationName() + "(" + "\n";
        sql += mm.getFromColumnName() + " " + evalFieldType(mm.getHostField()) + "," + "\n";
        sql += mm.getToColumnName() + " " + evalFieldType(mm.getLinkedField()) + "\n";
        sql += ")";
        return Sqls.create(sql);
    }

    public void dropRelation(Dao dao, Entity<?> en) {
        final List<Sql> sqls = new ArrayList<Sql>(5);
        for (LinkField lf : en.visitManyMany(null, null, null)) {
            ManyManyLinkField mm = (ManyManyLinkField) lf;
            if (!dao.exists(mm.getRelationName()))
                continue;
            sqls.add(Sqls.create("DROP TABLE " + mm.getRelationName()));
        }
        dao.execute(sqls.toArray(new Sql[sqls.size()]));
    }

    public String evalFieldType(MappingField mf) {
        if (mf.getCustomDbType() != null)
            return mf.getCustomDbType();
        switch (mf.getColumnType()) {
        case CHAR:
            return "CHAR(" + mf.getWidth() + ")";

        case BOOLEAN:
            return "BOOLEAN";

        case VARCHAR:
            return "VARCHAR(" + mf.getWidth() + ")";

        case TEXT:
            return "TEXT";

        case BINARY:
            return "BLOB";

        case TIMESTAMP:
            return "TIMESTAMP";

        case DATETIME:
            return "DATETIME";

        case DATE:
            return "DATE";
        case TIME:
            return "TIME";

        case INT:
            // 用户自定义了宽度
            if (mf.getWidth() > 0)
                return "INT(" + mf.getWidth() + ")";
            // 用数据库的默认宽度
            return "INT";

        case FLOAT:
            // 用户自定义了精度
            if (mf.getWidth() > 0 && mf.getPrecision() > 0) {
                return "NUMERIC(" + mf.getWidth() + "," + mf.getPrecision() + ")";
            }
            // 用默认精度
            if (mf.getTypeMirror().isDouble())
                return "NUMERIC(15,10)";
            return "FLOAT";

        case PSQL_ARRAY:
            return "ARRAY";

        case PSQL_JSON:
        case MYSQL_JSON:
            return "JSON";
        default:
            throw Lang.makeThrow("Unsupport colType '%s' of field '%s' in '%s' ",
                             mf.getColumnType(),
                             mf.getName(),
                             mf.getEntity().getType().getName());
        }
    }

    protected static List<DaoStatement> wrap(String... sqls) {
        List<DaoStatement> sts = new ArrayList<DaoStatement>(sqls.length);
        for (String sql : sqls)
            if (!Strings.isBlank(sql))
                sts.add(Sqls.create(sql));
        return sts;
    }

    protected static List<DaoStatement> wrap(List<String> sqls) {
        List<DaoStatement> sts = new ArrayList<DaoStatement>(sqls.size());
        for (String sql : sqls)
            if (!Strings.isBlank(sql))
                sts.add(Sqls.create(sql));
        return sts;
    }

    protected static String gSQL(String ptn, String table, String field) {
        CharSegment cs = new CharSegment(ptn);
        cs.set("T", table).set("F", field);
        return cs.toString();
    }

    protected String getDefaultValue(MappingField mf) {
        return mf.getDefaultValue(null).replaceAll("@", "@@");
    }

    protected List<Sql> createIndexs(Entity<?> en) {
        List<Sql> sqls = new ArrayList<Sql>();
        for (EntityIndex index : en.getIndexes()) {
            sqls.add(createIndexSql(en, index));
        }
        return sqls;
    }

    public Sql createIndexSql(Entity<?> en, EntityIndex index) {
        StringBuilder sb = new StringBuilder();
        if (index.isUnique())
            sb.append("Create UNIQUE Index ");
        else
            sb.append("Create Index ");
        sb.append(index.getName(en));
        sb.append(" ON ").append(en.getTableName()).append("(");
        for (EntityField field : index.getFields()) {
            if (field instanceof MappingField) {
                MappingField mf = (MappingField) field;
                sb.append(mf.getColumnNameInSql()).append(',');
            } else {
                throw Lang.makeThrow(DaoException.class,
                                     "%s %s is NOT a mapping field, can't use as index field!!",
                                     en.getClass(),
                                     field.getName());
            }
        }
        sb.setCharAt(sb.length() - 1, ')');
        return Sqls.create(sb.toString());
    }

    public void addComment(Dao dao, Entity<?> en) {
        addComment(dao, en, null, null);
    }

    public void addComment(Dao dao, Entity<?> en, String commentTable, String commentColumn) {
        if (!en.hasTableComment() && !en.hasColumnComment()) {
            return;
        }
        List<Sql> sqls = new ArrayList<Sql>();
        // 表注释
        if (en.hasTableComment()) {
            Sql tableCommentSQL = Sqls.create(Strings.isBlank(commentTable) ? DEFAULT_COMMENT_TABLE
                                                                            : commentTable);
            tableCommentSQL.vars().set("table", en.getTableName()).set("tableComment",
                                                                       en.getTableComment());
            sqls.add(tableCommentSQL);
        }
        // 字段注释
        if (en.hasColumnComment()) {
            for (MappingField mf : en.getMappingFields()) {
                if (mf.hasColumnComment() && !mf.isReadonly()) {
                    Sql columnCommentSQL = Sqls.create(Strings.isBlank(commentColumn) ? DEFAULT_COMMENT_COLUMN
                                                                                : commentColumn);
                    columnCommentSQL.vars()
                                    .set("table", en.getTableName())
                                    .set("column", mf.getColumnNameInSql())
                                    .set("columnComment", mf.getColumnComment());
                    sqls.add(columnCommentSQL);
                }
            }
        }
        // 执行创建语句
        dao.execute(sqls.toArray(new Sql[sqls.size()]));
    }

    public void formatQuery(DaoStatement daoStatement) {
        if (daoStatement == null)
            return;
        SqlContext ctx = daoStatement.getContext();
        if (ctx == null || ctx.getPager() == null)
            return;
        if (daoStatement instanceof Pojo)
            formatQuery((Pojo) daoStatement);
        else if (daoStatement instanceof Sql)
            formatQuery((Sql) daoStatement);
        else
            throw Lang.noImplement();
    }

    public abstract void formatQuery(Pojo pojo);

    public void formatQuery(Sql sql) {
        throw Lang.noImplement();
    }

    public Pojo fetchPojoId(Entity<?> en, MappingField idField) {
        String autoSql = "SELECT MAX($field) AS $field FROM $view";
        Pojo autoInfo = new SqlFieldMacro(idField, autoSql);
        autoInfo.setEntity(en);
        return autoInfo;
    }

    public boolean isSupportAutoIncrement() {
        return true;
    }

    public String makePksName(Entity<?> en) {
        String name = en.getType().getAnnotation(PK.class).name();
        if (Strings.isBlank(name)) {
            StringBuilder sb = new StringBuilder();
            for (MappingField mf : en.getPks()) {
                sb.append("_").append(mf.getColumnName());
            }
            sb.setLength(sb.length() - 1);
            return sb.toString();
        }
        return name;
    }

    public void addDefaultValue(StringBuilder sb, MappingField mf) {
        if (!mf.hasDefaultValue())
            return;
        String dft = getDefaultValue(mf);
        if (mf.getColumnType() == ColType.VARCHAR
                || mf.getTypeMirror().isStringLike())
            sb.append(" DEFAULT '").append(dft).append('\'');
        else
            sb.append(" DEFAULT ").append(dft);
    }

    public boolean addColumnNeedColumn() {
        return true;
    }

    public boolean supportTimestampDefault() {
        return true;
    }

    public void setKeywords(Set<String> keywords) {
        this.keywords = keywords;
    }

    public Set<String> getKeywords() {
        return keywords;
    }

    public String wrapKeywork(String columnName, boolean force) {
        if (force || keywords.contains(columnName.toUpperCase()))
            return "`" + columnName + "`";
        return null;
    }

    public boolean isSupportGeneratedKeys() {
        return true;
    }

    public void checkDataSource(Connection conn) throws SQLException {}

    @Override
    public Sql createAddColumnSql(Entity<?> en, MappingField mf) {
        StringBuilder sb = new StringBuilder("ALTER TABLE ");
        sb.append(en.getTableName()).append(" ADD ");
        if (addColumnNeedColumn())
            sb.append("COLUMN ");
        sb.append(mf.getColumnNameInSql()).append(" ").append(evalFieldType(mf));
        if (mf.isUnsigned()) {
            sb.append(" UNSIGNED");
        }
        if (mf.isNotNull()) {
            sb.append(" NOT NULL");
        }
        if (mf.getColumnType() == ColType.TIMESTAMP && supportTimestampDefault()) {
            if (mf.hasDefaultValue()) {
                sb.append(" ").append(mf.getDefaultValue(null).replaceAll("@", "@@"));
            } else {
                if (mf.isNotNull()) {
                    sb.append(" DEFAULT 0");
                } else {
                    sb.append(" NULL DEFAULT NULL");
                }
            }
        } else {
            if (mf.hasDefaultValue())
                addDefaultValue(sb, mf);
        }
        if (mf.hasColumnComment() && canCommentWhenAddIndex()) {
            sb.append(" COMMENT '").append(mf.getColumnComment()).append("'");
        }
        // sb.append(';');
        return Sqls.create(sb.toString());
    }

    public boolean canCommentWhenAddIndex() {
        return false;
    }

    @Override
    public List<String> getIndexNames(Entity<?> en, Connection conn) throws SQLException {
        List<String> names = new ArrayList<String>();
        String showIndexs = "show index from " + en.getTableName();
        PreparedStatement ppstat = conn.prepareStatement(showIndexs);
        ResultSet rest = ppstat.executeQuery();
        while (rest.next()) {
            String index = rest.getString(3);
            names.add(index);
        }
        return names;
    }

    public void setupProperties(NutMap conf) {
    }
}


package org.nutz.service;

import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.EntityField;

/**
 * 针对标注了@Id和@的实体类的Service
 * @author wendal(wendal1985@gmail.com)
 *
 * @param <T> 实体类的类型
 */
public abstract class IdNameEntityService<T> extends IdEntityService<T> {

    /**
     * @see IdEntityService
     * @see NameEntityService
     */
    public IdNameEntityService() {
        super();
    }

    /**
     * @see IdEntityService
     * @see NameEntityService
     */
    public IdNameEntityService(Dao dao) {
        super(dao);
    }

    /**
     * @see IdEntityService
     * @see NameEntityService
     */
    public IdNameEntityService(Dao dao, Class<T> entityType) {
        super(dao, entityType);
    }

    /**
     * 根据@Name所标注的属性的值进行删除
     * @param name 属性的值
     * @return 删除的记录数,通常为1或0
     */
    public int delete(String name) {
        return dao().delete(getEntityClass(), name);
    }

    /**
     * 根据@Name所标注的属性的值,获取一个实体
     * @param name 属性的值
     * @return 实体,如不存在则返回null
     */
    public T fetch(String name) {
        return dao().fetch(getEntityClass(), name);
    }

    /**
     * 智能获取一个实体,如str能转为Long类型,则调用fetch(long id),否则调用fetch(String name)
     * @param str 非空的字符串,可以是整数或普通字符串
     * @return 符合条件的记录,如不存在则返回null
     */
    public T smartFetch(String str) {
        try {
            long id = Long.parseLong(str);
            return fetch(id);
        }
        catch (Exception e) {}
        return fetch(str);
    }

    /**
     * 是否存在符合条件的记录,需要实体有@Name标注
     * @param name 属性的值
     * @return true,如果存在的话.
     */
    public boolean exists(String name) {
        EntityField ef = getEntity().getNameField();
        if (null == ef)
            return false;
        return dao().count(getEntityClass(), Cnd.where(ef.getName(), "=", name)) > 0;
    }
}