KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > access > QueryLogger


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.access;
21
22 import java.lang.reflect.Array JavaDoc;
23 import java.sql.SQLException JavaDoc;
24 import java.util.List JavaDoc;
25
26 import org.apache.cayenne.access.jdbc.ParameterBinding;
27 import org.apache.cayenne.conn.DataSourceInfo;
28 import org.apache.cayenne.util.IDUtil;
29 import org.apache.cayenne.util.Util;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 /**
34  * QueryLogger is intended to log special events that happen whenever Cayenne interacts
35  * with a database. This includes execution of generated SQL statements, result counts,
36  * connection events, etc. Normally QueryLogger methods are not invoked directly by the
37  * . Rather it is a single logging point used by the framework.
38  * <p>
39  * Internally QueryLogger uses commons-logging at the "info" level.
40  * </p>
41  *
42  * @author Andrus Adamchik
43  */

44 public class QueryLogger {
45
46     private static final Log logObj = LogFactory.getLog(QueryLogger.class);
47
48     public static final int TRIM_VALUES_THRESHOLD = 30;
49
50     /**
51      * @since 1.2
52      */

53     static ThreadLocal JavaDoc logLevel = new ThreadLocal JavaDoc();
54
55     /**
56      * Appends SQL literal for the specified object to the buffer. This is a utility
57      * method and is not intended to build SQL queries, rather this is used in logging
58      * routines. In particular it will trim large values to avoid flooding the logs.
59      * </p>
60      *
61      * @param buffer buffer to append value
62      * @param object object to be transformed to SQL literal.
63      */

64     public static void sqlLiteralForObject(StringBuffer JavaDoc buffer, Object JavaDoc object) {
65         if (object == null) {
66             buffer.append("NULL");
67         }
68         else if (object instanceof String JavaDoc) {
69             buffer.append('\'');
70             // lets escape quotes
71
String JavaDoc literal = (String JavaDoc) object;
72             if (literal.length() > TRIM_VALUES_THRESHOLD) {
73                 literal = literal.substring(0, TRIM_VALUES_THRESHOLD) + "...";
74             }
75
76             int curPos = 0;
77             int endPos = 0;
78
79             while ((endPos = literal.indexOf('\'', curPos)) >= 0) {
80                 buffer.append(literal.substring(curPos, endPos + 1)).append('\'');
81                 curPos = endPos + 1;
82             }
83
84             if (curPos < literal.length())
85                 buffer.append(literal.substring(curPos));
86
87             buffer.append('\'');
88         }
89         // handle byte pretty formatting
90
else if (object instanceof Byte JavaDoc) {
91             IDUtil.appendFormattedByte(buffer, ((Byte JavaDoc) object).byteValue());
92         }
93         else if (object instanceof Number JavaDoc) {
94             // process numeric value (do something smart in the future)
95
buffer.append(object);
96         }
97         else if (object instanceof java.sql.Date JavaDoc) {
98             buffer.append('\'').append(object).append('\'');
99         }
100         else if (object instanceof java.sql.Time JavaDoc) {
101             buffer.append('\'').append(object).append('\'');
102         }
103         else if (object instanceof java.util.Date JavaDoc) {
104             long time = ((java.util.Date JavaDoc) object).getTime();
105             buffer.append('\'').append(new java.sql.Timestamp JavaDoc(time)).append('\'');
106         }
107         else if (object instanceof java.util.Calendar JavaDoc) {
108             long time = ((java.util.Calendar JavaDoc) object).getTimeInMillis();
109             buffer.append(object.getClass().getName()).append('(').append(
110                     new java.sql.Timestamp JavaDoc(time)).append(')');
111         }
112         else if (object instanceof Character JavaDoc) {
113             buffer.append(((Character JavaDoc) object).charValue());
114         }
115         else if (object instanceof Boolean JavaDoc) {
116             buffer.append('\'').append(object).append('\'');
117         }
118         else if (object instanceof ParameterBinding) {
119             sqlLiteralForObject(buffer, ((ParameterBinding) object).getValue());
120         }
121         else if (object.getClass().isArray()) {
122             buffer.append("< ");
123
124             int len = Array.getLength(object);
125             boolean trimming = false;
126             if (len > TRIM_VALUES_THRESHOLD) {
127                 len = TRIM_VALUES_THRESHOLD;
128                 trimming = true;
129             }
130             
131             for (int i = 0; i < len; i++) {
132                 if (i > 0) {
133                     buffer.append(",");
134                 }
135                 sqlLiteralForObject(buffer, Array.get(object, i));
136             }
137
138             if (trimming) {
139                 buffer.append("...");
140             }
141
142             buffer.append('>');
143         }
144         else {
145             buffer.append(object.getClass().getName()).append("@").append(
146                     System.identityHashCode(object));
147         }
148     }
149     
150     
151
152     /**
153      * @since 1.2 logs an arbitrary message using logging level setup for QueryLogger.
154      */

155     public static void log(String JavaDoc message) {
156         if (message != null) {
157             logObj.info(message);
158         }
159     }
160
161     /**
162      * Logs database connection event using container data source.
163      *
164      * @since 1.2
165      */

166     public static void logConnect(String JavaDoc dataSource) {
167         if (isLoggable()) {
168             logObj.info("Connecting. JNDI path: " + dataSource);
169         }
170     }
171
172     /**
173      * @since 1.2
174      */

175     public static void logConnect(String JavaDoc url, String JavaDoc userName, String JavaDoc password) {
176
177         if (isLoggable()) {
178             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Opening connection: ");
179
180             // append URL on the same line to make log somewhat grep-friendly
181
buf.append(url);
182             buf.append("\n\tLogin: ").append(userName);
183             buf.append("\n\tPassword: *******");
184
185             logObj.info(buf.toString());
186         }
187     }
188
189     /**
190      * Logs database connection event.
191      *
192      * @since 1.2
193      */

194     public static void logPoolCreated(DataSourceInfo dsi) {
195         if (isLoggable()) {
196             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("Created connection pool: ");
197
198             if (dsi != null) {
199                 // append URL on the same line to make log somewhat grep-friendly
200
buf.append(dsi.getDataSourceUrl());
201
202                 if (dsi.getAdapterClassName() != null) {
203                     buf.append("\n\tCayenne DbAdapter: ").append(
204                             dsi.getAdapterClassName());
205                 }
206
207                 buf.append("\n\tDriver class: ").append(dsi.getJdbcDriver());
208
209                 if (dsi.getMinConnections() >= 0) {
210                     buf.append("\n\tMin. connections in the pool: ").append(
211                             dsi.getMinConnections());
212                 }
213                 if (dsi.getMaxConnections() >= 0) {
214                     buf.append("\n\tMax. connections in the pool: ").append(
215                             dsi.getMaxConnections());
216                 }
217             }
218             else {
219                 buf.append(" pool information unavailable");
220             }
221
222             logObj.info(buf.toString());
223         }
224     }
225
226     /**
227      * @since 1.2
228      */

229     public static void logConnectSuccess() {
230         logObj.info("+++ Connecting: SUCCESS.");
231     }
232
233     /**
234      * @since 1.2
235      */

236     public static void logConnectFailure(Throwable JavaDoc th) {
237         logObj.info("*** Connecting: FAILURE.", th);
238     }
239
240     /**
241      * @since 1.2
242      */

243     public static void logQuery(String JavaDoc queryStr, List JavaDoc params) {
244         logQuery(queryStr, params, -1);
245     }
246
247     /**
248      * Log query content using Log4J Category with "INFO" priority.
249      *
250      * @param queryStr Query SQL string
251      * @param params optional list of query parameters that are used when executing query
252      * in prepared statement.
253      * @since 1.2
254      */

255     public static void logQuery(String JavaDoc queryStr, List JavaDoc params, long time) {
256         if (isLoggable()) {
257             StringBuffer JavaDoc buf = new StringBuffer JavaDoc(queryStr);
258             if (params != null && params.size() > 0) {
259                 buf.append(" [bind: ");
260                 sqlLiteralForObject(buf, params.get(0));
261
262                 int len = params.size();
263                 for (int i = 1; i < len; i++) {
264                     buf.append(", ");
265                     sqlLiteralForObject(buf, params.get(i));
266                 }
267
268                 buf.append(']');
269             }
270
271             // log preparation time only if it is something significant
272
if (time > 5) {
273                 buf.append(" - prepared in ").append(time).append(" ms.");
274             }
275
276             logObj.info(buf.toString());
277         }
278     }
279
280     /**
281      * @since 1.2
282      */

283     public static void logQueryParameters(String JavaDoc label, List JavaDoc parameters) {
284
285         if (isLoggable() && parameters.size() > 0) {
286             int len = parameters.size();
287             StringBuffer JavaDoc buf = new StringBuffer JavaDoc("[");
288             buf.append(label).append(": ");
289
290             sqlLiteralForObject(buf, parameters.get(0));
291
292             for (int i = 1; i < len; i++) {
293                 buf.append(", ");
294                 sqlLiteralForObject(buf, parameters.get(i));
295             }
296
297             buf.append(']');
298             logObj.info(buf.toString());
299         }
300     }
301
302     /**
303      * @since 1.2
304      */

305     public static void logSelectCount(int count) {
306         logSelectCount(count, -1);
307     }
308
309     /**
310      * @since 1.2
311      */

312     public static void logSelectCount(int count, long time) {
313         if (isLoggable()) {
314             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
315
316             if (count == 1) {
317                 buf.append("=== returned 1 row.");
318             }
319             else {
320                 buf.append("=== returned ").append(count).append(" rows.");
321             }
322
323             if (time >= 0) {
324                 buf.append(" - took ").append(time).append(" ms.");
325             }
326
327             logObj.info(buf.toString());
328         }
329     }
330
331     /**
332      * @since 1.2
333      */

334     public static void logUpdateCount(int count) {
335         if (isLoggable()) {
336
337             if (count < 0) {
338                 logObj.info("=== updated ? rows");
339             }
340             else {
341                 String JavaDoc countStr = (count == 1) ? "=== updated 1 row." : "=== updated "
342                         + count
343                         + " rows.";
344                 logObj.info(countStr);
345             }
346         }
347     }
348
349     /**
350      * @since 1.2
351      */

352     public static void logBeginTransaction(String JavaDoc transactionLabel) {
353         logObj.info("--- " + transactionLabel);
354     }
355
356     /**
357      * @since 1.2
358      */

359     public static void logCommitTransaction(String JavaDoc transactionLabel) {
360         logObj.info("+++ " + transactionLabel);
361     }
362
363     /**
364      * @since 1.2
365      */

366     public static void logRollbackTransaction(String JavaDoc transactionLabel) {
367         logObj.info("*** " + transactionLabel);
368     }
369
370     /**
371      * @since 1.2
372      */

373     public static void logQueryError(Throwable JavaDoc th) {
374         if (isLoggable()) {
375             if (th != null) {
376                 th = Util.unwindException(th);
377             }
378
379             logObj.info("*** error.", th);
380
381             if (th instanceof SQLException JavaDoc) {
382                 SQLException JavaDoc sqlException = ((SQLException JavaDoc) th).getNextException();
383                 while (sqlException != null) {
384                     logObj.info("*** nested SQL error.", sqlException);
385                     sqlException = sqlException.getNextException();
386                 }
387             }
388         }
389     }
390
391     /**
392      * @since 1.2
393      */

394     public static void logQueryStart(int count) {
395         if (isLoggable()) {
396             String JavaDoc countStr = (count == 1) ? "--- will run 1 query." : "--- will run "
397                     + count
398                     + " queries.";
399             logObj.info(countStr);
400         }
401     }
402
403     /**
404      * Returns true if current thread default log level is high enough for QueryLogger to
405      * generate output.
406      *
407      * @since 1.2
408      */

409     public static boolean isLoggable() {
410         return logObj.isInfoEnabled();
411     }
412 }
413
Popular Tags