package org.nutz.lang;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.nutz.lang.util.Callback;
import org.nutz.lang.util.ClassTools;
import org.nutz.lang.util.Disks;
import org.nutz.lang.util.Regex;
import org.nutz.log.Logs;

/**
 * 文件操作的帮助函数
 *
 * @author amos(amosleaf@gmail.com)
 * @author zozoh(zozohtnt@gmail.com)
 * @author wendal(wendal1985@gmail.com)
 * @author bonyfish(mc02cxj@gmail.com)
 */
public class Files {

    /**
     * 读取 UTF-8 文件全部内容
     *
     * @param path
     *            文件路径
     * @return 文件内容
     */
    public static String read(String path) {
        File f = Files.findFile(path);
        if (null == f)
            throw Lang.makeThrow("Can not find file '%s'", path);
        return read(f);
    }

    /**
     * 读取 UTF-8 文件全部内容
     *
     * @param f
     *            文件
     * @return 文件内容
     */
    public static String read(File f) {
        return Lang.readAll(Streams.fileInr(f));
    }

    /**
     * 读取文件全部字节，并关闭文件
     *
     * @param path
     *            文件路径
     * @return 文件的字节内容
     */
    public static byte[] readBytes(String path) {
        File f = Files.findFile(path);
        if (null == f)
            throw Lang.makeThrow("Can not find file '%s'", path);
        return readBytes(f);
    }

    /**
     * 读取文件全部字节，并关闭文件
     *
     * @param f
     *            文件
     * @return 文件的字节内容
     */
    public static byte[] readBytes(File f) {
        return Streams.readBytesAndClose(Streams.buff(Streams.fileIn(f)));
    }

