Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.glaf.core.entity.mybatis; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.MappedStatement.Builder; import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import com.glaf.core.config.BaseConfiguration; import com.glaf.core.config.Configuration; import com.glaf.core.config.DBConfiguration; import com.glaf.core.config.Environment; import com.glaf.core.dialect.Dialect; import com.glaf.core.util.SQLFormatter; @Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class MyBatisOffsetLimitInterceptor implements Interceptor { protected final static Log logger = LogFactory.getLog(MyBatisOffsetLimitInterceptor.class); protected static Configuration conf = BaseConfiguration.create(); protected static ConcurrentMap<String, Dialect> dialects = new ConcurrentHashMap<String, Dialect>(); static int MAPPED_STATEMENT_INDEX = 0; static int PARAMETER_INDEX = 1; static int ROWBOUNDS_INDEX = 2; static int RESULT_HANDLER_INDEX = 3; public static class BoundSqlSqlSource implements SqlSource { BoundSql boundSql; public BoundSqlSqlSource(BoundSql boundSql) { this.boundSql = boundSql; } public BoundSql getBoundSql(Object parameterObject) { return boundSql; } } private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) { BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject()); for (ParameterMapping mapping : boundSql.getParameterMappings()) { String prop = mapping.getProperty(); if (boundSql.hasAdditionalParameter(prop)) { newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop)); } } return newBoundSql; } // see: PersistenceBuilderAssistant private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) { Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType()); builder.resource(ms.getResource()); builder.fetchSize(ms.getFetchSize()); builder.statementType(ms.getStatementType()); builder.keyGenerator(ms.getKeyGenerator()); // setStatementTimeout() builder.timeout(ms.getTimeout()); // setStatementResultMap() builder.parameterMap(ms.getParameterMap()); // setStatementResultMap() builder.resultMaps(ms.getResultMaps()); builder.resultSetType(ms.getResultSetType()); // setStatementCache() builder.cache(ms.getCache()); builder.flushCacheRequired(ms.isFlushCacheRequired()); builder.useCache(ms.isUseCache()); return builder.build(); } public Object intercept(Invocation invocation) throws Throwable { processIntercept(invocation.getArgs()); return invocation.proceed(); } public Object plugin(Object target) { return Plugin.wrap(target, this); } void processIntercept(final Object[] queryArgs) { // queryArgs = query(MappedStatement ms, Object parameter, RowBounds // rowBounds, ResultHandler resultHandler) MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX]; Object parameter = queryArgs[PARAMETER_INDEX]; final RowBounds rowBounds = (RowBounds) queryArgs[ROWBOUNDS_INDEX]; int offset = rowBounds.getOffset(); int limit = rowBounds.getLimit(); String currentSystemName = Environment.getCurrentSystemName(); Dialect dialect = null; if (conf.getBoolean("useDatabaseDialect", true)) { if (dialects.isEmpty()) { Map<String, Dialect> rows = DBConfiguration.getDatabaseDialects(); Iterator<Entry<String, Dialect>> iterator = rows.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Dialect> entry = iterator.next(); String key = (String) entry.getKey(); Dialect d = entry.getValue(); dialects.put(key, d); } } logger.debug("currentSystemName:" + currentSystemName); dialect = dialects.get(currentSystemName); } if (dialect != null && dialect.supportsLimit() && (offset != RowBounds.NO_ROW_OFFSET || limit != RowBounds.NO_ROW_LIMIT)) { logger.debug("dialect:" + dialect.getClass().getName()); BoundSql boundSql = ms.getBoundSql(parameter); String sql = boundSql.getSql().trim(); if (dialect.supportsLimit()) { sql = dialect.getLimitString(sql, offset, limit); offset = RowBounds.NO_ROW_OFFSET; } else { sql = dialect.getLimitString(sql, 0, limit); } limit = RowBounds.NO_ROW_LIMIT; queryArgs[ROWBOUNDS_INDEX] = new RowBounds(offset, limit); BoundSql newBoundSql = copyFromBoundSql(ms, boundSql, sql); MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql)); queryArgs[MAPPED_STATEMENT_INDEX] = newMs; if (logger.isDebugEnabled()) { String sql2 = newBoundSql.getSql(); SQLFormatter f = new SQLFormatter(); sql2 = f.format(sql2); logger.debug("limit sql:\n" + sql2); } } } public void setProperties(Properties properties) { String dialectClass = properties.getProperty("dialectClass"); if (dialectClass != null) { try { Dialect dialect = (Dialect) Class.forName(dialectClass).newInstance(); dialects.put(Environment.DEFAULT_SYSTEM_NAME, dialect); } catch (Exception ex) { throw new RuntimeException("cannot create dialect instance by dialect:" + dialectClass, ex); } logger.info(MyBatisOffsetLimitInterceptor.class.getSimpleName() + ".dialect=" + dialectClass); } if (conf.getBoolean("useDatabaseDialect", true)) { Map<String, Dialect> rows = DBConfiguration.getDatabaseDialects(); Iterator<Entry<String, Dialect>> iterator = rows.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Dialect> entry = iterator.next(); String key = (String) entry.getKey(); Dialect dialect = entry.getValue(); dialects.put(key, dialect); } } } }