KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > klopotek > utils > log > JDBCLogger


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

16
17 /*
18  * Copyright (C) The Apache Software Foundation. All rights reserved.
19 */

20
21 package com.klopotek.utils.log;
22
23 import java.sql.*;
24 import java.util.*;
25 import org.apache.log4j.*;
26 import org.apache.log4j.helpers.*;
27 import org.apache.log4j.spi.*;
28
29
30 /**
31 This class encapsulate the logic which is necessary to log into a table.
32 Used by JDBCAppender
33
34 <p><b>Author : </b><A HREF="mailto:t.fenner@klopotek.de">Thomas Fenner</A></p>
35
36 @since 1.0
37 */

38 public class JDBCLogger
39 {
40     //All columns of the log-table
41
private ArrayList logcols = null;
42    //Only columns which will be provided by logging
43
private String JavaDoc column_list = null;
44    //Number of all columns
45
private int num = 0;
46    //Status for successful execution of method configure()
47
private boolean isconfigured = false;
48    //Status for ready to do logging with method append()
49
private boolean ready = false;
50    //This message will be filled with a error-string when method ready() failes, and can be got by calling getMsg()
51
private String JavaDoc errormsg = "";
52
53     private Connection con = null;
54     private Statement stmt = null;
55     private ResultSet rs = null;
56    private String JavaDoc table = null;
57
58    //Variables for static SQL-statement logging
59
private String JavaDoc sql = null;
60     private String JavaDoc new_sql = null;
61    private String JavaDoc new_sql_part1 = null;
62    private String JavaDoc new_sql_part2 = null;
63    private static final String JavaDoc msg_wildcard = "@MSG@";
64     private int msg_wildcard_pos = 0;
65
66     /**
67     Writes a message into the database table.
68     Throws an exception, if an database-error occurs !
69     */

70     public void append(String JavaDoc _msg) throws Exception JavaDoc
71     {
72         if(!ready) if(!ready()) throw new Exception JavaDoc("JDBCLogger::append(), Not ready to append !");
73
74       if(sql != null)
75       {
76         appendSQL(_msg);
77          return;
78       }
79
80         LogColumn logcol;
81
82         rs.moveToInsertRow();
83
84         for(int i=0; i<num; i++)
85         {
86             logcol = (LogColumn)logcols.get(i);
87
88             if(logcol.logtype == LogType.MSG)
89             {
90                 rs.updateObject(logcol.name, _msg);
91             }
92             else if(logcol.logtype == LogType.ID)
93             {
94                 rs.updateObject(logcol.name, logcol.idhandler.getID());
95             }
96             else if(logcol.logtype == LogType.STATIC)
97             {
98                 rs.updateObject(logcol.name, logcol.value);
99             }
100             else if(logcol.logtype == LogType.TIMESTAMP)
101             {
102                 rs.updateObject(logcol.name, new Timestamp((new java.util.Date JavaDoc()).getTime()));
103             }
104         }
105
106         rs.insertRow();
107     }
108
109     /**
110     Writes a message into the database using a given sql-statement.
111     Throws an exception, if an database-error occurs !
112     */

113     public void appendSQL(String JavaDoc _msg) throws Exception JavaDoc
114     {
115         if(!ready) if(!ready()) throw new Exception JavaDoc("JDBCLogger::appendSQL(), Not ready to append !");
116
117       if(sql == null) throw new Exception JavaDoc("JDBCLogger::appendSQL(), No SQL-Statement configured !");
118
119       if(msg_wildcard_pos > 0)
120       {
121             new_sql = new_sql_part1 + _msg + new_sql_part2;
122       }
123         else new_sql = sql;
124
125       try
126       {
127             stmt.executeUpdate(new_sql);
128       }
129       catch(Exception JavaDoc e)
130       {
131         errormsg = new_sql;
132          throw e;
133         }
134     }
135
136
137     /**
138     Configures this class, by reading in the structure of the log-table
139     Throws an exception, if an database-error occurs !
140     */

141     public void configureTable(String JavaDoc _table) throws Exception JavaDoc
142     {
143     if(isconfigured) return;
144
145         //Fill logcols with META-informations of the table-columns
146
stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
147         rs = stmt.executeQuery("SELECT * FROM " + _table + " WHERE 1 = 2");
148
149         LogColumn logcol;
150
151         ResultSetMetaData rsmd = rs.getMetaData();
152
153         num = rsmd.getColumnCount();
154
155         logcols = new ArrayList(num);
156
157         for(int i=1; i<=num; i++)
158         {
159             logcol = new LogColumn();
160             logcol.name = rsmd.getColumnName(i).toUpperCase();
161             logcol.type = rsmd.getColumnTypeName(i);
162             logcol.nullable = (rsmd.isNullable(i) == rsmd.columnNullable);
163          logcol.isWritable = rsmd.isWritable(i);
164          if(!logcol.isWritable) logcol.ignore = true;
165          logcols.add(logcol);
166         }
167
168       table = _table;
169
170         isconfigured = true;
171     }
172
173     /**
174     Configures this class, by storing and parsing the given sql-statement.
175     Throws an exception, if somethings wrong !
176     */

177     public void configureSQL(String JavaDoc _sql) throws Exception JavaDoc
178     {
179     if(isconfigured) return;
180
181         if(!isConnected()) throw new Exception JavaDoc("JDBCLogger::configureSQL(), Not connected to database !");
182
183         if(_sql == null || _sql.trim().equals("")) throw new Exception JavaDoc("JDBCLogger::configureSQL(), Invalid SQL-Statement !");
184
185         sql = _sql.trim();
186
187       stmt = con.createStatement();
188
189         msg_wildcard_pos = sql.indexOf(msg_wildcard);
190
191       if(msg_wildcard_pos > 0)
192       {
193             new_sql_part1 = sql.substring(0, msg_wildcard_pos-1) + "'";
194          //between the message...
195
new_sql_part2 = "'" + sql.substring(msg_wildcard_pos+msg_wildcard.length());
196         }
197
198         isconfigured = true;
199     }
200
201     /**
202    Sets a connection. Throws an exception, if the connection is not open !
203     */

204     public void setConnection(Connection _con) throws Exception JavaDoc
205     {
206         con = _con;
207
208         if(!isConnected()) throw new Exception JavaDoc("JDBCLogger::setConnection(), Given connection isnt connected to database !");
209     }
210
211
212     /**
213     Sets a columns logtype (LogTypes) and value, which depends on that logtype.
214     Throws an exception, if the given arguments arent correct !
215    */

216     public void setLogType(String JavaDoc _name, int _logtype, Object JavaDoc _value) throws Exception JavaDoc
217     {
218         if(!isconfigured) throw new Exception JavaDoc("JDBCLogger::setLogType(), Not configured !");
219
220         //setLogType() makes only sense for further configuration of configureTable()
221
if(sql != null) return;
222
223       _name = _name.toUpperCase();
224
225         if(_name == null || !(_name.trim().length() > 0)) throw new Exception JavaDoc("JDBCLogger::setLogType(), Missing argument name !");
226         if(!LogType.isLogType(_logtype)) throw new Exception JavaDoc("JDBCLogger::setLogType(), Invalid logtype '" + _logtype + "' !");
227         if((_logtype != LogType.MSG && _logtype != LogType.EMPTY) && _value == null) throw new Exception JavaDoc("JDBCLogger::setLogType(), Missing argument value !");
228
229         LogColumn logcol;
230
231         for(int i=0; i<num; i++)
232         {
233             logcol = (LogColumn)logcols.get(i);
234
235             if(logcol.name.equals(_name))
236             {
237             if(!logcol.isWritable) throw new Exception JavaDoc("JDBCLogger::setLogType(), Column " + _name + " is not writeable !");
238
239                 //Column gets the message
240
if(_logtype == LogType.MSG)
241             {
242                 logcol.logtype = _logtype;
243                return;
244                 }
245                 //Column will be provided by JDBCIDHandler::getID()
246
else if(_logtype == LogType.ID)
247                 {
248                     logcol.logtype = _logtype;
249
250                try
251                {
252                 //Try to cast directly Object to JDBCIDHandler
253
logcol.idhandler = (JDBCIDHandler)_value;
254                }
255                catch(Exception JavaDoc e)
256                {
257                 try
258                   {
259                     //Assuming _value is of class string which contains the classname of a JDBCIDHandler
260
logcol.idhandler = (JDBCIDHandler)(Class.forName((String JavaDoc)_value).newInstance());
261                   }
262                   catch(Exception JavaDoc e2)
263                   {
264                             throw new Exception JavaDoc("JDBCLogger::setLogType(), Cannot cast value of class " + _value.getClass() + " to class JDBCIDHandler !");
265                   }
266                }
267
268                return;
269                 }
270
271                 //Column will be statically defined with Object _value
272
else if(_logtype == LogType.STATIC)
273                 {
274                     logcol.logtype = _logtype;
275                     logcol.value = _value;
276                return;
277                 }
278
279                 //Column will be provided with a actually timestamp
280
else if(_logtype == LogType.TIMESTAMP)
281                 {
282                     logcol.logtype = _logtype;
283                return;
284                 }
285
286             //Column will be fully ignored during process.
287
//If this column is not nullable, the column has to be filled by a database trigger,
288
//else a database error occurs !
289
//Columns which are not nullable, but should be not filled, must be explicit assigned with LogType.EMPTY,
290
//else a value is required !
291
else if(_logtype == LogType.EMPTY)
292                 {
293                     logcol.logtype = _logtype;
294                     logcol.ignore = true;
295                return;
296                 }
297             }
298         }
299     }
300
301
302     /**
303     Return true, if this class is ready to append(), else false.
304     When not ready, a reason-String is stored in the instance-variable msg.
305     */

306     public boolean ready()
307     {
308     if(ready) return true;
309
310         if(!isconfigured){ errormsg = "Not ready to append ! Call configure() first !"; return false;}
311
312       //No need to doing the whole rest...
313
if(sql != null)
314       {
315         ready = true;
316          return true;
317       }
318
319         boolean msgcol_defined = false;
320
321         LogColumn logcol;
322
323         for(int i=0; i<num; i++)
324         {
325         logcol = (LogColumn)logcols.get(i);
326
327          if(logcol.ignore || !logcol.isWritable) continue;
328             if(!logcol.nullable && logcol.logtype == LogType.EMPTY)
329          {
330             errormsg = "Not ready to append ! Column " + logcol.name + " is not nullable, and must be specified by setLogType() !";
331             return false;
332          }
333             if(logcol.logtype == LogType.ID && logcol.idhandler == null)
334          {
335             errormsg = "Not ready to append ! Column " + logcol.name + " is specified as an ID-column, and a JDBCIDHandler has to be set !";
336             return false;
337          }
338             else if(logcol.logtype == LogType.STATIC && logcol.value == null)
339          {
340             errormsg = "Not ready to append ! Column " + logcol.name + " is specified as a static field, and a value has to be set !";
341             return false;
342          }
343          else if(logcol.logtype == LogType.MSG) msgcol_defined = true;
344         }
345
346       if(!msgcol_defined) return false;
347
348       //create the column_list
349
for(int i=0; i<num; i++)
350         {
351         logcol = (LogColumn)logcols.get(i);
352
353             if(logcol.ignore || !logcol.isWritable) continue;
354
355          if(logcol.logtype != LogType.EMPTY)
356          {
357                 if(column_list == null)
358             {
359                 column_list = logcol.name;
360             }
361             else column_list += ", " + logcol.name;
362          }
363         }
364
365       try
366       {
367             rs = stmt.executeQuery("SELECT " + column_list + " FROM " + table + " WHERE 1 = 2");
368         }
369       catch(Exception JavaDoc e)
370       {
371             errormsg = "Not ready to append ! Cannot select columns '" + column_list + "' of table " + table + " !";
372         return false;
373       }
374
375         ready = true;
376
377         return true;
378     }
379
380     /**
381     Return true, if this class is configured, else false.
382     */

383     public boolean isConfigured(){ return isconfigured;}
384
385     /**
386     Return true, if this connection is open, else false.
387     */

388     public boolean isConnected()
389    {
390     try
391       {
392         return (con != null && !con.isClosed());
393       }
394       catch(Exception JavaDoc e){return false;}
395    }
396
397     /**
398     Return the internal error message stored in instance variable msg.
399     */

400    public String JavaDoc getErrorMsg(){String JavaDoc r = new String JavaDoc(errormsg); errormsg = null; return r;}
401 }
402
403
404 /**
405 This class encapsulate all by class JDBCLogger needed data around a column
406 */

