com.tiamaes.mybatis.SqlUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.tiamaes.mybatis.SqlUtil.java

Source

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 abel533@gmail.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.tiamaes.mybatis;

import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.builder.annotation.ProviderSqlSource;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.RawSqlSource;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.session.RowBounds;

import com.tiamaes.mybatis.parser.Parser;
import com.tiamaes.mybatis.parser.impl.AbstractParser;
import com.tiamaes.mybatis.parser.impl.CacheParser;
import com.tiamaes.mybatis.sqlsource.*;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Mybatis - sql?countMappedStatement?
 *
 * @author liuzh/abel533/isea533
 * @since 3.6.0
 * ? : http://git.oschina.net/free/Mybatis_PageHelper
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class SqlUtil implements Constant {
    private static final ThreadLocal<Pagination> LOCAL_PAGE = new ThreadLocal<Pagination>();
    //params?
    private static Map<String, String> PARAMS = new HashMap<String, String>(5);
    //request?
    private static Boolean hasRequest;
    private static Class<?> requestClass;
    private static Method getParameterMap;

    static {
        try {
            requestClass = Class.forName("javax.servlet.ServletRequest");
            getParameterMap = requestClass.getMethod("getParameterMap", new Class[] {});
            hasRequest = true;
        } catch (Throwable e) {
            hasRequest = false;
        }
    }

    //countms
    private static final Map<String, MappedStatement> msCountMap = new ConcurrentHashMap<String, MappedStatement>();
    //RowBounds?offsetPageNum - ?
    private boolean offsetAsPageNum = false;
    //RowBounds?count - ?
    private boolean rowBoundsWithCount = false;
    //truepagesize0RowBoundslimit=0?
    private boolean pageSizeZero = false;
    //??
    private boolean reasonable = false;
    //?parser
    private Parser parser;
    //??????false
    private boolean supportMethodsArguments = false;

    /**
     * 
     *
     * @param strDialect
     */
    public SqlUtil(String strDialect) {
        this(strDialect, null);
    }

    /**
     * 
     *
     * @param strDialect
     */
    public SqlUtil(String strDialect, String cacheClass) {
        if (strDialect == null || "".equals(strDialect)) {
            throw new IllegalArgumentException("Mybatis??dialect?!");
        }
        Exception exception = null;
        try {
            Dialect dialect = Dialect.of(strDialect);
            parser = AbstractParser.newParser(dialect, cacheClass);
        } catch (Exception e) {
            exception = e;
            //?????
            try {
                Class<?> parserClass = Class.forName(strDialect);
                if (Parser.class.isAssignableFrom(parserClass)) {
                    parser = (Parser) parserClass.newInstance();
                    //?falseMoonFruit???
                    if (StringUtil.isEmpty(cacheClass) || !cacheClass.equalsIgnoreCase("false")) {
                        parser = new CacheParser(parser, cacheClass);
                    }
                }
            } catch (ClassNotFoundException ex) {
                exception = ex;
            } catch (InstantiationException ex) {
                exception = ex;
            } catch (IllegalAccessException ex) {
                exception = ex;
            }
        }
        if (parser == null) {
            throw new RuntimeException(exception);
        }
    }

    public static Boolean getCOUNT() {
        Pagination page = getLocalPage();
        if (page != null) {
            return page.getCountSignal();
        }
        return null;
    }

    /**
     * ?Page?
     *
     * @return
     */
    public static <T> Pagination<T> getLocalPage() {
        return LOCAL_PAGE.get();
    }

    public static void setLocalPage(Pagination page) {
        LOCAL_PAGE.set(page);
    }

    /**
     * ??
     */
    public static void clearLocalPage() {
        LOCAL_PAGE.remove();
    }

    /**
     * ??
     *
     * @param params
     * @return
     */
    public static <T> Pagination<T> getPageFromObject(Object params) {
        int pageNum;
        int pageSize;
        MetaObject paramsObject = null;
        if (params == null) {
            throw new NullPointerException("??!");
        }
        if (hasRequest && requestClass.isAssignableFrom(params.getClass())) {
            try {
                paramsObject = SystemMetaObject.forObject(getParameterMap.invoke(params, new Object[] {}));
            } catch (Exception e) {
                //
            }
        } else {
            paramsObject = SystemMetaObject.forObject(params);
        }
        if (paramsObject == null) {
            throw new NullPointerException("??!");
        }
        Object orderBy = getParamValue(paramsObject, "orderBy", false);
        boolean hasOrderBy = false;
        if (orderBy != null && orderBy.toString().length() > 0) {
            hasOrderBy = true;
        }
        try {
            Object _pageNum = getParamValue(paramsObject, "pageNum", hasOrderBy ? false : true);
            Object _pageSize = getParamValue(paramsObject, "pageSize", hasOrderBy ? false : true);
            if (_pageNum == null || _pageSize == null) {
                Pagination page = new Pagination();
                page.setOrderBy(orderBy.toString());
                page.setOrderByOnly(true);
                return page;
            }
            pageNum = Integer.parseInt(String.valueOf(_pageNum));
            pageSize = Integer.parseInt(String.valueOf(_pageSize));
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("???!");
        }
        Pagination page = new Pagination(pageNum, pageSize);
        //count
        Object _count = getParamValue(paramsObject, "count", false);
        if (_count != null) {
            page.setCount(Boolean.valueOf(String.valueOf(_count)));
        }
        //?
        if (hasOrderBy) {
            page.setOrderBy(orderBy.toString());
        }
        //??
        Object reasonable = getParamValue(paramsObject, "reasonable", false);
        if (reasonable != null) {
            page.setReasonable(Boolean.valueOf(String.valueOf(reasonable)));
        }
        //
        Object pageSizeZero = getParamValue(paramsObject, "pageSizeZero", false);
        if (pageSizeZero != null) {
            page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero)));
        }
        return page;
    }

    /**
     * ??
     *
     * @param paramsObject
     * @param paramName
     * @param required
     * @return
     */
    public static Object getParamValue(MetaObject paramsObject, String paramName, boolean required) {
        Object value = null;
        if (paramsObject.hasGetter(PARAMS.get(paramName))) {
            value = paramsObject.getValue(PARAMS.get(paramName));
        }
        if (value != null && value.getClass().isArray()) {
            Object[] values = (Object[]) value;
            if (values.length == 0) {
                value = null;
            } else {
                value = values[0];
            }
        }
        if (required && value == null) {
            throw new RuntimeException("??:" + PARAMS.get(paramName));
        }
        return value;
    }

    /**
     * ???
     *
     * @param ms
     * @return
     */
    public boolean isPageSqlSource(MappedStatement ms) {
        if (ms.getSqlSource() instanceof PageSqlSource) {
            return true;
        }
        return false;
    }

    /**
     * [?]countsql
     *
     * @param dialect     ?
     * @param originalSql sql
     * @deprecated 5.x
     */
    @Deprecated
    public static void testSql(String dialect, String originalSql) {
        testSql(Dialect.of(dialect), originalSql);
    }

    /**
     * [?]countsql
     *
     * @param dialect     ?
     * @param originalSql sql
     * @deprecated 5.x
     */
    @Deprecated
    public static void testSql(Dialect dialect, String originalSql) {
        Parser parser = AbstractParser.newParser(dialect);
        if (dialect == Dialect.sqlserver) {
            setLocalPage(new Pagination(1, 10));
        }
        String countSql = parser.getCountSql(originalSql);
        System.out.println(countSql);
        String pageSql = parser.getPageSql(originalSql);
        System.out.println(pageSql);
        if (dialect == Dialect.sqlserver) {
            clearLocalPage();
        }
    }

    /**
     * SqlSource
     *
     * @param ms
     * @throws Throwable
     */
    public void processMappedStatement(MappedStatement ms) throws Throwable {
        SqlSource sqlSource = ms.getSqlSource();
        MetaObject msObject = SystemMetaObject.forObject(ms);
        SqlSource pageSqlSource;
        if (sqlSource instanceof StaticSqlSource) {
            pageSqlSource = new PageStaticSqlSource((StaticSqlSource) sqlSource);
        } else if (sqlSource instanceof RawSqlSource) {
            pageSqlSource = new PageRawSqlSource((RawSqlSource) sqlSource);
        } else if (sqlSource instanceof ProviderSqlSource) {
            pageSqlSource = new PageProviderSqlSource((ProviderSqlSource) sqlSource);
        } else if (sqlSource instanceof DynamicSqlSource) {
            pageSqlSource = new PageDynamicSqlSource((DynamicSqlSource) sqlSource);
        } else {
            throw new RuntimeException("?[" + sqlSource.getClass() + "]SqlSource");
        }
        msObject.setValue("sqlSource", pageSqlSource);
        //count??CountMS
        msCountMap.put(ms.getId(), MSUtils.newCountMappedStatement(ms));
    }

    /**
     * ??
     *
     * @param args
     * @return Page
     */
    public Pagination getPage(Object[] args) {
        Pagination page = getLocalPage();
        if (page == null || page.isOrderByOnly()) {
            Pagination oldPage = page;
            //?,page.isOrderByOnly()true??
            if ((args[2] == null || args[2] == RowBounds.DEFAULT) && page != null) {
                return oldPage;
            }
            if (args[2] instanceof RowBounds && args[2] != RowBounds.DEFAULT) {
                RowBounds rowBounds = (RowBounds) args[2];
                if (offsetAsPageNum) {
                    page = new Pagination(rowBounds.getOffset(), rowBounds.getLimit(), rowBoundsWithCount);
                } else {
                    page = new Pagination(new int[] { rowBounds.getOffset(), rowBounds.getLimit() },
                            rowBoundsWithCount);
                    //offsetAsPageNum=falsePageNum?reasonablefalse
                    page.setReasonable(false);
                }
            } else {
                try {
                    page = getPageFromObject(args[1]);
                } catch (Exception e) {
                    return null;
                }
            }
            if (oldPage != null) {
                page.setOrderBy(oldPage.getOrderBy());
            }
            setLocalPage(page);
        }
        //??
        if (page.getReasonable() == null) {
            page.setReasonable(reasonable);
        }
        //truepagesize0RowBoundslimit=0?
        if (page.getPageSizeZero() == null) {
            page.setPageSizeZero(pageSizeZero);
        }
        return page;
    }

    /**
     * Mybatis?Threadlocal
     *
     * @param invocation ?
     * @return 
     * @throws Throwable 
     */
    public Object processPage(Invocation invocation) throws Throwable {
        try {
            Object result = _processPage(invocation);
            return result;
        } finally {
            clearLocalPage();
        }
    }

    /**
     * Mybatis
     *
     * @param invocation ?
     * @return 
     * @throws Throwable 
     */
    private Object _processPage(Invocation invocation) throws Throwable {
        final Object[] args = invocation.getArgs();
        Pagination page = null;
        //????Page
        if (supportMethodsArguments) {
            page = getPage(args);
        }
        //?
        RowBounds rowBounds = (RowBounds) args[2];
        //??page == null???
        if ((supportMethodsArguments && page == null)
                //???LocalPageRowBounds??
                || (!supportMethodsArguments && SqlUtil.getLocalPage() == null && rowBounds == RowBounds.DEFAULT)) {
            return invocation.proceed();
        } else {
            //???page==null??
            if (!supportMethodsArguments && page == null) {
                page = getPage(args);
            }
            return doProcessPage(invocation, page, args);
        }
    }

    /**
     * ???
     *
     * @param page
     * @return
     */
    private boolean isQueryOnly(Pagination page) {
        return page.isOrderByOnly()
                || ((page.getPageSizeZero() != null && page.getPageSizeZero()) && page.getPageSize() == 0);
    }

    /**
     * ??
     *
     * @param page
     * @param invocation
     * @return
     * @throws Throwable
     */
    private Pagination doQueryOnly(Pagination page, Invocation invocation) throws Throwable {
        page.setCountSignal(null);
        //?
        Object result = invocation.proceed();
        //?
        page.addAll((List) result);
        //
        page.setPageNum(1);
        //?pageSize=total
        page.setPageSize(page.size());
        //??total
        page.setTotal(page.size());
        //?Page - ???
        return page;
    }

    /**
     * Mybatis
     *
     * @param invocation ?
     * @return 
     * @throws Throwable 
     */
    private Pagination doProcessPage(Invocation invocation, Pagination page, Object[] args) throws Throwable {
        //?RowBounds?
        RowBounds rowBounds = (RowBounds) args[2];
        //?ms
        MappedStatement ms = (MappedStatement) args[0];
        //?PageSqlSource
        if (!isPageSqlSource(ms)) {
            processMappedStatement(ms);
        }
        //?parser????setThreadLocal???
        ((PageSqlSource) ms.getSqlSource()).setParser(parser);
        try {
            //RowBounds-?Mybatis
            args[2] = RowBounds.DEFAULT;
            //??  pageSizeZero
            if (isQueryOnly(page)) {
                return doQueryOnly(page, invocation);
            }

            //?total??count
            if (page.isCount()) {
                page.setCountSignal(Boolean.TRUE);
                //?MS
                args[0] = msCountMap.get(ms.getId());
                //
                Object result = invocation.proceed();
                //ms
                args[0] = ms;
                //
                page.setTotal((Integer) ((List) result).get(0));
                if (page.getTotal() == 0) {
                    return page;
                }
            } else {
                page.setTotal(-1l);
            }
            //pageSize>0pageSize<=0???count
            if (page.getPageSize() > 0 && ((rowBounds == RowBounds.DEFAULT && page.getPageNum() > 0)
                    || rowBounds != RowBounds.DEFAULT)) {
                //?MappedStatement?qs
                page.setCountSignal(null);
                BoundSql boundSql = ms.getBoundSql(args[1]);
                args[1] = parser.setPageParameter(ms, args[1], boundSql, page);
                page.setCountSignal(Boolean.FALSE);
                //
                Object result = invocation.proceed();
                //?
                page.addAll((List) result);
            }
        } finally {
            ((PageSqlSource) ms.getSqlSource()).removeParser();
        }

        //
        return page;
    }

    public void setOffsetAsPageNum(boolean offsetAsPageNum) {
        this.offsetAsPageNum = offsetAsPageNum;
    }

    public void setRowBoundsWithCount(boolean rowBoundsWithCount) {
        this.rowBoundsWithCount = rowBoundsWithCount;
    }

    public void setPageSizeZero(boolean pageSizeZero) {
        this.pageSizeZero = pageSizeZero;
    }

    public void setReasonable(boolean reasonable) {
        this.reasonable = reasonable;
    }

    public void setSupportMethodsArguments(boolean supportMethodsArguments) {
        this.supportMethodsArguments = supportMethodsArguments;
    }

    public static void setParams(String params) {
        PARAMS.put("pageNum", "pageNum");
        PARAMS.put("pageSize", "pageSize");
        PARAMS.put("count", "countSql");
        PARAMS.put("orderBy", "orderBy");
        PARAMS.put("reasonable", "reasonable");
        PARAMS.put("pageSizeZero", "pageSizeZero");
        if (StringUtil.isNotEmpty(params)) {
            String[] ps = params.split("[;|,|&]");
            for (String s : ps) {
                String[] ss = s.split("[=|:]");
                if (ss.length == 2) {
                    PARAMS.put(ss[0], ss[1]);
                }
            }
        }
    }

    public void setProperties(Properties p) {
        //offsetPageNum
        String offsetAsPageNum = p.getProperty("offsetAsPageNum");
        this.offsetAsPageNum = Boolean.parseBoolean(offsetAsPageNum);
        //RowBounds???count
        String rowBoundsWithCount = p.getProperty("rowBoundsWithCount");
        this.rowBoundsWithCount = Boolean.parseBoolean(rowBoundsWithCount);
        //truepagesize0RowBoundslimit=0?
        String pageSizeZero = p.getProperty("pageSizeZero");
        this.pageSizeZero = Boolean.parseBoolean(pageSizeZero);
        //??true?????false??
        String reasonable = p.getProperty("reasonable");
        this.reasonable = Boolean.parseBoolean(reasonable);
        //??????false
        String supportMethodsArguments = p.getProperty("supportMethodsArguments");
        this.supportMethodsArguments = Boolean.parseBoolean(supportMethodsArguments);
        //offsetAsPageNum=false?
        //?
        setParams(p.getProperty("params"));
    }

    public void setSqlUtilConfig(SqlUtilConfig config) {
        this.offsetAsPageNum = config.isOffsetAsPageNum();
        this.rowBoundsWithCount = config.isRowBoundsWithCount();
        this.pageSizeZero = config.isPageSizeZero();
        this.reasonable = config.isReasonable();
        this.supportMethodsArguments = config.isSupportMethodsArguments();
        setParams(config.getParams());
    }
}