improve WallFilter

This commit is contained in:
wenshao
2013-03-17 08:41:41 +08:00
parent eec1ab34e5
commit c6182111d9
5 changed files with 237 additions and 62 deletions
@@ -0,0 +1,34 @@
package com.alibaba.druid.wall;
public class WallContext {
private final static ThreadLocal<WallContext> contextLocal = new ThreadLocal<WallContext>();
private WallSqlStat sqlState;
public static WallContext createIfNotExists() {
WallContext context = contextLocal.get();
if (context == null) {
context = new WallContext();
contextLocal.set(context);
}
return context;
}
public static WallContext current() {
return contextLocal.get();
}
public static void clearContext() {
contextLocal.remove();
}
public WallSqlStat getSqlState() {
return sqlState;
}
public void setSqlState(WallSqlStat sqlState) {
this.sqlState = sqlState;
}
}
@@ -159,139 +159,235 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
@Override
public void statement_addBatch(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
sql = check(sql);
chain.statement_addBatch(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
chain.statement_addBatch(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int autoGeneratedKeys) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, autoGeneratedKeys);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int resultSetType, int resultSetConcurrency)
throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, int[] columnIndexes) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnIndexes);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnIndexes);
} finally {
WallContext.clearContext();
}
}
@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection,
String sql, String[] columnNames) throws SQLException {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnNames);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareStatement(connection, sql, columnNames);
} finally {
WallContext.clearContext();
}
}
@Override
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
sql = check(sql);
return chain.connection_prepareCall(connection, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareCall(connection, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
int resultSetType, int resultSetConcurrency)
throws SQLException {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency);
} finally {
WallContext.clearContext();
}
}
@Override
public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql,
int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.connection_prepareCall(connection, sql, resultSetType, resultSetConcurrency,
resultSetHoldability);
} finally {
WallContext.clearContext();
}
}
// //////////////
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql, autoGeneratedKeys);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql, autoGeneratedKeys);
} finally {
WallContext.clearContext();
}
}
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql, columnIndexes);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql, columnIndexes);
} finally {
WallContext.clearContext();
}
}
@Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
throws SQLException {
sql = check(sql);
return chain.statement_execute(statement, sql, columnNames);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_execute(statement, sql, columnNames);
} finally {
WallContext.clearContext();
}
}
@Override
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
throws SQLException {
sql = check(sql);
return chain.statement_executeQuery(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeQuery(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, autoGeneratedKeys);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int columnIndexes[])
throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnIndexes);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnIndexes);
} finally {
WallContext.clearContext();
}
}
@Override
public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String columnNames[])
throws SQLException {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnNames);
WallContext.createIfNotExists();
try {
sql = check(sql);
return chain.statement_executeUpdate(statement, sql, columnNames);
} finally {
WallContext.clearContext();
}
}
public String check(String sql) throws SQLException {
@@ -355,7 +451,7 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
if (isLogViolation()) {
LOG.error("not support method : Connection.getMetdataData");
}
if (throwException) {
throw new WallSQLException("not support method : Connection.getMetdataData");
} else {
@@ -369,4 +465,16 @@ public class WallFilter extends FilterAdapter implements WallFilterMBean {
public long getViolationCount() {
return this.violationCount.get();
}
public void resetViolationCount() {
this.violationCount.set(0);
}
public void clearWhiteList() {
this.provider.clearCache();
}
public boolean checkValid(String sql) {
return provider.checkValid(sql);
}
}
@@ -39,4 +39,10 @@ public interface WallFilterMBean {
String check(String sql) throws SQLException;
long getViolationCount();
void resetViolationCount();
void clearWhiteList();
boolean checkValid(String sql);
}
@@ -32,20 +32,17 @@ import com.alibaba.druid.wall.violation.SyntaxErrorViolation;
public abstract class WallProvider {
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
private LinkedHashMap<String, WallSqlStat> whiteList;
private LinkedHashMap<String, Object> whiteList;
private int whileListMaxSize = 1024;
private int whileListMaxSize = 1024;
private int whiteSqlMaxLength = 1024; // 1k
private int whiteSqlMaxLength = 1024; // 1k
protected final WallConfig config;
protected final WallConfig config;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
private static final ThreadLocal<Boolean> privileged = new ThreadLocal<Boolean>();
public WallProvider(WallConfig config){
this.config = config;
@@ -59,10 +56,10 @@ public abstract class WallProvider {
lock.writeLock().lock();
try {
if (whiteList == null) {
whiteList = new LRUCache<String, Object>(whileListMaxSize);
whiteList = new LRUCache<String, WallSqlStat>(whileListMaxSize);
}
whiteList.put(sql, PRESENT);
whiteList.put(sql, new WallSqlStat());
} finally {
lock.writeLock().unlock();
}
@@ -81,8 +78,12 @@ public abstract class WallProvider {
return hashSet;
}
public void clearCache() {
clearWhiteList();
}
public void clearWhiteList() {
lock.writeLock().lock();
try {
if (whiteList != null) {
@@ -92,20 +93,24 @@ public abstract class WallProvider {
lock.writeLock().unlock();
}
}
public boolean whiteContains(String sql) {
public WallSqlStat getWhiteSql(String sql) {
lock.readLock().lock();
try {
if (whiteList == null) {
return false;
return null;
}
return whiteList.get(sql) != null;
return whiteList.get(sql);
} finally {
lock.readLock().unlock();
}
}
public boolean whiteContains(String sql) {
return getWhiteSql(sql) != null;
}
public abstract SQLStatementParser createParser(String sql);
public abstract WallVisitor createWallVisitor();
@@ -113,7 +118,8 @@ public abstract class WallProvider {
public abstract ExportParameterVisitor createExportParameterVisitor();
public boolean checkValid(String sql) {
return check(sql).getViolations().isEmpty();
WallCheckResult result = check(sql);
return result.getViolations().isEmpty();
}
public WallCheckResult check(String sql) {
@@ -124,8 +130,9 @@ public abstract class WallProvider {
}
// first step, check whiteList
boolean isWhite = whiteContains(sql);
if (isWhite) {
WallSqlStat sqlStat = getWhiteSql(sql);
if (sqlStat != null) {
sqlStat.incrementAndGetExecuteCount();
return result;
}
@@ -176,13 +183,13 @@ public abstract class WallProvider {
result.getViolations().addAll(visitor.getViolations());
return result;
}
public static boolean ispPivileged() {
Boolean value = privileged.get();
if (value == null) {
return false;
}
return value.booleanValue();
}
@@ -0,0 +1,20 @@
package com.alibaba.druid.wall;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
public class WallSqlStat {
private volatile long executeCount;
final static AtomicLongFieldUpdater<WallSqlStat> executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class,
"executeCount");
public long incrementAndGetExecuteCount() {
return executeCountUpdater.incrementAndGet(this);
}
public long getExecuteCount() {
return executeCount;
}
}