407 class LogColumn
408 {
409     //column name
410
String JavaDoc name = null;
411    //column type
412
String JavaDoc type = null;
413    //not nullability means that this column is mandatory
414
boolean nullable = false;
415    //isWritable means that the column can be updated, else column is only readable
416
boolean isWritable = false;
417    //if ignore is true, this column will be ignored by building sql-statements.
418
boolean ignore = false;
419
420     //Must be filled for not nullable columns ! In other case it is optional.
421
int logtype = LogType.EMPTY;
422     Object JavaDoc value = null; //Generic storage for typewrapper-classes Long, String, etc...
423
JDBCIDHandler idhandler = null;
424 }
425
426
427 /**
428 This class contains all constants which are necessary to define a columns log-type.
429 */

430 class LogType
431 {
432     //A column of this type will receive the message.
433
public static final int MSG = 1;
434
435     //A column of this type will be a unique identifier of the logged row.
436
public static final int ID = 2;
437
438     //A column of this type will contain a static, one-time-defined value.
439
public static final int STATIC = 3;
440
441     //A column of this type will be filled with an actual timestamp depending by the time the logging will be done.
442
public static final int TIMESTAMP = 4;
443
444     //A column of this type will contain no value and will not be included in logging insert-statement.
445
//This could be a column which will be filled not by creation but otherwhere...
446
public static final int EMPTY = 5;
447
448
449     public static boolean isLogType(int _lt)
450     {
451         if(_lt == MSG || _lt == STATIC || _lt == ID || _lt == TIMESTAMP || _lt == EMPTY) return true;
452
453         return false;
454     }
455
456    public static int parseLogType(String JavaDoc _lt)
457    {
458         if(_lt.equals("MSG")) return MSG;
459         if(_lt.equals("ID")) return ID;
460         if(_lt.equals("STATIC")) return STATIC;
461         if(_lt.equals("TIMESTAMP")) return TIMESTAMP;
462         if(_lt.equals("EMPTY")) return EMPTY;
463
464       return -1;
465    }
466 }
467
468
469
470
471
472
Popular Tags