Source Code Cross Referenced for JDBCMonProxy.java in  » Profiler » JAMon » com » jamonapi » proxy » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Profiler » JAMon » com.jamonapi.proxy 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package com.jamonapi.proxy;
002:
003:        import java.lang.reflect.Method;
004:        import java.util.Date;
005:        import java.sql.*;
006:        import java.util.*;
007:
008:        import com.jamonapi.*;
009:        import com.jamonapi.utils.*;
010:
011:        /**
012:         * Class that implements JDBC specific proxied monitoring.  The following are monitored by this class 1) All SQL statements executed.
013:         * For Statements argument values are replaced by '?' and for CallableStatements and PreparedStatement the original query with the '?'
014:         * is used (select * from table where key=?), 2) The first keyword of the SQL command (i.e. select/update/delete/insert/create/...
015:         * 3) String matches.  Developers pass in these strings. This is useful for tracking table accesses, 4) SQL Details.  This keeps track
016:         * of the most recent N queries.
017:         * 
018:         * In addition the standard MonProxy stats are tracked (Interface method calls, and Exception details).
019:         * *          
020:         *          */
021:
022:        class JDBCMonProxy extends MonProxy {
023:
024:            // The queries associated with the PreparedStatments are kept here.  PreparedStatements have no way to get the query out.
025:            // A weakHashMap() is used as you can't guarantee when a PreparedStatement closes, and there has to be some way of cleaning up
026:            // stale objects in the map.  WeakHashMaps() automatically remove any Object that has no other reference.
027:            private static Map statementsMap = Collections
028:                    .synchronizedMap(new WeakHashMap());
029:            private static Long DEFAULT_SQL_TIME = new Long(-99);// number for when the query hasn't finished executing yet.
030:            private static int ARGS_SQL_STATEMENT = 0;// The sql is always the first argument to methods like executeQuery(sql,...);
031:            // the following numbers correspond to this header
032:            //String[] sqlHeader={"ID", "StartTime", "Executiontime", "StatementReuse", "SQL",  "ExceptionStackTrace", "MethodName", };
033:            private static int SQL_EXECUTION_TIME_IND = 2;
034:            private static int SQL_EXCEPTION_IND = 5;
035:
036:            JDBCMonProxy(Object monitoredObj, Params params) {
037:                super (monitoredObj, params);
038:            }
039:
040:            /** Method that monitors method invocations of the proxied interface.  This method is not explicitly called.  
041:             *  The Proxy class automatically calls it. 
042:             *  
043:             *  
044:             */
045:            public Object invoke(Object proxy, Method method, Object[] args)
046:                    throws Throwable {
047:                BasicTimingMonitor mon = null;
048:                Object[] row = null;
049:                SQLDeArgMon sqlMon = null;
050:                // These values need to be checked at beginning and end of routine, so need to ensure they don't change during this method call
051:                // hence the local versions of them.
052:                boolean isSQLSummaryEnabled = params.isSQLSummaryEnabled
053:                        && params.isEnabled;
054:                boolean isSQLDetailEnabled = params.isSQLDetailEnabled
055:                        && params.isEnabled;
056:                boolean executingQuery = isExecuteQueryMethod(method.getName()); // determine if a query is being executed.
057:
058:                // Because this monitor string is created every time I use a StringBuffer as it should be more effecient.
059:                // I didn't do this in the exception part of the code as that shouldn't be called as often.
060:                try {
061:
062:                    // If enabled and the method that is being called executes a query then monitor the sql executed.  Note that 'Statement' 'execute'
063:                    // methods will have sql passed to them, and and PreparedStatement and CallableStatements will not.  
064:                    // When needed PrepatedStatement/CallableStatements will get their sql from the WeakHashMap  from when the PreparedStatement was created.  
065:                    if (executingQuery
066:                            && (isSQLSummaryEnabled || isSQLDetailEnabled)) {
067:                        String actualSQL = null;
068:                        // Start timing the query and add a row to the recently executed query buffer
069:                        mon = new BasicTimingMonitor();
070:                        mon.start();
071:
072:                        int statementReuseCounter = 0;//createStatement will always have a value of 0 as they can't be reused.  PreparedStaement is tracked
073:
074:                        if (isStatementObject(args)) {// a query associated with a Statement is being executed.
075:                            actualSQL = getSQL(args[ARGS_SQL_STATEMENT]);//get the sql being executed
076:                            sqlMon = new SQLDeArgMon("Statement", actualSQL,
077:                                    params.matchStrings);// parses sql and puts ? marks associated with args, and sets up monitors.
078:
079:                        } else { // a query associated with a PreparedStatement/CallableStatement is being executed
080:                            sqlMon = (SQLDeArgMon) statementsMap
081:                                    .get(getMonitoredObject()); // get existing object associated with this PreparedStatement/CallableStatement
082:                            statementReuseCounter = sqlMon.incrementCounter();// increment the reuse counter.
083:                            if (isSQLSummaryEnabled)
084:                                MonitorFactory.add(
085:                                        "MonProxy-SQL-PreparedStatement Reuse",
086:                                        "count", 2 * statementReuseCounter);// to get the average to be accurate multiply by 2
087:
088:                            actualSQL = getSQL(sqlMon.getSQL());// in the case of a preparedStatement the actual sql includes question marks.
089:
090:                        }
091:
092:                        // create a monitor for:  select * from table where name=?
093:                        if (isSQLSummaryEnabled)
094:                            sqlMon.start();
095:
096:                        if (isSQLDetailEnabled) {
097:                            row = new Object[] { new Long(++params.sqlID),
098:                                    new Date(), DEFAULT_SQL_TIME,
099:                                    new Integer(statementReuseCounter),
100:                                    actualSQL, "", method.toString(), };
101:                            params.sqlBuffer.addRow(row);
102:                        }
103:                    } // end if enabled
104:
105:                    // Invoke the underlying method
106:                    Object returnValue = super .invoke(proxy, method, args);
107:
108:                    // If sql monitoring is not enabled or if the proxy is already there then don't wrap a proxy.  For example Statements can 
109:                    // return the underlying Connection which will probably already be Monitored. Note for jdbc if the Object returns another jdbc Object
110:                    // type that should be monitored it will also be monitored.
111:                    if (!(params.isEnabled) || returnValue instanceof  MonProxy)
112:                        return returnValue;
113:                    else if ((isSQLSummaryEnabled || isSQLDetailEnabled)
114:                            && returnsPreparedStatement(method.getName())
115:                            && isPreparedStatement(returnValue)) { // not sure if the returnsPreparedStatement is needed or not
116:                        // Associate sql such as 'select * from table where name=?' with the PreparedStatement in the WeakHashMap so when later executeQuery() is 
117:                        // issued against the PreparedStatement we can count stats of the preparedStatements reuses.  PreparedStatements have no way of getting out
118:                        // what sql is associated.  WeakHashMap will not leave the memory hanging when the PreparedStatement goes out of scope.
119:                        String actualSQL = getSQL(args[ARGS_SQL_STATEMENT]);
120:                        statementsMap.put(returnValue, new SQLDeArgMon(
121:                                "PreparedStatement", actualSQL,
122:                                params.matchStrings));
123:                        return MonProxyFactory
124:                                .monitor((PreparedStatement) returnValue);
125:                    } else if ((isSQLSummaryEnabled || isSQLDetailEnabled)
126:                            && (monitorResultSet(returnValue) || monitorOtherJDBC(returnValue)))
127:                        return monitorJDBC(returnValue);
128:                    else
129:                        return returnValue;
130:
131:                } catch (Throwable e) {
132:
133:                    // If there is a stack trace it will be part of the SQL details row.  Note a user reported a null pointer exception being thrown,
134:                    // so i added the 'row!=null' check.
135:                    if (executingQuery && isSQLDetailEnabled && row != null)
136:                        row[SQL_EXCEPTION_IND] = Misc.getExceptionTrace(e);
137:
138:                    throw e;
139:                } finally {
140:
141:                    // mon != null means either or both of the sql detail monitoring or sql summary monitoring is enabled.
142:                    if (mon != null && executingQuery) {
143:                        long executionTime = mon.stop();
144:
145:                        if (isSQLDetailEnabled && row != null)
146:                            row[SQL_EXECUTION_TIME_IND] = new Long(
147:                                    executionTime);
148:
149:                        if (isSQLSummaryEnabled)
150:                            sqlMon.add(executionTime).stop();
151:                    }
152:
153:                }
154:            }
155:
156:            private boolean isExecuteQueryMethod(String methodName) {
157:                return "executeQuery".equals(methodName)
158:                        || "executeUpdate".equals(methodName)
159:                        || "execute".equals(methodName);
160:
161:            }
162:
163:            private boolean returnsPreparedStatement(String methodName) {
164:                return "prepareStatement".equals(methodName)
165:                        || "prepareCall".equals(methodName);
166:            }
167:
168:            private boolean isStatementObject(Object[] args) {
169:                return (args != null && args.length >= 1);
170:            }
171:
172:            private boolean monitorOtherJDBC(Object value) {
173:                return (value instanceof  Statement || value instanceof  Connection);
174:            }
175:
176:            private boolean monitorResultSet(Object value) {
177:                return (value instanceof  ResultSet && params.isResultSetEnabled && params.isInterfaceEnabled);
178:            }
179:
180:            private Object monitorJDBC(Object returnValue) {
181:                if (returnValue instanceof  ResultSet)
182:                    return MonProxyFactory.monitor((ResultSet) returnValue);
183:                else if (returnValue instanceof  Statement)
184:                    return MonProxyFactory.monitor((Statement) returnValue);
185:                else if (returnValue instanceof  Connection)
186:                    return MonProxyFactory.monitor((Connection) returnValue);
187:                else
188:                    return returnValue;
189:            }
190:
191:            // This will return true for CallableStatements too.
192:            private boolean isPreparedStatement(Object value) {
193:                return value instanceof  PreparedStatement;
194:            }
195:
196:            private String getSQL(Object sql) {
197:                return (sql == null) ? "null sql" : sql.toString();
198:            }
199:
200:            /**
201:             * This class associates queries with the PreparedStatement and tracks accesses to it.  It also removes values from a Statements sql and 
202:             * replaces it with '?'.  For example:  select * from table where key='steve', becomes select * from table where key=?
203:             * @author steve souza
204:             *
205:             */
206:            private static class SQLDeArgMon {
207:
208:                private int accessCounter = 0;
209:                private String sql;
210:
211:                private int monRows;
212:                private static final int LABEL_IND = 0;
213:                private MonitorComposite monitors = null;
214:                private String[][] data = null;
215:
216:                //The constructor creates monitors for 1) the first keyword (i.e. select/delete/...), 2) the sql for the PreparedStatement/Statement
217:                // 3) Any keyword matches passed in (such as table names)
218:
219:                SQLDeArgMon(String statementType, String sql, List matchStrings) {
220:
221:                    SQLDeArger sqld = new SQLDeArger(sql, matchStrings);
222:                    this .sql = sqld.getParsedSQL();
223:                    data = sqld.getAll(); // contains 3 cols: summary sql dearged, detail sql, ms. (units)
224:                    monRows = data.length;
225:
226:                    for (int i = 0; i < monRows; i++) {
227:                        StringBuffer label = new StringBuffer("MonProxy-SQL-");
228:                        // note this loop matches one in SQLDeArger.getAll and positions are important
229:                        // The constructor must be changed if this method changes - kind of ugly...
230:                        // The following labels will appear in the jamon report.
231:                        if (i == 0) //All
232:                            data[i][LABEL_IND] = label.append("Type: ").append(
233:                                    data[i][LABEL_IND]).toString();
234:                        else if (i == 1) // SQL Type - i.e. select, delete, update etc.
235:                            data[i][LABEL_IND] = label.append("Type: ").append(
236:                                    data[i][LABEL_IND]).toString();
237:                        else if (i == 2) // Parsed SQL (Statement, or PreparedStatement then - select * from table where key=?
238:                            data[i][LABEL_IND] = label.append(statementType)
239:                                    .append(": ").append(data[i][LABEL_IND])
240:                                    .toString();
241:                        else
242:                            // Match - Any string matches in the sql.
243:                            data[i][LABEL_IND] = label.append("Match: ")
244:                                    .append(data[i][LABEL_IND]).toString();
245:
246:                    }
247:
248:                }
249:
250:                private SQLDeArgMon start() {
251:                    synchronized (this ) { // keep data from being clobbered while being accessed by this method
252:                        if (monitors == null) {
253:                            // note if this is called in the constructor then monitors would be created even if sql summary is disabled
254:                            monitors = MonitorComposite.getMonitors(data);
255:                            data = null;
256:                        }
257:                    }
258:
259:                    monitors.start();
260:                    return this ;
261:                }
262:
263:                private SQLDeArgMon stop() {
264:                    monitors.stop();
265:                    return this ;
266:                }
267:
268:                private SQLDeArgMon add(double time) {
269:                    monitors.add(time);
270:                    return this ;
271:                }
272:
273:                private synchronized int incrementCounter() {
274:                    return accessCounter++;
275:                }
276:
277:                private String getSQL() {
278:                    return sql;
279:                }
280:
281:                public String toString() {
282:                    return "accessCounter=" + accessCounter + ", sql=" + sql;
283:                }
284:            }
285:
286:            public static void main(String[] args) {
287:                JDBCMonProxy.SQLDeArgMon sqlMon = new JDBCMonProxy.SQLDeArgMon(
288:                        "Statement", "select * from table where name='steve'",
289:                        null);
290:                System.out.println(sqlMon);
291:            }
292:
293:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.