    /**
     * 将内容写到一个文件内，内容对象可以是：
     *

     *
InputStream - 按二进制方式写入
     *
byte[] - 按二进制方式写入
     *
Reader - 按 UTF-8 方式写入
     *
其他对象被 toString() 后按照 UTF-8 方式写入
     *

     *
     * @param path
     *            文件路径，如果不存在，则创建
     * @param obj
     *            内容对象
     */
    public static void write(String path, Object obj) {
        if (null == path || null == obj)
            return;
        try {
            write(Files.createFileIfNoExists(path), obj);
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 将内容写到一个文件内，内容对象可以是：
     *
     *

     *
InputStream - 按二进制方式写入
     *
byte[] - 按二进制方式写入
     *
Reader - 按 UTF-8 方式写入
     *
其他对象被 toString() 后按照 UTF-8 方式写入
     *

     *
     * @param f
     *            文件
     * @param obj
     *            内容
     */
    public static void write(File f, Object obj) {
        if (null == f || null == obj)
            return;
        if (f.isDirectory())
            throw Lang.makeThrow("Directory '%s' can not be write as File", f);

        try {
            // 保证文件存在
            if (!f.exists())
                Files.createNewFile(f);
            // 输入流
            if (obj instanceof InputStream) {
                Streams.writeAndClose(Streams.fileOut(f), (InputStream) obj);
            }
            // 字节数组
            else if (obj instanceof byte[]) {
                Streams.writeAndClose(Streams.fileOut(f), (byte[]) obj);
            }
            // 文本输入流
            else if (obj instanceof Reader) {
                Streams.writeAndClose(Streams.fileOutw(f), (Reader) obj);
            }
            // 其他对象
            else {
                Streams.writeAndClose(Streams.fileOutw(f), obj.toString());
            }
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 将内容写到一个文件末尾
     *

     *
InputStream - 按二进制方式写入
     *
byte[] - 按二进制方式写入
     *
Reader - 按 UTF-8 方式写入
     *
其他对象被 toString() 后按照 UTF-8 方式写入
     *

     *
     * @param f
     *            文件
     * @param obj
     *            内容
     */
    public static void appendWrite(File f, Object obj) {
        if (null == f || null == obj)
            return;
        if (f.isDirectory())
            throw Lang.makeThrow("Directory '%s' can not be write as File", f);

        try {
            // 保证文件存在
            if (!f.exists())
                Files.createNewFile(f);
            // 输入流
            if (obj instanceof InputStream) {
                // TODO
                throw Lang.noImplement();
            }
            // 字节数组
            else if (obj instanceof byte[]) {
                // TODO
                throw Lang.noImplement();
            }
            // 文本输入流
            else if (obj instanceof Reader) {
                // TODO
                throw Lang.noImplement();
            }
            // 其他对象
            else {
                Streams.appendWriteAndClose(f, obj.toString());
            }
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 将文件后缀改名，从而生成一个新的文件对象。但是并不在磁盘上创建它
     *
     * @param f
     *            文件
     * @param suffix
     *            新后缀， 比如 ".gif" 或者 ".jpg"
     * @return 新文件对象
     */
    public static File renameSuffix(File f, String suffix) {
        if (null == f || null == suffix || suffix.length() == 0)
            return f;
        return new File(renameSuffix(f.getAbsolutePath(), suffix));
    }

    /**
     * 将文件路径后缀改名，从而生成一个新的文件路径。
     *
     * @param path
     *            文件路径
     * @param suffix
     *            新后缀， 比如 ".gif" 或者 ".jpg"
     * @return 新文件后缀
     */
    public static String renameSuffix(String path, String suffix) {
        int pos = path.length();
        for (--pos; pos > 0; pos--) {
            if (path.charAt(pos) == '.')
                break;
            if (path.charAt(pos) == '/' || path.charAt(pos) == '\\') {
                pos = -1;
                break;
            }
        }
        if (0 >= pos)
            return path + suffix;
        return path.substring(0, pos) + suffix;
    }

    /**
     * 获取文件主名。 即去掉后缀的名称
     *
     * @param path
     *            文件路径
     * @return 文件主名
     */
    public static String getMajorName(String path) {
        int len = path.length();
        int l = 0;
        int r = len;
        for (int i = r - 1; i > 0; i--) {
            if (r == len)
                if (path.charAt(i) == '.') {
                    r = i;
                }
            if (path.charAt(i) == '/' || path.charAt(i) == '\\') {
                l = i + 1;
                break;
            }
        }
        return path.substring(l, r);
    }

    /**
     * 获取文件主名。 即去掉后缀的名称
     *
     * @param f
     *            文件
     * @return 文件主名
     */
    public static String getMajorName(File f) {
        return getMajorName(f.getAbsolutePath());
    }

    /**
     * @see #getSuffixName(String)
     */
    public static String getSuffixName(File f) {
        if (null == f)
            return null;
        return getSuffixName(f.getAbsolutePath());
    }

    /**
     * 获取文件后缀名，不包括 '.'，如 'abc.gif','，则返回 'gif'
     *
     * @param path
     *            文件路径
     * @return 文件后缀名
     */
    public static String getSuffixName(String path) {
        if (null == path)
            return null;
        int p0 = path.lastIndexOf('.');
        int p1 = path.lastIndexOf('/');
        if (-1 == p0 || p0 < p1)
            return "";
        return path.substring(p0 + 1);
    }

    /**
     * @see #getSuffix(String)
     */
    public static String getSuffix(File f) {
        if (null == f)
            return null;
        return getSuffix(f.getAbsolutePath());
    }

    /**
     * 获取文件后缀名，包括 '.'，如 'abc.gif','，则返回 '.gif'
     *
     * @param path
     *            文件路径
     * @return 文件后缀
     */
    public static String getSuffix(String path) {
        if (null == path)
            return null;
        int p0 = path.lastIndexOf('.');
        int p1 = path.lastIndexOf('/');
        if (-1 == p0 || p0 < p1)
            return "";
        return path.substring(p0);
    }

    /**
     * 根据正则式，从压缩文件中获取文件
     *
     * @param zip
     *            压缩文件
     * @param regex
     *            正则式，用来匹配文件名
     * @return 数组
     */
    public static ZipEntry[] findEntryInZip(ZipFile zip, String regex) {
        List<ZipEntry> list = new LinkedList<ZipEntry>();
        Enumeration<? extends ZipEntry> en = zip.entries();
        while (en.hasMoreElements()) {
            ZipEntry ze = en.nextElement();
            if (null == regex || Regex.match(regex, ze.getName()))
                list.add(ze);
        }
        return list.toArray(new ZipEntry[list.size()]);
    }

    /**
     * 试图生成一个文件对象，如果文件不存在则创建它。 如果给出的 PATH 是相对路径 则会在 CLASSPATH
     * 中寻找，如果未找到，则会在用户主目录中创建这个文件
     *
     * @param path
     *            文件路径，可以以 ~ 开头，也可以是 CLASSPATH 下面的路径
     * @return 文件对象
     * @throws IOException
     *             创建失败
     */
    public static File createFileIfNoExists(String path) throws IOException {
        String thePath = Disks.absolute(path);
        if (null == thePath)
            thePath = Disks.normalize(path);
        File f = new File(thePath);
        if (!f.exists())
            Files.createNewFile(f);
        if (!f.isFile())
            throw Lang.makeThrow("'%s' should be a file!", path);
        return f;
    }

    public static File createFileIfNoExists2(String path) {
        try {
            return createFileIfNoExists(path);
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 如果文件对象不存在，则创建它
     *
     * @param f
     *            文件对象
     * @return 传入的文件对象，以便为调用者省略一行代码
     */
    public static File createFileIfNoExists(File f) {
        if (null == f)
            return f;
        if (!f.exists())
            try {
                Files.createNewFile(f);
            }
            catch (IOException e) {
                throw Lang.wrapThrow(e);
            }
        if (!f.isFile())
            throw Lang.makeThrow("'%s' should be a file!", f);
        return f;
    }

    /**
     * 试图生成一个目录对象，如果文件不存在则创建它。 如果给出的 PATH 是相对路径 则会在 CLASSPATH
     * 中寻找，如果未找到，则会在用户主目录中创建这个目录
     *
     * @param path
     *            文件路径，可以以 ~ 开头，也可以是 CLASSPATH 下面的路径
     * @return 文件对象
     */
    public static File createDirIfNoExists(String path) {
        String thePath = Disks.absolute(path);
        if (null == thePath)
            thePath = Disks.normalize(path);
        File f = new File(thePath);
        if (!f.exists()) {
            boolean flag = Files.makeDir(f);
            if (!flag) {
                Logs.get().warnf("create filepool dir(%s) fail!!", f.getPath());
            }
        }
        if (!f.isDirectory())
            throw Lang.makeThrow("'%s' should be a directory or don't have permission to create it!", path);
        return f;
    }

    /**
     * 传入一个目录对象，如果目录不存在，则创建目录
     *
     * @param d
     *            文件目录对象
     * @return 文件目录对象，以便调用者省略一行代码
     */
    public static File createDirIfNoExists(File d) {
        if (null == d)
            return d;
        if (!d.exists()) {
            if (!Files.makeDir(d)) {
                throw Lang.makeThrow("fail to create '%s', permission deny?", d.getAbsolutePath());
            }
        }
        if (!d.isDirectory())
            throw Lang.makeThrow("'%s' should be a directory!", d);
        return d;
    }

    /**
     * 从 CLASSPATH 下或从指定的本机器路径下寻找一个文件
     *
     * @param path
     *            文件路径
     * @param klassLoader
     *            参考 ClassLoader
     * @param enc
     *            文件路径编码
     *
     * @return 文件对象，如果不存在，则为 null
     */
    public static File findFile(String path, ClassLoader klassLoader, String enc) {
        path = Disks.absolute(path, klassLoader, enc);
        if (null == path)
            return null;
        return new File(path);
    }

    /**
     * 从 CLASSPATH 下或从指定的本机器路径下寻找一个文件
     *
     * @param path
     *            文件路径
     * @param enc
     *            文件路径编码
     * @return 文件对象，如果不存在，则为 null
     */
    public static File findFile(String path, String enc) {
        return findFile(path, ClassTools.getClassLoader(), enc);
    }

    /**
     * 从 CLASSPATH 下或从指定的本机器路径下寻找一个文件
     *
     * @param path
     *            文件路径
     * @param klassLoader
     *            使用该 ClassLoader进行查找
     *
     * @return 文件对象，如果不存在，则为 null
     */
    public static File findFile(String path, ClassLoader klassLoader) {
        return findFile(path, klassLoader, Encoding.defaultEncoding());
    }

    /**
     * each 函数的参数类型
     */
    public enum LsMode {
        /**
         * 仅文件
         */
        FILE, /**
               * 仅目录
               */
        DIR, /**
              * 文件和目录
              */
        ALL
    }

    /**
     * 在一个目录里列出所有的子文件或者目录
     *
     * @param d
     *            目录
     * @param p
     *            正则表达式对象，如果为空，则是全部正则表达式
     * @param exclude
     *            true 正则表达式匹配的文件会被忽略，false 正则表达式匹配的文件会被包含
     * @param mode
     *            请参看 LsMode 枚举类说明, null 表示 LsMode.ALL
     *
     * @return 得到文件对象数组
     * @see LsMode
     */
    public static File[] ls(File d, final Pattern p, final boolean exclude, LsMode mode) {
        if (null == p) {
            return d.listFiles();
        }
        // 全部
        else if (null == mode || LsMode.ALL == mode) {
            return d.listFiles(new FileFilter() {
                public boolean accept(File f) {
                    return p.matcher(f.getName()).find() ^ exclude;
                }
            });
        }
        // 仅文件
        else if (LsMode.FILE == mode) {
            return d.listFiles(new FileFilter() {
                public boolean accept(File f) {
                    if (!f.isFile())
                        return false;
                    return p.matcher(f.getName()).find() ^ exclude;
                }
            });
        }
        // 仅目录
        else if (LsMode.DIR == mode) {
            return d.listFiles(new FileFilter() {
                public boolean accept(File f) {
                    if (!f.isDirectory())
                        return false;
                    return p.matcher(f.getName()).find() ^ exclude;
                }
            });
        }
        // 不可能
        throw Lang.impossible();
    }

    /**
     * 列文件
     *
     * @param d
     *            目录对象
     * @param regex
     *            正则表达式
     * @param mode
     *            模式
     * @return 文件列表对象
     * @see #ls(File, Pattern, boolean, LsMode)
     */
    public static File[] ls(File d, String regex, LsMode mode) {
        boolean exclude = false;
        Pattern p = null;
        if (!Strings.isBlank(regex)) {
            exclude = regex.startsWith("!");
            if (exclude) {
                regex = Strings.trim(regex.substring(1));
            }
            p = Pattern.compile(regex);
        }
        return ls(d, p, exclude, mode);
    }

    /**
     * @see #ls(File, String, LsMode)
     */
    public static File[] ls(String path, String regex, LsMode mode) {
        return ls(checkFile(path), regex, mode);
    }

    /**
     * @see #ls(File, String, LsMode)
     */
    public static File[] lsFile(File d, String regex) {
        return ls(d, regex, LsMode.FILE);
    }

    /**
     * @see #ls(String, String, LsMode)
     */
    public static File[] lsFile(String path, String regex) {
        return ls(path, regex, LsMode.FILE);
    }

    /**
     * @see #ls(File, String, LsMode)
     */
    public static File[] lsDir(File d, String regex) {
        return ls(d, regex, LsMode.DIR);
    }

    /**
     * @see #ls(String, String, LsMode)
     */
    public static File[] lsDir(String path, String regex) {
        return ls(path, regex, LsMode.DIR);
    }

    /**
     * @see #ls(File, String, LsMode)
     */
    public static File[] lsAll(File d, String regex) {
        return ls(d, regex, LsMode.ALL);
    }

    /**
     * @see #ls(String, String, LsMode)
     */
    public static File[] lsAll(String path, String regex) {
        return ls(path, regex, LsMode.ALL);
    }

    /**
     * 从 CLASSPATH 下或从指定的本机器路径下寻找一个文件
     *
     * @param path
     *            文件路径
     *
     * @return 文件对象，如果不存在，则为 null
     */
    public static File findFile(String path) {
        return findFile(path, ClassTools.getClassLoader(), Encoding.defaultEncoding());
    }

    /**
     * 从 CLASSPATH 下或从指定的本机器路径下寻找一个文件
     *
     * @param path
     *            文件路径
     *
     * @return 文件对象，如果不存在，则抛出一个运行时异常
     */
    public static File checkFile(String path) {
        File f = findFile(path);
        if (null == f)
            throw Lang.makeThrow("Fail to found file '%s'", path);
        return f;
    }

    /**
     * 获取输出流
     *
     * @param path
     *            文件路径
     * @param klass
     *            参考的类， -- 会用这个类的 ClassLoader
     * @param enc
     *            文件路径编码
     *
     * @return 输出流
     */
    public static InputStream findFileAsStream(String path, Class<?> klass, String enc) {
        File f = new File(path);
        if (f.exists())
            try {
                return new FileInputStream(f);
            }
            catch (FileNotFoundException e1) {
                return null;
            }
        if (null != klass) {
            InputStream ins = klass.getClassLoader().getResourceAsStream(path);
            if (null == ins)
                ins = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
            if (null != ins)
                return ins;
        }
        return ClassLoader.getSystemResourceAsStream(path);
    }

    /**
     * 获取输出流
     *
     * @param path
     *            文件路径
     * @param enc
     *            文件路径编码
     *
     * @return 输出流
     */
    public static InputStream findFileAsStream(String path, String enc) {
        return findFileAsStream(path, Files.class, enc);
    }

    /**
     * 获取输出流
     *
     * @param path
     *            文件路径
     * @param klass
     *            参考的类， -- 会用这个类的 ClassLoader
     *
     * @return 输出流
     */
    public static InputStream findFileAsStream(String path, Class<?> klass) {
        return findFileAsStream(path, klass, Encoding.defaultEncoding());
    }

    /**
     * 获取输出流
     *
     * @param path
     *            文件路径
     *
     * @return 输出流
     */
    public static InputStream findFileAsStream(String path) {
        return findFileAsStream(path, Files.class, Encoding.defaultEncoding());
    }

    /**
     * 文件对象是否是目录，可接受 null
     */
    public static boolean isDirectory(File f) {
        if (null == f)
            return false;
        if (!f.exists())
            return false;
        if (!f.isDirectory())
            return false;
        return true;
    }

    /**
     * 文件对象是否是文件，可接受 null
     */
    public static boolean isFile(File f) {
        return null != f && f.exists() && f.isFile();
    }

    /**
     * 创建新文件，如果父目录不存在，也一并创建。可接受 null 参数
     *
     * @param f
     *            文件对象
     * @return false，如果文件已存在。 true 创建成功
     * @throws IOException
     */
    public static boolean createNewFile(File f) throws IOException {
        if (null == f || f.exists())
            return false;
        makeDir(f.getParentFile());
        return f.createNewFile();
    }

    /**
     * 创建新目录，如果父目录不存在，也一并创建。可接受 null 参数
     *
     * @param dir
     *            目录对象
     * @return false，如果目录已存在。 true 创建成功
     * @throws IOException
     */
    public static boolean makeDir(File dir) {
        if (null == dir || dir.exists())
            return false;
        return dir.mkdirs();
    }

    /**
     * 强行删除一个目录，包括这个目录下所有的子目录和文件
     *
     * @param dir
     *            目录
     * @return 是否删除成功
     */
    public static boolean deleteDir(File dir) {
        if (null == dir || !dir.exists())
            return false;
        if (!dir.isDirectory())
            throw new RuntimeException("\"" + dir.getAbsolutePath() + "\" should be a directory!");
        File[] files = dir.listFiles();
        boolean re = false;
        if (null != files) {
            if (files.length == 0)
                return dir.delete();
            for (File f : files) {
                if (f.isDirectory())
                    re |= deleteDir(f);
                else
                    re |= deleteFile(f);
            }
            re |= dir.delete();
        }
        return re;
    }

    /**
     * 删除一个文件
     *
     * @param f
     *            文件
     * @return 是否删除成功
     * @throws IOException
     */
    public static boolean deleteFile(File f) {
        if (null == f)
            return false;
        return f.delete();
    }

    /**
     * 清除一个目录里所有的内容
     *
     * @param dir
     *            目录
     * @return 是否清除成功
     */
    public static boolean clearDir(File dir) {
        if (null == dir)
            return false;
        if (!dir.exists())
            return false;
        File[] fs = dir.listFiles();
        if (fs != null) {
            for (File f : fs) {
                if (f.isFile())
                    Files.deleteFile(f);
                else if (f.isDirectory())
                    Files.deleteDir(f);
            }
        }
        return true;
    }

    /**
     * 相当于 copyFile(src,target,-1)
     *
     * @see #copyFile(File, File, long)
     */
    public static boolean copyFile(File src, File target) throws IOException {
        return copyFile(src, target, -1);
    }

    /**
     * 将一个文件 copy 一部分（或者全部）到另外一个文件。如果目标文件不存在，创建它先。
     *
     * @param src
     *            源文件
     * @param target
     *            目标文件
     * @param count
     *            要 copy 的字节数，0 表示什么都不 copy， -1 表示 copy 全部数据
     * @return 是否成功
     * @throws IOException
     */
    public static boolean copyFile(File src, File target, long count) throws IOException {
        if (src == null || target == null || !src.exists())
            return false;
        if (!target.exists())
            if (!createNewFile(target))
                return false;

        // 0 字节？ 那就啥都不做咯
        if (count == 0)
            return true;

        FileInputStream ins = null;
        FileOutputStream ops = null;
        FileChannel in = null;
        FileChannel out = null;

        try {
            ins = new FileInputStream(src);
            ops = new FileOutputStream(target);
            in = ins.getChannel();
            out = ops.getChannel();

            long maxCount = in.size();
            if (count < 0 || count > maxCount)
                count = maxCount;

            in.transferTo(0, count, out);
        }
        finally {
            Streams.safeClose(out);
            Streams.safeFlush(ops);
            Streams.safeClose(ops);
            Streams.safeClose(in);
            Streams.safeClose(ins);
        }
        return target.setLastModified(src.lastModified());
    }

    /**
     * @see #copyFile(File, File, long)
     */
    public static boolean copyFileWithoutException(File src, File target, long count) {
        try {
            return copyFile(src, target, -1);
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 自动决定是 copy 文件还是目录
     *
     * @param src
     *            源
     * @param target
     *            目标
     * @return 是否 copy 成功
     */
    public static boolean copy(File src, File target) {
        try {
            if (src.isDirectory())
                return copyDir(src, target);
            return copyFile(src, target);
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 拷贝一个目录
     *
     * @param src
     *            原始目录
     * @param target
     *            新目录
     * @return 是否拷贝成功
     * @throws IOException
     */
    public static boolean copyDir(File src, File target) throws IOException {
        if (src == null || target == null || !src.exists())
            return false;
        if (!src.isDirectory())
            throw new IOException(src.getAbsolutePath() + " should be a directory!");
        if (!target.exists())
            if (!makeDir(target))
                return false;
        boolean re = true;
        File[] files = src.listFiles();
        if (null != files) {
            for (File f : files) {
                if (f.isFile())
                    re &= copyFile(f, new File(target.getAbsolutePath() + "/" + f.getName()));
                else
                    re &= copyDir(f, new File(target.getAbsolutePath() + "/" + f.getName()));
            }
        }
        return re;
    }

    /**
     * 将文件移动到新的位置
     *
     * @param src
     *            原始文件
     * @param target
     *            新文件
     * @return 移动是否成功
     * @throws IOException
     */
    public static boolean move(File src, File target) throws IOException {
        if (src == null || target == null)
            return false;
        makeDir(target.getParentFile());
        if (src.isDirectory()) {
            src = new File(src.getCanonicalPath() + File.separator);
            target = new File(target.getCanonicalPath() + File.separator);
        }
        return src.renameTo(target);
    }

    /**
     * 将文件改名
     *
     * @param src
     *            文件
     * @param newName
     *            新名称
     * @return 改名是否成功
     */
    public static boolean rename(File src, String newName) {
        if (src == null || newName == null)
            return false;
        if (src.exists()) {
            File newFile = new File(src.getParent() + "/" + newName);
            if (newFile.exists())
                return false;
            Files.makeDir(newFile.getParentFile());
            return src.renameTo(newFile);
        }
        return false;
    }

    /**
     * 修改路径
     *
     * @param path
     *            路径
     * @param newName
     *            新名称
     * @return 新路径
     */
    public static String renamePath(String path, String newName) {
        if (!Strings.isBlank(path)) {
            int pos = path.replace('\\', '/').lastIndexOf('/');
            if (pos > 0)
                return path.substring(0, pos) + "/" + newName;
        }
        return newName;
    }

    /**
     * @param path
     *            路径
     * @return 父路径
     */
    public static String getParent(String path) {
        if (Strings.isBlank(path))
            return path;
        int pos = path.replace('\\', '/').lastIndexOf('/');
        if (pos > 0)
            return path.substring(0, pos);
        return "/";
    }

    /**
     * @param f
     *            文件对象
     * @return 文件或者目录名
     */
    public static String getName(File f) {
        return getName(f.getPath());
    }

    /**
     * @param path
     *            全路径
     * @return 文件或者目录名
     */
    public static String getName(String path) {
        if (!Strings.isBlank(path)) {
            int pos = path.replace('\\', '/').lastIndexOf('/');
            if (pos != -1)
                return path.substring(pos + 1);
        }
        return path;
    }

    /**
     * 将一个目录下的特殊名称的目录彻底删除，比如 '.svn' 或者 '.cvs'
     *
     * @param dir
     *            目录
     * @param name
     *            要清除的目录名
     * @throws IOException
     */
    public static void cleanAllFolderInSubFolderes(File dir, String name) throws IOException {
        File[] files = dir.listFiles();
        if (files == null)
        	return;
        for (File d : files) {
            if (d.isDirectory())
                if (d.getName().equalsIgnoreCase(name))
                    deleteDir(d);
                else
                    cleanAllFolderInSubFolderes(d, name);
        }
    }

    /**
     * 精确比较两个文件是否相等
     *
     * @param f1
     *            文件1
     * @param f2
     *            文件2
     * @return
     *

     *
true: 两个文件内容完全相等
     *
false: 任何一个文件对象为 null，不存在 或内容不相等
     *

     */
    public static boolean isEquals(File f1, File f2) {
        if (null == f1 || null == f2 || !f1.isFile() || !f2.isFile())
            return false;
        InputStream ins1 = null;
        InputStream ins2 = null;
        try {
            ins1 = Streams.fileIn(f1);
            ins2 = Streams.fileIn(f2);
            return Streams.equals(ins1, ins2);
        }
        catch (IOException e) {
            return false;
        }
        finally {
            Streams.safeClose(ins1);
            Streams.safeClose(ins2);
        }
    }

    /**
     * 在一个目录下，获取一个文件对象
     *
     * @param dir
     *            目录
     * @param path
     *            文件相对路径
     * @return 文件
     */
    public static File getFile(File dir, String path) {
        if (dir.exists()) {
            if (dir.isDirectory())
                return new File(dir.getAbsolutePath() + "/" + path);
            return new File(dir.getParent() + "/" + path);
        }
        throw Lang.makeThrow("dir noexists: %s", dir);
    }

    /**
     * 获取一个目录下所有子目录。子目录如果以 '.' 开头，将被忽略
     *
     * @param dir
     *            目录
     * @return 子目录数组
     */
    public static File[] dirs(File dir) {
        return dir.listFiles(new FileFilter() {
            public boolean accept(File f) {
                return !f.isHidden() && f.isDirectory() && !f.getName().startsWith(".");
            }
        });
    }

    /**
     * 递归查找获取一个目录下所有子目录(及子目录的子目录)。子目录如果以 '.' 开头，将被忽略
     *

     * 包含传入的目录
     *
     * @param dir
     *            目录
     * @return 子目录数组
     */
    public static File[] scanDirs(File dir) {
        ArrayList<File> list = new ArrayList<File>();
        list.add(dir);
        scanDirs(dir, list);
        return list.toArray(new File[list.size()]);
    }

    private static void scanDirs(File rootDir, List<File> list) {
        File[] dirs = rootDir.listFiles(new FileFilter() {
            public boolean accept(File f) {
                return !f.isHidden() && f.isDirectory() && !f.getName().startsWith(".");
            }
        });
        if (dirs != null) {
            for (File dir : dirs) {
                scanDirs(dir, list);
                list.add(dir);
            }
        }
    }

    /**
     * 获取一个目录下所有的文件(不递归，仅仅一层)。隐藏文件会被忽略。
     *
     * @param dir
     *            目录
     * @param suffix
     *            文件后缀名。如果为 null，则获取全部文件
     * @return 文件数组
     */
    public static File[] files(File dir, final String suffix) {
        return dir.listFiles(new FileFilter() {
            public boolean accept(File f) {
                return !f.isHidden()
                       && f.isFile()
                       && (null == suffix || f.getName().endsWith(suffix));
            }
        });
    }

    /**
     * 判断两个文件内容是否相等
     *
     * @param f1
     *            文件对象
     * @param f2
     *            文件对象
     * @return
     *

     *
true: 两个文件内容完全相等
     *
false: 任何一个文件对象为 null，不存在 或内容不相等
     *

     */
    public static boolean equals(File f1, File f2) {
        return isEquals(f1, f2);
    }

    public static boolean copyOnWrite(File f, Object obj) {
        File tmp = new File(f.getAbsolutePath() + ".new");
        File tmp2 = new File(f.getAbsolutePath() + ".old");
        tmp2.delete();
        try {
            write(tmp, obj);
            boolean flag = false;
            if (f.exists()) {
                flag = f.renameTo(tmp2);
            }
            if (tmp.renameTo(f)) {
                tmp2.delete();
                return true;
            } else if (flag)
                tmp2.renameTo(f); // 如果这里也失败的话,起码.old还在...
            return false;
        }
        finally {
            tmp.delete();
        }
    }

    public static boolean copyOnWrite(String path, Object obj) {
        return copyOnWrite(new File(path), obj);
    }

    public static List<String> readLines(File f) {
        List<String> lines = new ArrayList<String>();
        BufferedReader br = null;
        try {
            br = Streams.buffr(Streams.fileInr(f));
            while (br.ready())
                lines.add(br.readLine());
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
        finally {
            Streams.safeClose(br);
        }
        return lines;
    }

    public static void readLine(File f, Callback<String> callback) {
        BufferedReader br = null;
        try {
            br = Streams.buffr(Streams.fileInr(f));
            while (br.ready())
                callback.invoke(br.readLine());
        }
        catch (ExitLoop e) {}
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
        finally {
            Streams.safeClose(br);
        }
    }

    public static int readRange(File f, int pos, byte[] buf, int at, int len) {
        try {
            if (f == null || !f.exists())
                return 0;
            long fsize = f.length();
            if (pos > fsize)
                return 0;
            len = Math.min(len, buf.length - at);
            if (pos + len > fsize) {
                len = (int)(fsize - pos);
            }
            RandomAccessFile raf = new RandomAccessFile(f, "r");
            raf.seek(pos);
            raf.readFully(buf, at, len);
            raf.close();
            return len;
        }
        catch (IOException e) {
            return -1;
        }
    }

    public static int writeRange(File f, int pos, byte[] buf, int at, int len) {
        try {
            if (f == null || !f.exists())
                return 0;
            RandomAccessFile raf = new RandomAccessFile(f, "rw");
            raf.seek(pos);
            raf.write(buf, at, len);
            raf.close();
            return len;
        }
        catch (IOException e) {
            return -1;
        }
    }
}


package org.nutz.lang.util;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * 通过实现ParameterizedType,达到无需通过反射得到泛型Type</p> 通过嵌套Map/List,可得出无限可能
 *
 * @author wendal(wendal1985@gmail.com)
 *
 */
public class NutType implements ParameterizedType {

    /**
     * 生成List<AbcBean>形式的泛型信息
     *
     * @param clazz
     *            泛型的具体类
     * @return List<clazz>形式的泛型Type
     */
    public static Type list(Type clazz) {
        return new NutType(List.class, clazz);
    }

    /**
     * 生成Abc[]形式的泛型信息
     */
    public static Type array(Class<?> clazz) {
        return new NutType(Array.newInstance(clazz, 0).getClass());
    }

    /**
     * 生成Map<key,value>形式的泛型Type
     *
     * @param key
     *            key的泛型
     * @param value
     *            value的泛型
     * @return Map<key,value>形式的泛型Type
     */
    public static Type map(Type key, Type value) {
        return new NutType(Map.class, key, value);
    }

    /**
     * 生成Map<String,value>形式的泛型Type
     *
     * @param value
     *            value的泛型
     * @return Map<String,value>形式的泛型Type
     */
    public static Type mapStr(Type value) {
        return new NutType(Map.class, String.class, value);
    }

    public NutType() {}

    public NutType(Type rawType, Type... actualTypeArguments) {
        this.rawType = rawType;
        this.actualTypeArguments = actualTypeArguments;
    }

    private Type[] actualTypeArguments;

    private Type rawType;

    private Type ownerType;

    public Type[] getActualTypeArguments() {
        return actualTypeArguments;
    }

    public Type getRawType() {
        return rawType;
    }

    public Type getOwnerType() {
        return ownerType;
    }

    public void setActualTypeArguments(Type... actualTypeArguments) {
        this.actualTypeArguments = actualTypeArguments;
    }

    public void setOwnerType(Type ownerType) {
        this.ownerType = ownerType;
    }

    public void setRawType(Type rawType) {
        this.rawType = rawType;
    }
}


package org.nutz.mapl.impl.convert;

import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;

import org.nutz.castor.Castors;
import org.nutz.conf.NutConf;
import org.nutz.el.El;
import org.nutz.json.Json;
import org.nutz.json.entity.JsonCallback;
import org.nutz.json.entity.JsonEntity;
import org.nutz.json.entity.JsonEntityField;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.util.Context;
import org.nutz.mapl.Mapl;
import org.nutz.mapl.MaplConvert;

/**
 * 对象转换 将MapList结构转换成对应的对象
 *
 * @author juqkai(juqkai@gmail.com)
 * @author wendal(wendal1985@gmail.com)
 */
public class ObjConvertImpl implements MaplConvert {

    // 路径
    protected Stack<String> path = new Stack<String>();
    // 对象缓存
    protected Context context;

    protected Type type;

    public ObjConvertImpl(Type type) {
        this.type = type;
        if (NutConf.USE_EL_IN_OBJECT_CONVERT)
            context = Lang.context();
    }

    /**
     * 这个实现, 主要将 List, Map 的对象结构转换成真实的对象.
     *

     * 规则:
     *

     *
对象以Map存储, key为属性名, value为属性值
     *
数组以List存储
     *
Map直接存储为Map
     *
List直接存储为List
     *
只要不是List, Map 存储的, 都认为是可以直接写入对象的. TODO 这点可以调整一下.
     *

     */
    public Object convert(Object model) {
        if (model == null)
            return null;
        if (type == null)
            return model;
        // obj是基本数据类型或String
        if (!(model instanceof Map) && !(model instanceof Iterable)) {
            return Castors.me().castTo(model, Lang.getTypeClass(type));
        }

        return inject(model, type);
    }

    public Object inject(Object model, Type type) {
        if (model == null) {
            return null;
        }
        if (type == Object.class) {
            return model;
        }
        Mirror<?> me = Mirror.me(type);
        Object obj = null;
        if (Collection.class.isAssignableFrom(me.getType())) {
            obj = injectCollection(model, me);
        } else if (Map.class.isAssignableFrom(me.getType())) {
            obj = injectMap(model, me);
        } else if (me.getType().isArray()) {
            obj = injectArray(model, me);
        } else {
            obj = injectObj(model, me);
        }
        if (path.size() > 0)
            path.pop();
        return obj;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private Object injectArray(Object model, Mirror<?> me) {
        Class<?> clazz = me.getType().getComponentType();
        List list = (List) model;
        List vals = new ArrayList();
        int j = 0;
        for (Object obj : list) {
            if (isLeaf(obj)) {
                vals.add(Castors.me().castTo(obj, clazz));
                continue;
            }
            path.push("a" + (j++));
            vals.add(inject(obj, clazz));
        }
        Object obj = Array.newInstance(clazz, vals.size());
        for (int i = 0; i < vals.size(); i++) {
            Array.set(obj, i, vals.get(i));
        }
        return obj;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private Object injectMap(Object model, Mirror<?> me) {
        Map re = null;
        if (me.isInterface()) {
            re = new LinkedHashMap();
        } else {
            re = (Map) me.born();
        }

        Map map = (Map) model;
        if (me.getGenericsTypes() == null) {
            re.putAll(map);
            return re;
        }

        // 获取泛型信息
        Type[] ts = me.getGenericsTypes();
        Type keyType = null;
        Type valueType = null;
        if (ts != null && ts.length == 2) {
            keyType = ts[0];
            valueType = ts[1];
        }
        for (Object key : map.keySet()) {
            Object val = map.get(key);
            // 转换Key
            if (isLeaf(key)) {
                // 如果Map的key的类型不是String,那就转换一下吧
                if (keyType != null && !String.class.equals(keyType)) {
                    key = Castors.me().castTo(key, Lang.getTypeClass(keyType));
                }
            }
            else {
                key = inject(key, me.getGenericsType(0));
            }
            // 转换val并填充
            if (isLeaf(val)) {
                re.put(key, Castors.me().castTo(val, Lang.getTypeClass(valueType)));
                continue;
            }
            path.push(key.toString());
            re.put(key, inject(val, valueType));
        }
        return re;
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    private Object injectCollection(Object model, Mirror<?> me) {
        if (! (model instanceof Collection)) {
            if (model instanceof Map) {
                model = ((Map)model).values();
            } else {
                throw Lang.makeThrow("Not a Collection --> " + model.getClass());
            }
        }
        Collection re = null;
        if (!me.isInterface()) {
            re = (Collection) me.born();
        } else {
            re = makeCollection(me);
        }
        if (me.getGenericsTypes() == null) {
            re.addAll((Collection) model);
            return re;
        }
        Type type = me.getGenericsType(0);
        int j = 0;
        for (Object obj : (Collection) model) {
            if (isLeaf(obj)) {
                re.add(Castors.me().castTo(obj, Lang.getTypeClass(type)));
                continue;
            }
            path.push("a" + (j++));
            re.add(inject(obj, type));
        }
        return re;
    }

    @SuppressWarnings("rawtypes")
    private Collection makeCollection(Mirror<?> me) {
        if (List.class.isAssignableFrom(me.getType())) {
            return new ArrayList();
        }
        if (Set.class.isAssignableFrom(me.getType())) {
            return new HashSet();
        }
        throw new RuntimeException("不支持的类型!");
    }

    @SuppressWarnings("unchecked")
    private Object injectObj(Object model, Mirror<?> mirror) {
        JsonEntity jen = Json.getEntity(mirror);
        Object obj = null;
        JsonCallback callback = jen.getJsonCallback();
        if (callback != null) {
            obj = callback.fromJson(model);
            if (obj != null)
                return obj;
        }
        obj = mirror.born();
        if (NutConf.USE_EL_IN_OBJECT_CONVERT)
            context.set(fetchPath(), obj);
        Map<String, Object> map = (Map<String, Object>) model;
        for (Entry<String, ?> en : map.entrySet()) {
            Object val = en.getValue();
            if (val == null)
                continue;
            String key = en.getKey();
            JsonEntityField jef = jen.getField(key);
            if (jef == null) {
                continue;
            }
            if (NutConf.USE_EL_IN_OBJECT_CONVERT) {
                if (isLeaf(val)) {
                    if (val instanceof El) {
                        val = ((El) val).eval(context);
                    }
                } else {
                    path.push(key);
                }
            }
            // fix issue 1386
            if (jef.getMirror().isDateTimeLike() && jef.getDataFormat() != null) {
                try {
                    jef.setValue(obj, ((DateFormat)jef.getDataFormat()).parse(String.valueOf(val)));
                    continue;
                } catch (Throwable e) {
                }
            }
            jef.setValue(obj, Mapl.maplistToObj(val, jef.getGenericType()));
        }
        return obj;
    }

    private static boolean isLeaf(Object obj) {
        if (obj instanceof Map) {
            return false;
        }
        if (obj instanceof List) {
            return false;
        }
        return true;
    }

    private String fetchPath() {
        StringBuffer sb = new StringBuffer();
        sb.append("root");
        for (String item : path) {
            if (item.charAt(0) != 'a') {
                sb.append("m");
            }
            sb.append(item);
        }
        return sb.toString();
    }
}


package org.nutz.dao.impl;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Condition;
import org.nutz.dao.ConnCallback;
import org.nutz.dao.Dao;
import org.nutz.dao.DaoException;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.FieldMatcher;
import org.nutz.dao.SqlManager;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Entity;
import org.nutz.dao.entity.EntityMaker;
import org.nutz.dao.entity.LinkField;
import org.nutz.dao.entity.LinkVisitor;
import org.nutz.dao.entity.MappingField;
import org.nutz.dao.entity.Record;
import org.nutz.dao.impl.link.DoClearLinkVisitor;
import org.nutz.dao.impl.link.DoClearRelationByHostFieldLinkVisitor;
import org.nutz.dao.impl.link.DoClearRelationByLinkedFieldLinkVisitor;
import org.nutz.dao.impl.link.DoDeleteLinkVisitor;
import org.nutz.dao.impl.link.DoInsertLinkVisitor;
import org.nutz.dao.impl.link.DoInsertRelationLinkVisitor;
import org.nutz.dao.impl.link.DoUpdateLinkVisitor;
import org.nutz.dao.impl.link.DoUpdateRelationLinkVisitor;
import org.nutz.dao.impl.sql.pojo.ConditionPItem;
import org.nutz.dao.impl.sql.pojo.PojoEachEntityCallback;
import org.nutz.dao.impl.sql.pojo.PojoEachRecordCallback;
import org.nutz.dao.impl.sql.pojo.PojoFetchEntityByJoinCallback;
import org.nutz.dao.impl.sql.pojo.PojoFetchEntityCallback;
import org.nutz.dao.impl.sql.pojo.PojoFetchIntCallback;
import org.nutz.dao.impl.sql.pojo.PojoFetchObjectCallback;
import org.nutz.dao.impl.sql.pojo.PojoFetchRecordCallback;
import org.nutz.dao.impl.sql.pojo.PojoQueryEntityByJoinCallback;
import org.nutz.dao.impl.sql.pojo.PojoQueryEntityCallback;
import org.nutz.dao.impl.sql.pojo.PojoQueryRecordCallback;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.dao.jdbc.Jdbcs;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Criteria;
import org.nutz.dao.sql.DaoStatement;
import org.nutz.dao.sql.GroupBy;
import org.nutz.dao.sql.PItem;
import org.nutz.dao.sql.Pojo;
import org.nutz.dao.sql.PojoCallback;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos;
import org.nutz.dao.util.Pojos;
import org.nutz.dao.util.cri.SimpleCriteria;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.lang.ContinueLoop;
import org.nutz.lang.Each;
import org.nutz.lang.ExitLoop;
import org.nutz.lang.Lang;
import org.nutz.lang.LoopException;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;
import org.nutz.trans.Atom;
import org.nutz.trans.Molecule;

public class NutDao extends DaoSupport implements Dao {

    private PojoCallback _pojo_queryEntity;

    private PojoCallback _pojo_fetchEntity;

    private PojoCallback _pojo_eachEntity;

    private PojoCallback _pojo_queryRecord;

    private PojoCallback _pojo_fetchRecord;

    private PojoCallback _pojo_eachRecord;

    private PojoCallback _pojo_fetchInt;

    private PojoCallback _pojo_fetchObject;

    // ==========================================================
    // 下面是 3 个构造函数
    public NutDao() {
        super();
        // 设置默认的回调
        _pojo_queryEntity = new PojoQueryEntityCallback();
        _pojo_fetchEntity = new PojoFetchEntityCallback();
        _pojo_eachEntity = new PojoEachEntityCallback();
        _pojo_fetchInt = new PojoFetchIntCallback();
        _pojo_fetchObject = new PojoFetchObjectCallback();
        _pojo_queryRecord = new PojoQueryRecordCallback();
        _pojo_fetchRecord = new PojoFetchRecordCallback();
        _pojo_eachRecord = new PojoEachRecordCallback();
    }

    public NutDao(DataSource dataSource) {
        this();
        this.setDataSource(dataSource);
    }

    public NutDao(DataSource dataSource, SqlManager sqlManager) {
        this(dataSource);
        this.setSqlManager(sqlManager);
    }

    public NutDao(DataSource dataSource, EntityMaker maker) {
        this(dataSource);
        this.holder.maker = maker;
        maker.init(dataSource, expert, holder);
    }

    // 上面是 4 个构造函数
    // ==========================================================

    public <T> T getObject(Class<T> classOfT, ResultSet rs, FieldMatcher fm) {
        return getObject(classOfT, rs, fm, null);
    }

    public <T> T getObject(Class<T> classOfT, ResultSet rs, FieldMatcher fm, String prefix) {
        return holder.getEntity(classOfT).getObject(rs, fm, prefix);
    }

    public <T> T insert(final T obj) {
        Object first = Lang.first(obj);
        final EntityOperator opt = _optBy(first);
        if (null == opt)
            return null;
        int size = Lang.eleSize(obj);
    	opt.addInsert(opt.entity, first);
        if (size > 1) {
        	if (opt.getPojoListSize() == 1) {
        		// 单一操作,可以转为批量插入
        		return fastInsert(obj);
        	}
        	Lang.each(obj, false, new Each<Object>() {
        		public void invoke(int i, Object ele, int length) throws ExitLoop, LoopException {
        			if (i != 0)
        				opt.addInsert(opt.entity, ele);
        		}
        	});
        }
        opt.exec();
        return obj;
    }

    public <T> T insert(final T obj, FieldFilter filter) {
        if (filter == null)
            return insert(obj);
        filter.run(new Atom() {
            public void run() {
                insert(obj);
            }
        });
        return obj;
    }

    public void insert(String tableName, Chain chain) {
        if (chain.isSpecial()) {
            Daos.insertBySpecialChain(this, null, tableName, chain);
            return;
        }
        EntityOperator opt = _optBy(chain.toEntityMap(tableName));
        if (null == opt)
            return;
        opt.addInsert();
        opt.exec();
    }

    public void insert(Class<?> classOfT, Chain chain) {
        if (chain.isSpecial()) {
            Daos.insertBySpecialChain(this, getEntity(classOfT), null, chain);
            return;
        }
        EntityOperator opt = _opt(classOfT);
        opt.myObj = chain;
        opt.addInsertSelfOnly();
        // insert(chain.toObject(classOfT));// TODO 这样的效率,未免太低了,需要改进
        opt.exec();
    }

    public <T> T fastInsert(T obj) {
        return fastInsert(obj, false);
    }

    public <T> T fastInsert(T obj, boolean detectAllColumns) {
        EntityOperator opt = _optBy(obj, detectAllColumns);
        if (null == opt)
            return null;
        opt.addInsertSelfOnly();
        opt.exec();
        return obj;
    }

    public <T> T insertWith(T obj, String regex) {
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return null;
        final LinkVisitor one = doInsert(opt);
        final boolean[] flag = new boolean[1];
        // issue 889. hostField是@Id(auto=true)的时候
        // 需要把相应的@One对象,押后到host对象插入之后
        opt.entity.visitOne(obj, regex, new LinkVisitor() {
            public void visit(Object obj, LinkField lnk) {
                if (lnk.getHostField().isId()) {
                    flag[0] = true;
                    return;
                }
                one.visit(obj, lnk);
            }
        });
        opt.addInsert();
        opt.entity.visitMany(obj, regex, doInsert(opt));
        opt.entity.visitManyMany(obj, regex, doInsert(opt));
        opt.entity.visitManyMany(obj, regex, doInsertRelation(opt));
        opt.exec();

        if (flag[0]) {
            opt = _optBy(obj);
            final LinkVisitor _one = doInsert(opt);
            opt.entity.visitOne(obj, regex, new LinkVisitor() {
                public void visit(Object obj, LinkField lnk) {
                    if (!lnk.getHostField().isId())
                        return;
                    _one.visit(obj, lnk);
                }
            });
            opt.exec();
        }

        return obj;
    }

    public <T> T insertLinks(T obj, String regex) {
        // TODO 天啊,每个调用都有4个正则表达式,能快起来不?
        // TODO zzh: NutEntity 会缓存正则表达式计算的结果的，会很快的
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return null;

        opt.entity.visitOne(obj, regex, doInsert(opt));
        opt.entity.visitMany(obj, regex, doInsert(opt));
        opt.entity.visitManyMany(obj, regex, doInsert(opt));
        opt.entity.visitManyMany(obj, regex, doInsertRelation(opt));
        opt.exec();

        return obj;
    }

    public <T> T insertRelation(T obj, String regex) {
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return null;

        opt.entity.visitManyMany(obj, regex, doInsertRelation(opt));
        opt.exec();

        return obj;
    }

    public int update(Object obj) {
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return 0;
        opt.addUpdate();
        opt.exec();
        return opt.getUpdateCount();
    }

    public int update(final Object obj, String actived) {
        Object first = Lang.first(obj);
        if (null == first)
            return 0;

        if (Strings.isBlank(actived))
            return update(obj);

        return update(obj, FieldFilter.create(first.getClass(), actived));
    }

    public int update(final Object obj, String actived, String locked, boolean ignoreNull) {
        Object first = Lang.first(obj);
        if (null == first)
            return 0;
        return update(obj, FieldFilter.create(first.getClass(), actived, locked, ignoreNull));
    }

    public int update(final Object obj, FieldFilter fieldFilter) {
        if (fieldFilter == null)
            return update(obj);

        return fieldFilter.run(new Molecule<Integer>() {
            public void run() {
                setObj(update(obj));
            }
        });
    }

    public int update(final Object obj, FieldFilter fieldFilter, final Condition cnd) {
        if (fieldFilter == null)
            return update(obj, cnd);
        return fieldFilter.run(new Molecule<Integer>() {
            public void run() {
                setObj(update(obj, cnd));
            }
        });
    }

    public int update(Object obj, Condition cnd) {
        if (cnd == null)
            return update(obj);
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return 0;
        opt.addUpdateByPkAndCnd(cnd);
        opt.exec();
        return opt.getUpdateCount();
    }

    public int updateIgnoreNull(final Object obj) {
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return 0;
        opt.addUpdateForIgnoreNull(opt.entity, obj, FieldFilter.get(opt.entity.getType()));
        opt.exec();
        return opt.getUpdateCount();
    }

    public int update(String tableName, Chain chain, Condition cnd) {
        EntityOperator opt = _optBy(chain.toEntityMap(tableName));
        if (null == opt)
            return 0;
        opt.addUpdate(chain, cnd);
        opt.exec();
        return opt.getUpdateCount();
    }

    public int update(Class<?> classOfT, Chain chain, Condition cnd) {
        EntityOperator opt = _opt(classOfT);
        opt.addUpdate(chain, cnd);
        opt.exec();
        return opt.getUpdateCount();
    }

    public <T> T updateWith(T obj, final String regex) {
        if (null == obj)
            return null;
        Lang.each(obj, false, new Each<Object>() {
            public void invoke(int index, Object ele, int length) throws ExitLoop, ContinueLoop,
                    LoopException {
                EntityOperator opt = _optBy(ele);
                if (null == opt)
                    return;

                opt.entity.visitOne(ele, regex, doUpdate(opt));
                opt.addUpdate();
                opt.entity.visitMany(ele, regex, doUpdate(opt));
                opt.entity.visitManyMany(ele, regex, doUpdate(opt));

                opt.exec();
            }
        });
        return obj;
    }

    public <T> T updateLinks(T obj, final String regex) {
        if (null == obj)
            return null;
        Lang.each(obj, false, new Each<Object>() {
            public void invoke(int index, Object ele, int length) throws ExitLoop, ContinueLoop,
                    LoopException {
                EntityOperator opt = _optBy(ele);
                if (null == opt)
                    return;

                opt.entity.visitOne(ele, regex, doUpdate(opt));
                opt.entity.visitMany(ele, regex, doUpdate(opt));
                opt.entity.visitManyMany(ele, regex, doUpdate(opt));

                opt.exec();
            }
        });
        return obj;
    }

    public int updateRelation(Class<?> classOfT, String regex, Chain chain, Condition cnd) {
        if (chain.isSpecial())
            throw Lang.noImplement();

        EntityOperator opt = this._opt(classOfT);

        opt.entity.visitManyMany(null, regex, doUpdateRelation(opt, chain, cnd));
        opt.exec();

        return opt.getUpdateCount();
    }

    public int delete(Class<?> classOfT, long id) {
        Entity<?> en = holder.getEntity(classOfT);
        Pojo pojo = pojoMaker.makeDelete(en).append(Pojos.Items.cndId(en, id));
        pojo.addParamsBy(id);
        _exec(pojo);
        return pojo.getUpdateCount();
    }

    public int delete(Class<?> classOfT, String name) {
        Entity<?> en = holder.getEntity(classOfT);
        Pojo pojo = pojoMaker.makeDelete(en)
                             .append(Pojos.Items.cndName(en, name))
                             .addParamsBy(name);
        _exec(pojo);
        return pojo.getUpdateCount();
    }

    public <T> int deletex(Class<T> classOfT, Object... pks) {
        Entity<T> en = holder.getEntity(classOfT);
        Pojo pojo = pojoMaker.makeDelete(en).append(Pojos.Items.cndPk(en, pks));
        _exec(pojo);
        return pojo.getUpdateCount();
    }

    public int delete(Object obj) {
        EntityOperator opt = _optBy(obj);
        if (null == opt)
            return 0;
        opt.addDeleteSelfOnly();
        opt.exec();
        return opt.getUpdateCount();
    }

    public int deleteWith(Object obj, final String regex) {
        if (null == obj)
            return 0;
        final int[] re = new int[1];
        Lang.each(obj, false, new Each<Object>() {
            public void invoke(int index, Object ele, int length) throws ExitLoop, ContinueLoop,
                    LoopException {
                EntityOperator opt = _optBy(ele);
                if (null == opt)
                    return;
                opt.entity.visitMany(ele, regex, doDelete(opt));
                opt.entity.visitManyMany(ele, regex, doClearRelationByLinkedField(opt));
                opt.entity.visitManyMany(ele, regex, doDelete(opt));
                opt.addDeleteSelfOnly();
                opt.entity.visitOne(ele, regex, doDelete(opt));

                re[0] += opt.exec().getUpdateCount();
            }
        });
        return re[0];
    }

    public int deleteLinks(Object obj, final String regex) {
        if (null == obj)
            return 0;
        final int[] re = new int[1];
        Lang.each(obj, false, new Each<Object>() {
            public void invoke(int index, Object ele, int length) throws ExitLoop, ContinueLoop,
                    LoopException {
                EntityOperator opt = _optBy(ele);
                if (null == opt)
                    return;
                opt.entity.visitMany(ele, regex, doDelete(opt));
                opt.entity.visitManyMany(ele, regex, doClearRelationByLinkedField(opt));
                opt.entity.visitManyMany(ele, regex, doDelete(opt));
                opt.entity.visitOne(ele, regex, doDelete(opt));

                re[0] += opt.exec().getUpdateCount();
            }
        });
        return re[0];
    }

    public <T> List<T> query(Class<T> classOfT, Condition cnd, Pager pager) {
        Pojo pojo = pojoMaker.makeQuery(holder.getEntity(classOfT))
                             .append(Pojos.Items.cnd(cnd))
                             .addParamsBy("*")
                             .setPager(pager)
                             .setAfter(_pojo_queryEntity);
        expert.formatQuery(pojo);
        _exec(pojo);
        return pojo.getList(classOfT);
    }

    public <T> List<T> query(Class<T> classOfT, Condition cnd) {
        return query(classOfT, cnd, Pojos.Items.pager(cnd));
    }

    public <T> int each(Class<T> classOfT, Condition cnd, Pager pager, Each<T> callback) {
        Pojo pojo = pojoMaker.makeQuery(holder.getEntity(classOfT))
                             .append(Pojos.Items.cnd(cnd))
                             .addParamsBy("*")
                             .setPager(pager)
                             .setAfter(_pojo_queryEntity);
        expert.formatQuery(pojo);
        pojo.setAfter(_pojo_eachEntity);
        pojo.getContext().attr(Each.class.getName(), callback);
        pojo.getContext().attr("dao-cache-skip", "true");
        _exec(pojo);
        return pojo.getInt();
    }

    public <T> int each(Class<T> classOfT, Condition cnd, Each<T> callback) {
        return each(classOfT, cnd, Pojos.Items.pager(cnd), callback);
    }

    public List<Record> query(String tableName, Condition cnd, Pager pager) {
        return query(tableName, cnd, pager, "*");
    }

    public List<Record> query(String tableName, Condition cnd, Pager pager, String fields) {
        Pojo pojo = pojoMaker.makeQuery(tableName, fields)
                             .addParamsBy(fields)
                             .setPager(pager)
                             .append(Pojos.Items.cnd(cnd));
        expert.formatQuery(pojo);
        pojo.setAfter(_pojo_queryRecord);
        _exec(pojo);
        return pojo.getList(Record.class);
    }

    public List<Record> query(String tableName, Condition cnd) {
        return query(tableName, cnd, Pojos.Items.pager(cnd));
    }

    public int each(String tableName, Condition cnd, Pager pager, Each<Record> callback, String fields) {
        Pojo pojo = pojoMaker.makeQuery(tableName, fields)
                             .addParamsBy(fields)
                             .setPager(pager)
                             .append(Pojos.Items.cnd(cnd));
        expert.formatQuery(pojo);
        pojo.setAfter(_pojo_eachRecord);
        pojo.getContext().attr(Each.class.getName(), callback);
        pojo.getContext().attr("dao-cache-skip", "true");
        _exec(pojo);
        return pojo.getInt();
    }

    public int each(String tableName, Condition cnd, Pager pager, Each<Record> callback) {
        return each(tableName, cnd, pager, callback, "*");
    }

    public int each(String tableName, Condition cnd, Each<Record> callback) {
        return each(tableName, cnd, Pojos.Items.pager(cnd), callback);
    }

    public <T> T fetch(Class<T> classOfT, long id) {
        Entity<T> en = holder.getEntity(classOfT);
        if (en.getIdField() == null)
            throw new DaoException("Need @Id for " + classOfT);
        Pojo pojo = pojoMaker.makeQuery(en)
                             .append(Pojos.Items.cndId(en, id))
                             .addParamsBy(id)
                             .setAfter(_pojo_fetchEntity);
        _exec(pojo);
        return pojo.getObject(classOfT);
    }

    public <T> T fetch(Class<T> classOfT, String name) {
        if (name == null)
            throw new IllegalArgumentException("name MUST NOT NULL!");
        Entity<T> en = holder.getEntity(classOfT);
        if (en.getNameField() == null)
            throw new DaoException("Need @Name for " + classOfT);
        Pojo pojo = pojoMaker.makeQuery(en)
                             .append(Pojos.Items.cndName(en, name))
                             .addParamsBy(name)
                             .setAfter(_pojo_fetchEntity);
        _exec(pojo);
        return pojo.getObject(classOfT);
    }

    public <T> T fetchx(Class<T> classOfT, Object... pks) {
        Entity<T> en = holder.getEntity(classOfT);
        Pojo pojo = pojoMaker.makeQuery(en)
                             .append(Pojos.Items.cndPk(en, pks))
                             .setAfter(_pojo_fetchEntity);
        _exec(pojo);
        return pojo.getObject(classOfT);
    }

    public <T> T fetch(Class<T> classOfT, Condition cnd) {
        Pojo pojo = pojoMaker.makeQuery(holder.getEntity(classOfT))
                             .append(Pojos.Items.cnd(cnd))
                             .addParamsBy("*")
                             .setPager(createPager(1, 1))
                             .setAfter(_pojo_fetchEntity);
        expert.formatQuery(pojo);
        _exec(pojo);
        return pojo.getObject(classOfT);
    }

    public Record fetch(String tableName, Condition cnd) {
        return fetch(tableName, cnd, "*");
    }

    public Record fetch(String tableName, Condition cnd, String fields) {
        Pojo pojo = pojoMaker.makeQuery(tableName, fields)
                             .append(Pojos.Items.cnd(cnd))
                             .addParamsBy(fields)
                             .setPager(createPager(1, 1))
                             .setAfter(_pojo_fetchRecord);
        expert.formatQuery(pojo);
        _exec(pojo);
        return pojo.getObject(Record.class);
    }

    @SuppressWarnings("unchecked")
    public <T> T fetch(T obj) {
        Entity<?> en = holder.getEntityBy(obj);
        Pojo pojo = pojoMaker.makeQuery(en)
                             .append(Pojos.Items.cndAuto(en, obj))
                             .setAfter(_pojo_fetchEntity)
                             .setPager(createPager(1, 1));
        _exec(pojo);
        return (T) pojo.getResult();
    }

    public <T> T fetch(Class<T> classOfT) {
        List<T> list = query(classOfT, null, createPager(1, 1));
        if (null != list && !list.isEmpty())
            return list.get(0);
        return null;
    }

    public <T> T fetchLinks(T obj, final String regex) {
        return fetchLinks(obj, regex, null);
    }

    public <T> T fetchLinks(final T obj, final String regex, final Condition cnd) {
        if (null == obj)
            return null;
        Lang.each(obj, false, new Each<Object>() {
            public void invoke(int index, Object ele, int length) {
                _fetchLinks(ele, regex, true, true, true, cnd);
            }
        });
        return obj;
    }

    public int clear(Class<?> classOfT, Condition cnd) {
        Pojo pojo = pojoMaker.makeDelete(holder.getEntity(classOfT)).append(Pojos.Items.cnd(cnd));
        _exec(pojo);
        return pojo.getUpdateCount();
    }

    public int clear(String tableName, Condition cnd) {
        Pojo pojo = pojoMaker.makeDelete(tableName).append(Pojos.Items.cnd(cnd));
        _exec(pojo);
        return pojo.getUpdateCount();
    }

    public int clear(Class<?> classOfT) {
        return clear(classOfT, null);
    }

    public int clear(String tableName) {
        return clear(tableName, null);
    }

    public <T> T clearLinks(T obj, final String regex) {
        if (null == obj)
            return null;
        Lang.each(obj, false, new Each<Object>() {
            public void invoke(int index, Object ele, int length) {
                EntityOperator opt = _optBy(ele);
                if (null == opt)
                    return;
                opt.entity.visitMany(ele, regex, doClear(opt));
                opt.entity.visitManyMany(ele, regex, doClearRelationByHostField(opt));
                opt.entity.visitOne(ele, regex, doClear(opt));

                opt.exec();
            }
        });
        return obj;
    }

    public <T> Entity<T> getEntity(Class<T> classOfT) {
        return holder.getEntity(classOfT);
    }

    public int count(Class<?> classOfT, Condition cnd) {
        Entity<?> en = holder.getEntity(classOfT);
        return _count(en, en.getViewName(), cnd);
    }

    public int count(Class<?> classOfT) {
        Entity<?> en = holder.getEntity(classOfT);
        return _count(en, en.getViewName(), null);
    }

    public int count(String tableName) {
        return count(tableName, null);
    }

    public int count(String tableName, Condition cnd) {
        return _count(null, tableName, cnd);
    }

    private int _count(Entity<?> en, String tableName, Condition cnd) {
        // 如果有条件的话
        if (null != cnd) {
            Pojo pojo = pojoMaker.makeFunc(tableName, "COUNT", "*");
            pojo.setEntity(en);
            // 高级条件接口，直接得到 WHERE 子句
            if (cnd instanceof Criteria) {
                if (cnd instanceof SimpleCriteria) {
                    String beforeWhere = ((SimpleCriteria)cnd).getBeforeWhere();
                    if (!Strings.isBlank(beforeWhere))
                        pojo.addParamsBy(Pojos.Items.wrap(beforeWhere));
                }
                pojo.append(((Criteria) cnd).where());
                // MySQL/PgSQL/SqlServer 与 Oracle/H2的结果会不一样,奇葩啊
                GroupBy gb = ((Criteria) cnd).getGroupBy();
                pojo.append(gb);
            }
            // 否则暴力获取 WHERE 子句
            else {
                String str = Pojos.formatCondition(en, cnd);
                if (!Strings.isBlank(str)) {
                    String[] ss = str.toUpperCase().split("ORDER BY");
                    pojo.append(Pojos.Items.wrap(str.substring(0, ss[0].length())));
                }
            }
            // 设置回调，并执行 SQL
            pojo.setAfter(_pojo_fetchInt);
            _exec(pojo);
            return pojo.getInt();
        }
        // 没有条件，直接生成表达式
        return func(tableName, "COUNT", "*");
    }

    public int getMaxId(Class<?> classOfT) {
        Entity<?> en = holder.getEntity(classOfT);
        return func(en.getViewName(), "MAX", en.getIdField().getColumnNameInSql());
    }

    public int func(Class<?> classOfT, String funcName, String fieldName) {
        return func(classOfT, funcName, fieldName, null);
    }

    public int func(String tableName, String funcName, String colName) {
        return func(tableName, funcName, colName, null);
    }

    public int func(Class<?> classOfT, String funcName, String colName, Condition cnd) {
        Entity<?> en = holder.getEntity(classOfT);
        if (null != en.getField(colName))
            colName = en.getField(colName).getColumnNameInSql();
        DaoStatement pojo = pojoMaker.makeFunc(en.getViewName(), funcName, colName)
                                     .append(Pojos.Items.cnd(cnd))
                                     .setAfter(_pojo_fetchInt)
                                     .setEntity(en);
        _exec(pojo);
        return pojo.getInt();
    }

    public int func(String tableName, String funcName, String colName, Condition cnd) {
        DaoStatement pojo = pojoMaker.makeFunc(tableName, funcName, colName)
                                     .append(Pojos.Items.cnd(cnd))
                                     .setAfter(_pojo_fetchInt);
        _exec(pojo);
        return pojo.getInt();
    }

    public Object func2(Class<?> classOfT, String func2Name, String fieldName) {
        return func2(classOfT, func2Name, fieldName, null);
    }

    public Object func2(String tableName, String func2Name, String colName) {
        return func2(tableName, func2Name, colName, null);
    }

    public Object func2(Class<?> classOfT, String func2Name, String colName, Condition cnd) {
        Entity<?> en = holder.getEntity(classOfT);
        if (null != en.getField(colName))
            colName = en.getField(colName).getColumnNameInSql();
        DaoStatement pojo = pojoMaker.makeFunc(en.getViewName(), func2Name, colName)
                                     .append(Pojos.Items.cnd(cnd))
                                     .setAfter(_pojo_fetchObject)
                                     .setEntity(en);
        _exec(pojo);
        return pojo.getResult();
    }

    public Object func2(String tableName, String func2Name, String colName, Condition cnd) {
        DaoStatement pojo = pojoMaker.makeFunc(tableName, func2Name, colName)
                                     .append(Pojos.Items.cnd(cnd))
                                     .setAfter(_pojo_fetchObject);
        _exec(pojo);
        return pojo.getResult();
    }

    public Pager createPager(int pageNumber, int pageSize) {
        Pager pager = new Pager();
        pager.setPageNumber(pageNumber);
        pager.setPageSize(pageSize);
        return pager;
    }

    public synchronized <T> Entity<T> create(Class<T> classOfT, boolean dropIfExists) {
        Entity<T> en = holder.getEntity(classOfT);
        if (exists(en.getTableName())) {
            if (dropIfExists) {
                expert.dropEntity(this, en);
            } else {
                expert.createRelation(this, en);
                return en;
            }
        }
        holder.remove(classOfT.getName());
        final Entity<T> _en = holder.getEntity(classOfT);
        expert.createEntity(this, _en);
        // 最后在数据库中验证一下实体各个字段
        run(new ConnCallback() {
            public void invoke(Connection conn) throws Exception {
                expert.setupEntityField(conn, _en);
            }
        });
        return en;
    }

    public synchronized <T> Entity<T> create(final Entity<T> en, boolean dropIfExists) {
        if (exists(en.getTableName())) {
            if (dropIfExists) {
                expert.dropEntity(this, en);
            } else {
                expert.createRelation(this, en);
                return en;
            }
        }
        expert.createEntity(this, en);
        // 最后在数据库中验证一下实体各个字段
        run(new ConnCallback() {
            public void invoke(Connection conn) throws Exception {
                expert.setupEntityField(conn, en);
            }
        });
        return en;
    }

    public synchronized <T extends Map<String, ?>> Entity<T> create(T map, boolean dropIfExists) {
        String tableName = (String) map.get(".table");
        if (Strings.isBlank(tableName))
            throw new DaoException("need .table!!");
        return create(tableName, map, dropIfExists);
    }

    public synchronized <T extends Map<String, ?>> Entity<T> create(String tableName, T map, boolean dropIfExists) {
        final Entity<T> en = holder.makeEntity(tableName, map);
        if (exists(en.getTableName())) {
            if (dropIfExists) {
                expert.dropEntity(this, en);
            } else {
                expert.createRelation(this, en);
                return en;
            }
        }
        expert.createEntity(this, en);
        // 最后在数据库中验证一下实体各个字段
        run(new ConnCallback() {
            public void invoke(Connection conn) throws Exception {
                expert.setupEntityField(conn, en);
            }
        });
        return en;
    }

    public boolean drop(Class<?> classOfT) {
        Entity<?> en = holder.getEntity(classOfT);
        if (!exists(en.getTableName()))
            return false;
        return expert.dropEntity(this, en);
    }

    public boolean drop(String tableName) {
        if (!exists(tableName))
            return false;
        Sql sql = Sqls.createf("DROP TABLE %s", tableName);
        _exec(sql);
        return true;
    }

    public boolean exists(Class<?> classOfT) {
        return exists(getEntity(classOfT).getViewName());
    }

    public boolean exists(final String tableName) {
        final boolean[] ee = {false};
        this.run(new ConnCallback() {
            public void invoke(Connection conn) {
                Statement stat = null;
                ResultSet rs = null;
                try {
                    stat = conn.createStatement();
                    // 增加不等式,减少sql执行时间
                    String sql = "SELECT COUNT(1) FROM " + tableName + " where 1!=1";
                    rs = stat.executeQuery(sql);
                    if (rs.next())
                        ee[0] = true;
                }
                catch (SQLException e) {}
                finally {
                    Daos.safeClose(stat, rs);
                }
            }
        });
        return ee[0];
    }

    // ==========================================================
    // 下面几个是快速创建映射操作回调的帮助函数

    private LinkVisitor doInsert(EntityOperator opt) {
        return new DoInsertLinkVisitor().opt(opt);
    }

    private LinkVisitor doInsertRelation(EntityOperator opt) {
        return new DoInsertRelationLinkVisitor(holder).opt(opt);
    }

    private LinkVisitor doUpdate(EntityOperator opt) {
        return new DoUpdateLinkVisitor().opt(opt);
    }

    private LinkVisitor doUpdateRelation(EntityOperator opt, Chain chain, Condition cnd) {
        return new DoUpdateRelationLinkVisitor(chain.toMap(), cnd).opt(opt);
    }

    private LinkVisitor doClearRelationByLinkedField(EntityOperator opt) {
        return new DoClearRelationByLinkedFieldLinkVisitor().opt(opt);
    }

    private LinkVisitor doClearRelationByHostField(EntityOperator opt) {
        return new DoClearRelationByHostFieldLinkVisitor().opt(opt);
    }

    private LinkVisitor doDelete(EntityOperator opt) {
        return new DoDeleteLinkVisitor().opt(opt);
    }

    private LinkVisitor doClear(EntityOperator opt) {
        return new DoClearLinkVisitor().opt(opt);
    }

    private LinkVisitor doFetch(final EntityOperator opt) {
        return new LinkVisitor() {
            public void visit(final Object obj, final LinkField lnk) {
                Pojo pojo = opt.maker().makeQuery(lnk.getLinkedEntity());
                pojo.setOperatingObject(obj);
                pojo.append(Pojos.Items.cnd(lnk.createCondition(obj)));
                pojo.setAfter(lnk.getCallback());
                _exec(pojo);
                lnk.setValue(obj, pojo.getObject(Object.class));
            }
        };
    }

    private LinkVisitor doLinkQuery(final EntityOperator opt, final Condition _cnd, final Map<String, Condition> cnds) {
        return new LinkVisitor() {
            public void visit(final Object obj, final LinkField lnk) {
                Pojo pojo = opt.maker().makeQuery(lnk.getLinkedEntity());
                pojo.setOperatingObject(obj);
                PItem[] _cndItems = Pojos.Items.cnd(lnk.createCondition(obj));
                pojo.append(_cndItems);
                Condition cnd = _cnd;
                if (_cnd == null && cnds != null)
                    cnd = cnds.get(lnk.getLinkedField().getName());
                if (cnd != null) {
                    if (cnd instanceof Criteria) {
                        Criteria cri = (Criteria) cnd;
                        SqlExpressionGroup seg = cri.where();
                        if (_cndItems.length > 0 && seg != null && !seg.isEmpty()) {
                            seg.setTop(false);
                            pojo.append(Pojos.Items.wrap(" AND "));
                        }
                        pojo.append(cri);
                        if (cri.getPager() != null) {
                            pojo.setPager(cri.getPager());
                            expert.formatQuery(pojo);
                        }
                    }
                    // 普通条件
                    else {
                        pojo.append(new ConditionPItem(cnd));
                    }
                }
                pojo.setAfter(lnk.getCallback());
                pojo.setEntity(lnk.getLinkedEntity());
                _exec(pojo);
                lnk.setValue(obj, pojo.getResult());
            }
        };
    }

    // ==========================================================
    // 下面几个是快速创建实体操作对象的帮助函数

    private <T> EntityOperator _opt() {
        EntityOperator opt = new EntityOperator();
        opt.dao = this;
        return opt;
    }

    <T> EntityOperator _opt(Entity<T> en) {
        EntityOperator opt = _opt();
        opt.entity = en;
        return opt;
    }

    <T> EntityOperator _opt(Class<T> classOfT) {
        return _opt(holder.getEntity(classOfT));
    }

    EntityOperator _optBy(Object obj) {
        return _optBy(obj, false);
    }

    EntityOperator _optBy(Object obj, boolean detectAllColumns) {
        // 阻止空对象
        if (null == obj)
            return null;
        Entity<?> en = null;
        // for issue 1425
        if (detectAllColumns && Lang.eleSize(obj) > 1) {
            Object first = Lang.first(obj);
            if (first != null && first instanceof Map) {
                final Map<String, Object> tmp = new HashMap<String, Object>();
                Lang.each(obj, new Each<Object>() {
                    @SuppressWarnings({"unchecked", "rawtypes"})
                    public void invoke(int index, Object ele, int length) throws ExitLoop, ContinueLoop, LoopException {
                        tmp.putAll((Map)ele);
                    }
                });
                en = holder.getEntityBy(tmp);
            }
        }
        if (en == null) {
            en = holder.getEntityBy(obj);
        }
        // 对象是否有内容，这里会考虑集合与数组

        if (null == en)
            return null;
        // 创建操作对象
        EntityOperator re = _opt(en);
        re.myObj = obj.getClass().isArray() ? Lang.array2list((Object[]) obj) : obj;
        return re;
    }

    // ---------------------------------------------------------------
    // 专属于NutDao的一些帮助方法

    public void setExpert(Object obj) throws Exception {
        if (obj == null)
            throw new NullPointerException("expert MUST NOT NULL!!");
        if (obj instanceof JdbcExpert) {
            this.expert = (JdbcExpert) obj;
        } else {
            String name = obj.toString();
            this.expert = Jdbcs.getExpert(name, "");
            if (this.expert == null) {
                if (name.contains(".")) {
                    Class<?> klass = Lang.loadClass(name);
                    try {
                        this.expert = (JdbcExpert) Mirror.me(klass).born(Jdbcs.getConf());
                    }
                    catch (Throwable e) {
                        this.expert = (JdbcExpert) Mirror.me(klass).born();
                    }
                } else {
                    throw new DaoException("not such expert=" + obj);
                }
            }
        }
        DataSource ds = this.dataSource;
        // 如果数据源比expert先设置,那么需要重新设置一次
        if (ds != null) {
            this.dataSource = null;
            setDataSource(ds);
        }
    }

    public Sql execute(Sql sql) {
        if (sql != null)
            execute(new Sql[]{sql});
        return sql;
    }

    public <T> T insert(final T t, boolean ignoreNull, boolean ignoreZero, boolean ignoreBlankStr) {
    	Object obj = Lang.first(t);
    	Entity<?> en = getEntity(obj.getClass());
    	List<String> names = new ArrayList<String>();
    	for (MappingField mf : en.getMappingFields()) {
    	    if (mf.isName() || mf.isPk() || mf.isId()) {
                names.add(mf.getName());
    	        continue;
    	    }
    		Object tmp = mf.getValue(obj);
			if (ignoreNull && tmp == null) {
				continue;
			}
			if (ignoreZero && (tmp == null || (tmp instanceof Number && ((Number)tmp).intValue() == 0))) {
				continue;
			}
			if (ignoreBlankStr && (tmp instanceof CharSequence && Strings.isBlank((CharSequence)tmp)))
				continue;
			names.add(mf.getName());
		}
    	FieldFilter ff = FieldFilter.create(obj.getClass(), "^("+Strings.join("|", names.toArray())+")$");
    	Molecule<T> m = new Molecule<T>() {
    		public void run() {
    			insert(t);
    			setObj(t);
    		}
		};
		return ff.run(m);
    }

    public <T> List<T> query(final Class<T> classOfT, final Condition cnd, final Pager pager, FieldMatcher matcher) {
        if (matcher == null)
            return query(classOfT, cnd, pager);
        FieldFilter ff = FieldFilter.create(classOfT, matcher);
        Molecule<List<T>> m = new Molecule<List<T>>() {
            public void run() {
                setObj(query(classOfT, cnd, pager));
            }
        };
        return ff.run(m);
    }

    public <T> List<T> query(final Class<T> classOfT, final Condition cnd, final Pager pager, String regex) {
        if (regex == null)
            return query(classOfT, cnd, pager);
        FieldFilter ff = FieldFilter.create(classOfT, FieldMatcher.make(regex, null, false));
        Molecule<List<T>> m = new Molecule<List<T>>() {
            public void run() {
                setObj(query(classOfT, cnd, pager));
            }
        };
        return ff.run(m);
    }

    public <T> T insertOrUpdate(T t) {
        return insertOrUpdate(t, null, null);
    }

    public <T> T insertOrUpdate(T t, final FieldFilter insertFieldFilter, final FieldFilter updateFieldFilter) {
        if (t == null)
            return null;
        Object obj = Lang.first(t);
        final Entity<?> en = getEntity(obj.getClass());
        Lang.each(t, new Each<Object>() {

            public void invoke(int index, Object ele, int length) throws ExitLoop, ContinueLoop, LoopException {

                boolean shall_update = false;
                MappingField mf = en.getNameField();
                if (mf != null) {
                    Object val = mf.getValue(ele);
                    if (val != null && fetch(en.getType(), Cnd.where(mf.getName(), "=", val)) != null) {
                        shall_update = true;
                    }
                }
                else if (en.getIdField() != null) {
                    mf = en.getIdField();
                    Object val = mf.getValue(ele);
                    if (val != null && fetch(ele) != null) {
                        shall_update = true;
                    }
                }
                else {
                    shall_update = fetch(ele) != null;
                }
                if (shall_update)
                    update(ele, updateFieldFilter);
                else
                    insert(ele, insertFieldFilter);
            }
        });
        return t;
    }

    public int updateAndIncrIfMatch(final Object obj, FieldFilter fieldFilter, String fieldName) {
        final EntityOperator opt = _optBy(obj);
        if (null == opt)
            return 0;
        if (fieldName == null)
            fieldName = "version";
        if (fieldFilter == null)
            fieldFilter = FieldFilter.create(opt.entity.getType(), null, "^"+fieldName+"$", false);
        else {
            FieldMatcher fieldMatcher = fieldFilter.map().get(opt.entity.getType());
            if (fieldMatcher == null) {
                fieldMatcher = FieldMatcher.make(null, "^"+fieldName+"$", false);
                fieldFilter.map().put(opt.entity.getType(), fieldMatcher);
            } else {
                if (fieldMatcher.getLocked() == null) {
                    fieldMatcher.setLocked("^"+fieldName+"$");
                }
            }
        }
        final String _fieldName = fieldName;
        fieldFilter.run(new Atom() {
            public void run() {
                opt.addUpdateAndIncrIfMatch(opt.entity, obj, _fieldName);
                opt.exec();}
        });
        return opt.getUpdateCount();
    }

    public int updateWithVersion(Object obj) {
        return updateWithVersion(obj, null);
    }

    public int updateWithVersion(Object obj, FieldFilter fieldFilter) {
        return updateAndIncrIfMatch(obj, fieldFilter, getEntity(Lang.first(obj).getClass()).getVersionField().getName());
    }

    public <T> T fetchByJoin(Class<T> klass, String regex, long id) {
        Entity<T> en = getEntity(klass);
        MappingField mf = en.getIdField();
        return fetchByJoin(klass, regex, en, mf, id);
    }

    public <T> T fetchByJoin(Class<T> klass, String regex, String name) {
        Entity<T> en = getEntity(klass);
        MappingField mf = en.getNameField();
        return fetchByJoin(klass, regex, en, mf, name);
    }

    public <T> T fetchByJoin(Class<T> klass, String regex, Entity<T> en, MappingField mf, Object value) {
        String key = en.getTableName() + "." + mf.getColumnNameInSql();
        T t = fetchByJoin(klass, regex, Cnd.where(key, "=", value));
        if (t != null)
            _fetchLinks(t, regex, false, true, true, null);
        return t;
    }

    public <T> T fetchByJoin(Class<T> classOfT, String regex, Condition cnd) {
        return fetchByJoin(classOfT, regex, cnd, null);
    }

    public <T> T fetchByJoin(Class<T> classOfT, String regex, Condition cnd, Map<String, Condition> cnds) {
        Pojo pojo = pojoMaker.makeQueryByJoin(holder.getEntity(classOfT), regex)
                .append(Pojos.Items.cnd(cnd))
                .addParamsBy("*")
                .setPager(createPager(1, 1))
                .setAfter(new PojoFetchEntityByJoinCallback(regex));
        expert.formatQuery(pojo);
        _exec(pojo);
        T t = pojo.getObject(classOfT);
        if (t != null)
            _fetchLinks(t, regex, false, true, true, null, cnds);
        return t;
    }

    public <T> List<T> queryByJoin(Class<T> classOfT, String regex, Condition cnd) {
        return this.queryByJoin(classOfT, regex, cnd, null);
    }

    public <T> List<T> queryByJoin(Class<T> classOfT, String regex, Condition cnd, Pager pager) {
        return queryByJoin(classOfT, regex, cnd, pager, null);
    }

    public <T> List<T> queryByJoin(Class<T> classOfT, String regex, Condition cnd, Pager pager, Map<String, Condition> cnds) {
    	Pojo pojo = pojoMaker.makeQueryByJoin(holder.getEntity(classOfT), regex)
    			.append(Pojos.Items.cnd(cnd))
    			.addParamsBy("*")
    			.setPager(pager)
    			.setAfter(new PojoQueryEntityByJoinCallback(regex));
    	expert.formatQuery(pojo);
    	_exec(pojo);
    	List<T> list = pojo.getList(classOfT);
    	if (list != null && list.size() > 0)
    		for (T t : list) {
    			_fetchLinks(t, regex, false, true, true, null, cnds);
    		}
    	return list;
    }

    public <T> int countByJoin(Class<T> classOfT, String regex, Condition cnd) {
        Pojo pojo = pojoMaker.makeCountByJoin(holder.getEntity(classOfT), regex)
                .append(Pojos.Items.cnd(cnd))
                .addParamsBy("*")
                .setAfter(_pojo_fetchInt);
        expert.formatQuery(pojo);
        _exec(pojo);
        return pojo.getInt(0);
    }

    protected Object _fetchLinks(Object t, String regex, boolean visitOne, boolean visitMany, boolean visitManyMany, final Condition cnd) {
        return _fetchLinks(t, regex, visitOne, visitMany, visitManyMany, cnd, null);
    }

    protected Object _fetchLinks(Object t, String regex, boolean visitOne, boolean visitMany, boolean visitManyMany, final Condition cnd, final Map<String, Condition> cnds) {
        EntityOperator opt = _optBy(t);
        if (null == opt)
            return t;
        if (visitMany)
            opt.entity.visitMany(t, regex, doLinkQuery(opt, cnd, cnds));
        if (visitManyMany)
            opt.entity.visitManyMany(t, regex, doLinkQuery(opt, cnd, cnds));
        if (visitOne)
            opt.entity.visitOne(t, regex, doFetch(opt));
        opt.exec();
        return t;
    }

    public EntityHolder getEntityHolder() {
        return holder;
    }

    public <T> T insert(T obj, String actived) {
        Object first = Lang.first(obj);
        if (null == first)
            return null;

        if (Strings.isBlank(actived))
            return insert(obj);

        return insert(obj, FieldFilter.create(first.getClass(), actived));
    }

    @Override
    public void truncate(Class<?> klass) {
        Entity<?> en = getEntity(klass);
        truncate(en.getTableName());
    }

    @Override
    public void truncate(String tableName) {
        if (!exists(tableName))
            return;
        Sql sql = Sqls.createf("TRUNCATE TABLE %s", tableName);
        _exec(sql);
        return;
    }
}


package org.nutz.mvc.impl.processor;

import javax.servlet.http.HttpServletRequest;

import org.nutz.lang.Lang;
import org.nutz.lang.util.Context;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionInfo;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.NutConfig;
import org.nutz.mvc.View;
import org.nutz.mvc.ViewModel;
import org.nutz.mvc.view.ViewWrapper;
import org.nutz.mvc.view.ViewZone;

public class ViewProcessor extends AbstractProcessor {

    protected View view;
    public static final String DEFAULT_ATTRIBUTE = "obj";
    private static final Log log = Logs.get();
    protected int index = -1;

    @Override
    public void init(NutConfig config, ActionInfo ai) throws Throwable {
        //需要特别提醒一下使用jsonView,但方法的返回值是String的!!
        if("json".equals(ai.getOkView()) && String.class.equals(ai.getMethod().getReturnType())) {
            log.warn("Not a good idea : Return String ,and using JsonView!! (Using @Ok(\"raw\") or return map/list/pojo)--> " + Lang.simpleMethodDesc(ai.getMethod()));
        }
        view = evalView(config, ai, ai.getOkView());

        Class<?>[] params = ai.getMethod().getParameterTypes();
        for (int i = 0; i < params.length; i++) {
            if (ViewModel.class.isAssignableFrom(params[i])) {
                index = i;
                break;
            }
        }
        if (view instanceof ViewZone)
            ((ViewZone)view).setIndex(index);
    }

    public void process(ActionContext ac) throws Throwable {
        Object re = ac.getMethodReturn();
        Object err = ac.getError();
        if (Mvcs.SKIP_COMMITTED && ac.getResponse().isCommitted()) {
            log.info("Response is committed, skip mvc view render");
            doNext(ac);
            return;
        }
        if (re != null && re instanceof View) {
            if (re instanceof ViewWrapper)
                putRequestAttribute(ac.getRequest(), ((ViewWrapper)re).getData());
            ((View) re).render(ac.getRequest(), ac.getResponse(), err);
        } else {
            if (view instanceof ViewZone) {
                if (index > -1)
                    putRequestAttribute(ac.getRequest(), ac.getMethodArgs()[index]);
                view.render(ac.getRequest(), ac.getResponse(), re);
            } else {
                if (index > -1 && re == null && err == null) {
                    re = ac.getMethodArgs()[index];
                }
                putRequestAttribute(ac.getRequest(), null == re ? err : re);
                view.render(ac.getRequest(), ac.getResponse(), null == re ? err : re);
            }
        }
        doNext(ac);
    }

    /**
     * 保存对象到attribute
     */
    public static void putRequestAttribute(HttpServletRequest req, Object re){
        if (null != re){
            if(re instanceof Context){
                Context context = (Context) re;
                for(String key : context.keys()){
                    req.setAttribute(key, context.get(key));
                }
            } else {
                req.setAttribute(ViewProcessor.DEFAULT_ATTRIBUTE, re);
            }
        }
    }

    public static View evalView(NutConfig config, ActionInfo ai, String viewType) {
        return ViewZone.makeView(config, ai, viewType, true);
    }
}


package org.nutz.mvc.adaptor;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.nutz.lang.Mirror;
import org.nutz.mvc.adaptor.convertor.ArrayParamConvertor;
import org.nutz.mvc.adaptor.convertor.BooleanParamConvertor;
import org.nutz.mvc.adaptor.convertor.DateParamConvertor;
import org.nutz.mvc.adaptor.convertor.StringParamConvertor;
import org.nutz.mvc.adaptor.extractor.BaseParamExtractor;
import org.nutz.mvc.adaptor.extractor.MapParamExtractor;

public abstract class Params {

    /**
     * 构造参数转换器
     *
     * @param type
     *            要转换的目标类型
     * @param datefmt
     *            如果目标类型是 DateTime 类似的类型，可以声明一个特殊转换格式，<br>
     *            如果为 null 表示用 Times.D 函数自动猜测
     */
    public static ParamConvertor makeParamConvertor(Class<?> type,
                                                    String datefmt) {
        return makeParamConvertor(type, datefmt, null);
    }
    public static ParamConvertor makeParamConvertor(Class<?> type,
                                                    String datefmt,
                                                    String locale) {
        if (type.isArray())
            return new ArrayParamConvertor(type.getComponentType());

        Mirror<?> mirror = Mirror.me(type);
        if (mirror.isDateTimeLike()) {
            return new DateParamConvertor(type, datefmt, locale);
        }
        if (mirror.isBoolean()) {
            return new BooleanParamConvertor();
        }

        return new StringParamConvertor();
    }

    /**
     * 构造参数提取器
     */
    @SuppressWarnings("unchecked")
    public static ParamExtractor makeParamExtractor(HttpServletRequest req,
                                                    Object refer) {
        if (refer != null && Map.class.isAssignableFrom(refer.getClass())) {
            return new MapParamExtractor(req, (Map<String, Object>) refer);
        }
        return new BaseParamExtractor(req);
    }

    public static final String ParamDefaultTag = "//NOT EXIST IN//";
}