001: /*
002: Copyright (C) 2007 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022: */
023:
024: package com.mysql.jdbc.interceptors;
025:
026: import java.lang.reflect.InvocationHandler;
027: import java.lang.reflect.Method;
028: import java.lang.reflect.Proxy;
029: import java.sql.SQLException;
030: import java.util.Properties;
031: import java.util.regex.Matcher;
032: import java.util.regex.Pattern;
033:
034: import com.mysql.jdbc.Connection;
035: import com.mysql.jdbc.ResultSetInternalMethods;
036: import com.mysql.jdbc.Statement;
037: import com.mysql.jdbc.StatementInterceptor;
038:
039: public class ResultSetScannerInterceptor implements
040: StatementInterceptor {
041:
042: private Pattern regexP;
043:
044: public void init(Connection conn, Properties props)
045: throws SQLException {
046: String regexFromUser = props
047: .getProperty("resultSetScannerRegex");
048:
049: if (regexFromUser == null || regexFromUser.length() == 0) {
050: throw new SQLException(
051: "resultSetScannerRegex must be configured, and must be > 0 characters");
052: }
053:
054: try {
055: this .regexP = Pattern.compile(regexFromUser);
056: } catch (Throwable t) {
057: SQLException sqlEx = new SQLException(
058: "Can't use configured regex due to underlying exception.");
059: sqlEx.initCause(t);
060:
061: throw sqlEx;
062: }
063:
064: }
065:
066: public ResultSetInternalMethods postProcess(String sql,
067: Statement interceptedStatement,
068: ResultSetInternalMethods originalResultSet,
069: Connection connection) throws SQLException {
070:
071: // requirement of anonymous class
072: final ResultSetInternalMethods finalResultSet = originalResultSet;
073:
074: return (ResultSetInternalMethods) Proxy.newProxyInstance(
075: originalResultSet.getClass().getClassLoader(),
076: new Class[] { ResultSetInternalMethods.class },
077: new InvocationHandler() {
078:
079: public Object invoke(Object proxy, Method method,
080: Object[] args) throws Throwable {
081:
082: Object invocationResult = method.invoke(
083: finalResultSet, args);
084:
085: String methodName = method.getName();
086:
087: if (invocationResult != null
088: && invocationResult instanceof String
089: || "getString".equals(methodName)
090: || "getObject".equals(methodName)
091: || "getObjectStoredProc"
092: .equals(methodName)) {
093: Matcher matcher = regexP
094: .matcher(invocationResult
095: .toString());
096:
097: if (matcher.matches()) {
098: throw new SQLException(
099: "value disallowed by filter");
100: }
101: }
102:
103: return invocationResult;
104: }
105: });
106:
107: }
108:
109: public ResultSetInternalMethods preProcess(String sql,
110: Statement interceptedStatement, Connection connection)
111: throws SQLException {
112: // we don't care about this event
113:
114: return null;
115: }
116:
117: // we don't issue queries, so it should be safe to intercept
118: // at any point
119: public boolean executeTopLevelOnly() {
120: return false;
121: }
122: }
|