Home » apache-log4j-1.2.15 » com.klopotek.utils » log » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   /*
   19    * Copyright (C) The Apache Software Foundation. All rights reserved.
   20   */
   21   
   22   package com.klopotek.utils.log;
   23   
   24   import java.sql;
   25   import java.util;
   26   import org.apache.log4j;
   27   import org.apache.log4j.helpers;
   28   import org.apache.log4j.spi;
   29   
   30   
   31   /**
   32   This class encapsulate the logic which is necessary to log into a table.
   33   Used by JDBCAppender
   34   
   35   <p><b>Author : </b><A HREF="mailto:t.fenner@klopotek.de">Thomas Fenner</A></p>
   36   
   37   @since 1.0
   38   */
   39   public class JDBCLogger
   40   {
   41   	//All columns of the log-table
   42   	private ArrayList logcols = null;
   43      //Only columns which will be provided by logging
   44      private String column_list = null;
   45      //Number of all columns
   46   	private int num = 0;
   47      //Status for successful execution of method configure()
   48   	private boolean isconfigured = false;
   49      //Status for ready to do logging with method append()
   50   	private boolean ready = false;
   51      //This message will be filled with a error-string when method ready() failes, and can be got by calling getMsg()
   52      private String errormsg = "";
   53   
   54   	private Connection con = null;
   55   	private Statement stmt = null;
   56   	private ResultSet rs = null;
   57      private String table = null;
   58   
   59      //Variables for static SQL-statement logging
   60      private String sql = null;
   61   	private String new_sql = null;
   62      private String new_sql_part1 = null;
   63      private String new_sql_part2 = null;
   64      private static final String msg_wildcard = "@MSG@";
   65   	private int msg_wildcard_pos = 0;
   66   
   67   	/**
   68   	Writes a message into the database table.
   69   	Throws an exception, if an database-error occurs !
   70   	*/
   71   	public void append(String _msg) throws Exception
   72   	{
   73   		if(!ready) if(!ready()) throw new Exception("JDBCLogger::append(), Not ready to append !");
   74   
   75         if(sql != null)
   76         {
   77         	appendSQL(_msg);
   78            return;
   79         }
   80   
   81   		LogColumn logcol;
   82   
   83   		rs.moveToInsertRow();
   84   
   85   		for(int i=0; i<num; i++)
   86   		{
   87           	logcol = (LogColumn)logcols.get(i);
   88   
   89   			if(logcol.logtype == LogType.MSG)
   90   			{
   91   				rs.updateObject(logcol.name, _msg);
   92   			}
   93   			else if(logcol.logtype == LogType.ID)
   94   			{
   95   				rs.updateObject(logcol.name, logcol.idhandler.getID());
   96   			}
   97   			else if(logcol.logtype == LogType.STATIC)
   98   			{
   99   				rs.updateObject(logcol.name, logcol.value);
  100   			}
  101   			else if(logcol.logtype == LogType.TIMESTAMP)
  102   			{
  103   				rs.updateObject(logcol.name, new Timestamp((new java.util.Date()).getTime()));
  104   			}
  105   		}
  106   
  107   		rs.insertRow();
  108   	}
  109   
  110   	/**
  111   	Writes a message into the database using a given sql-statement.
  112   	Throws an exception, if an database-error occurs !
  113   	*/
  114   	public void appendSQL(String _msg) throws Exception
  115   	{
  116   		if(!ready) if(!ready()) throw new Exception("JDBCLogger::appendSQL(), Not ready to append !");
  117   
  118         if(sql == null) throw new Exception("JDBCLogger::appendSQL(), No SQL-Statement configured !");
  119   
  120         if(msg_wildcard_pos > 0)
  121         {
  122   			new_sql = new_sql_part1 + _msg + new_sql_part2;
  123         }
  124   		else new_sql = sql;
  125   
  126         try
  127         {
  128   			stmt.executeUpdate(new_sql);
  129         }
  130         catch(Exception e)
  131         {
  132         	errormsg = new_sql;
  133            throw e;
  134   		}
  135   	}
  136   
  137   
  138   	/**
  139   	Configures this class, by reading in the structure of the log-table
  140   	Throws an exception, if an database-error occurs !
  141   	*/
  142   	public void configureTable(String _table) throws Exception
  143   	{
  144      	if(isconfigured) return;
  145   
  146   		//Fill logcols with META-informations of the table-columns
  147   		stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
  148   		rs = stmt.executeQuery("SELECT * FROM " + _table + " WHERE 1 = 2");
  149   
  150   		LogColumn logcol;
  151   
  152   		ResultSetMetaData rsmd = rs.getMetaData();
  153   
  154   		num = rsmd.getColumnCount();
  155   
  156   		logcols = new ArrayList(num);
  157   
  158   		for(int i=1; i<=num; i++)
  159   		{
  160   			logcol = new LogColumn();
  161   			logcol.name = rsmd.getColumnName(i).toUpperCase();
  162   			logcol.type = rsmd.getColumnTypeName(i);
  163   			logcol.nullable = (rsmd.isNullable(i) == rsmd.columnNullable);
  164            logcol.isWritable = rsmd.isWritable(i);
  165            if(!logcol.isWritable) logcol.ignore = true;
  166            logcols.add(logcol);
  167   		}
  168   
  169         table = _table;
  170   
  171   		isconfigured = true;
  172   	}
  173   
  174   	/**
  175   	Configures this class, by storing and parsing the given sql-statement.
  176   	Throws an exception, if somethings wrong !
  177   	*/
  178   	public void configureSQL(String _sql) throws Exception
  179   	{
  180      	if(isconfigured) return;
  181   
  182   		if(!isConnected()) throw new Exception("JDBCLogger::configureSQL(), Not connected to database !");
  183   
  184   		if(_sql == null || _sql.trim().equals("")) throw new Exception("JDBCLogger::configureSQL(), Invalid SQL-Statement !");
  185   
  186   		sql = _sql.trim();
  187   
  188         stmt = con.createStatement();
  189   
  190   		msg_wildcard_pos = sql.indexOf(msg_wildcard);
  191   
  192         if(msg_wildcard_pos > 0)
  193         {
  194   			new_sql_part1 = sql.substring(0, msg_wildcard_pos-1) + "'";
  195            //between the message...
  196            new_sql_part2 = "'" + sql.substring(msg_wildcard_pos+msg_wildcard.length());
  197   		}
  198   
  199   		isconfigured = true;
  200   	}
  201   
  202   	/**
  203      Sets a connection. Throws an exception, if the connection is not open !
  204   	*/
  205   	public void setConnection(Connection _con) throws Exception
  206   	{
  207   		con = _con;
  208   
  209   		if(!isConnected()) throw new Exception("JDBCLogger::setConnection(), Given connection isnt connected to database !");
  210   	}
  211   
  212   
  213   	/**
  214   	Sets a columns logtype (LogTypes) and value, which depends on that logtype.
  215   	Throws an exception, if the given arguments arent correct !
  216      */
  217   	public void setLogType(String _name, int _logtype, Object _value) throws Exception
  218   	{
  219   		if(!isconfigured) throw new Exception("JDBCLogger::setLogType(), Not configured !");
  220   
  221   		//setLogType() makes only sense for further configuration of configureTable()
  222         if(sql != null) return;
  223   
  224         _name = _name.toUpperCase();
  225   
  226   		if(_name == null || !(_name.trim().length() > 0)) throw new Exception("JDBCLogger::setLogType(), Missing argument name !");
  227   		if(!LogType.isLogType(_logtype)) throw new Exception("JDBCLogger::setLogType(), Invalid logtype '" + _logtype + "' !");
  228   		if((_logtype != LogType.MSG && _logtype != LogType.EMPTY) && _value == null) throw new Exception("JDBCLogger::setLogType(), Missing argument value !");
  229   
  230     		LogColumn logcol;
  231   
  232   		for(int i=0; i<num; i++)
  233   		{
  234           	logcol = (LogColumn)logcols.get(i);
  235   
  236   			if(logcol.name.equals(_name))
  237   			{
  238            	if(!logcol.isWritable) throw new Exception("JDBCLogger::setLogType(), Column " + _name + " is not writeable !");
  239   
  240   				//Column gets the message
  241   				if(_logtype == LogType.MSG)
  242               {
  243               	logcol.logtype = _logtype;
  244                  return;
  245   				}
  246   				//Column will be provided by JDBCIDHandler::getID()
  247   				else if(_logtype == LogType.ID)
  248   				{
  249   					logcol.logtype = _logtype;
  250   
  251                  try
  252                  {
  253                  	//Try to cast directly Object to JDBCIDHandler
  254   						logcol.idhandler = (JDBCIDHandler)_value;
  255                  }
  256                  catch(Exception e)
  257                  {
  258                  	try
  259                     {
  260                     	//Assuming _value is of class string which contains the classname of a JDBCIDHandler
  261   							logcol.idhandler = (JDBCIDHandler)(Class.forName((String)_value).newInstance());
  262                     }
  263                     catch(Exception e2)
  264                     {
  265   							throw new Exception("JDBCLogger::setLogType(), Cannot cast value of class " + _value.getClass() + " to class JDBCIDHandler !");
  266                     }
  267                  }
  268   
  269                  return;
  270   				}
  271   
  272   				//Column will be statically defined with Object _value
  273   				else if(_logtype == LogType.STATIC)
  274   				{
  275   					logcol.logtype = _logtype;
  276   					logcol.value = _value;
  277                  return;
  278   				}
  279   
  280   				//Column will be provided with a actually timestamp
  281   				else if(_logtype == LogType.TIMESTAMP)
  282   				{
  283   					logcol.logtype = _logtype;
  284                  return;
  285   				}
  286   
  287               //Column will be fully ignored during process.
  288               //If this column is not nullable, the column has to be filled by a database trigger,
  289               //else a database error occurs !
  290               //Columns which are not nullable, but should be not filled, must be explicit assigned with LogType.EMPTY,
  291               //else a value is required !
  292   				else if(_logtype == LogType.EMPTY)
  293   				{
  294   					logcol.logtype = _logtype;
  295   					logcol.ignore = true;
  296                  return;
  297   				}
  298   			}
  299   		}
  300   	}
  301   
  302   
  303   	/**
  304   	Return true, if this class is ready to append(), else false.
  305   	When not ready, a reason-String is stored in the instance-variable msg.
  306   	*/
  307   	public boolean ready()
  308   	{
  309      	if(ready) return true;
  310   
  311   		if(!isconfigured){ errormsg = "Not ready to append ! Call configure() first !"; return false;}
  312   
  313         //No need to doing the whole rest...
  314         if(sql != null)
  315         {
  316         	ready = true;
  317            return true;
  318         }
  319   
  320   		boolean msgcol_defined = false;
  321   
  322   		LogColumn logcol;
  323   
  324   		for(int i=0; i<num; i++)
  325   		{
  326         	logcol = (LogColumn)logcols.get(i);
  327   
  328            if(logcol.ignore || !logcol.isWritable) continue;
  329   			if(!logcol.nullable && logcol.logtype == LogType.EMPTY)
  330            {
  331            	errormsg = "Not ready to append ! Column " + logcol.name + " is not nullable, and must be specified by setLogType() !";
  332               return false;
  333            }
  334   			if(logcol.logtype == LogType.ID && logcol.idhandler == null)
  335            {
  336            	errormsg = "Not ready to append ! Column " + logcol.name + " is specified as an ID-column, and a JDBCIDHandler has to be set !";
  337               return false;
  338            }
  339   			else if(logcol.logtype == LogType.STATIC && logcol.value == null)
  340            {
  341            	errormsg = "Not ready to append ! Column " + logcol.name + " is specified as a static field, and a value has to be set !";
  342               return false;
  343            }
  344            else if(logcol.logtype == LogType.MSG) msgcol_defined = true;
  345   		}
  346   
  347         if(!msgcol_defined) return false;
  348   
  349         //create the column_list
  350   		for(int i=0; i<num; i++)
  351   		{
  352         	logcol = (LogColumn)logcols.get(i);
  353   
  354   			if(logcol.ignore || !logcol.isWritable) continue;
  355   
  356            if(logcol.logtype != LogType.EMPTY)
  357            {
  358   				if(column_list == null)
  359               {
  360               	column_list = logcol.name;
  361               }
  362               else column_list += ", " + logcol.name;
  363            }
  364   		}
  365   
  366         try
  367         {
  368   			rs = stmt.executeQuery("SELECT " + column_list + " FROM " + table + " WHERE 1 = 2");
  369   		}
  370         catch(Exception e)
  371         {
  372   			errormsg = "Not ready to append ! Cannot select columns '" + column_list + "' of table " + table + " !";
  373         	return false;
  374         }
  375   
  376   		ready = true;
  377   
  378   		return true;
  379   	}
  380   
  381   	/**
  382   	Return true, if this class is configured, else false.
  383   	*/
  384   	public boolean isConfigured(){ return isconfigured;}
  385   
  386   	/**
  387   	Return true, if this connection is open, else false.
  388   	*/
  389   	public boolean isConnected()
  390      {
  391      	try
  392         {
  393      		return (con != null && !con.isClosed());
  394         }
  395         catch(Exception e){return false;}
  396      }
  397   
  398   	/**
  399   	Return the internal error message stored in instance variable msg.
  400   	*/
  401      public String getErrorMsg(){String r = new String(errormsg); errormsg = null; return r;}
  402   }
  403   
  404   
  405   /**
  406   This class encapsulate all by class JDBCLogger needed data around a column
  407   */
  408   class LogColumn
  409   {
  410   	//column name
  411   	String name = null;
  412      //column type
  413   	String type = null;
  414      //not nullability means that this column is mandatory
  415   	boolean nullable = false;
  416      //isWritable means that the column can be updated, else column is only readable
  417      boolean isWritable = false;
  418      //if ignore is true, this column will be ignored by building sql-statements.
  419      boolean ignore = false;
  420   
  421   	//Must be filled for not nullable columns ! In other case it is optional.
  422   	int logtype = LogType.EMPTY;
  423   	Object value = null;				//Generic storage for typewrapper-classes Long, String, etc...
  424   	JDBCIDHandler idhandler = null;
  425   }
  426   
  427   
  428   /**
  429   This class contains all constants which are necessary to define a columns log-type.
  430   */
  431   class LogType
  432   {
  433   	//A column of this type will receive the message.
  434   	public static final int MSG = 1;
  435   
  436   	//A column of this type will be a unique identifier of the logged row.
  437   	public static final int ID = 2;
  438   
  439   	//A column of this type will contain a static, one-time-defined value.
  440   	public static final int STATIC = 3;
  441   
  442     	//A column of this type will be filled with an actual timestamp depending by the time the logging will be done.
  443   	public static final int TIMESTAMP = 4;
  444   
  445   	//A column of this type will contain no value and will not be included in logging insert-statement.
  446      //This could be a column which will be filled not by creation but otherwhere...
  447   	public static final int EMPTY = 5;
  448   
  449   
  450   	public static boolean isLogType(int _lt)
  451   	{
  452   		if(_lt == MSG || _lt == STATIC || _lt == ID || _lt == TIMESTAMP || _lt == EMPTY) return true;
  453   
  454   		return false;
  455   	}
  456   
  457      public static int parseLogType(String _lt)
  458      {
  459   		if(_lt.equals("MSG")) return MSG;
  460   		if(_lt.equals("ID")) return ID;
  461   		if(_lt.equals("STATIC")) return STATIC;
  462   		if(_lt.equals("TIMESTAMP")) return TIMESTAMP;
  463   		if(_lt.equals("EMPTY")) return EMPTY;
  464   
  465         return -1;
  466      }
  467   }
  468   
  469   
  470   
  471   
  472   

Save This Page
Home » apache-log4j-1.2.15 » com.klopotek.utils » log » [javadoc | source]