From c6182111d94f33b4251b8ef585622c86f6234576 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 17 Mar 2013 08:41:41 +0800 Subject: [PATCH] improve WallFilter --- .../com/alibaba/druid/wall/WallContext.java | 34 ++++ .../com/alibaba/druid/wall/WallFilter.java | 188 ++++++++++++++---- .../alibaba/druid/wall/WallFilterMBean.java | 6 + .../com/alibaba/druid/wall/WallProvider.java | 51 +++-- .../com/alibaba/druid/wall/WallSqlStat.java | 20 ++ 5 files changed, 237 insertions(+), 62 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/wall/WallContext.java create mode 100644 src/main/java/com/alibaba/druid/wall/WallSqlStat.java diff --git a/src/main/java/com/alibaba/druid/wall/WallContext.java b/src/main/java/com/alibaba/druid/wall/WallContext.java new file mode 100644 index 0000000000..96997cac14 --- /dev/null +++ b/src/main/java/com/alibaba/druid/wall/WallContext.java @@ -0,0 +1,34 @@ +package com.alibaba.druid.wall; + +public class WallContext { + + private final static ThreadLocal contextLocal = new ThreadLocal(); + + 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; + } + +} diff --git a/src/main/java/com/alibaba/druid/wall/WallFilter.java b/src/main/java/com/alibaba/druid/wall/WallFilter.java index 105fe339a0..81ccc0d57f 100644 --- a/src/main/java/com/alibaba/druid/wall/WallFilter.java +++ b/src/main/java/com/alibaba/druid/wall/WallFilter.java @@ -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); + } } diff --git a/src/main/java/com/alibaba/druid/wall/WallFilterMBean.java b/src/main/java/com/alibaba/druid/wall/WallFilterMBean.java index 297c12f336..bd2f51450c 100644 --- a/src/main/java/com/alibaba/druid/wall/WallFilterMBean.java +++ b/src/main/java/com/alibaba/druid/wall/WallFilterMBean.java @@ -39,4 +39,10 @@ public interface WallFilterMBean { String check(String sql) throws SQLException; long getViolationCount(); + + void resetViolationCount(); + + void clearWhiteList(); + + boolean checkValid(String sql); } diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index 92a15f36b6..4ec7e9d2f9 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -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 whiteList; - private LinkedHashMap 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 privileged = new ThreadLocal(); + private static final ThreadLocal privileged = new ThreadLocal(); 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(whileListMaxSize); + whiteList = new LRUCache(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(); } diff --git a/src/main/java/com/alibaba/druid/wall/WallSqlStat.java b/src/main/java/com/alibaba/druid/wall/WallSqlStat.java new file mode 100644 index 0000000000..224a676843 --- /dev/null +++ b/src/main/java/com/alibaba/druid/wall/WallSqlStat.java @@ -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 executeCountUpdater = AtomicLongFieldUpdater.newUpdater(WallSqlStat.class, + "executeCount"); + + public long incrementAndGetExecuteCount() { + return executeCountUpdater.incrementAndGet(this); + } + + public long getExecuteCount() { + return executeCount; + } + +}