/*
* Copyright 1999,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
/**
* JDBCAppender implementation to log into a database.
*/
package org.apache.log4j.jdbcplus;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.StringTokenizer;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Layout;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;
/**
* <p>
* The JDBCAppender writes messages into a database via JDBC. Multiple
* configuration options and parameters are supported.
* </p>
*
* <p>
* <b>Configuration by file/code </b>
* </p>
*
* <p>
* The JDBCAppender is configurable at runtime by setting options in two
* alternatives :
* </p>
*
* <ol>
* <li>Use a configuration-file
* <ul>
* <li>Here is a configuration-file example ( <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/log4j_test.xml">log4j_test.xml
* </a>, which can be used as argument for the DOMConfigurator. Here is a
* code-example ( <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/DomConfiguratorTest.java"
* >DomConfiguratorTest.java </a>) to configure the JDBCAppender with a
* configuration-file.</li>
*
* <li>Here is a configuration-file example ( <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/log4j_test_prepstmt.xml">log4j_test_prepstmt.xml
* </a>), which can be used as argument for the DOMConfigurator. It uses
* prepared statement configuration.</li>
*
* <li>Here is a configuration-file example ( <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/log4j_test_storedproc.xml">log4j_test_storedproc.xml
* </a>), which can be used as argument for the DOMConfigurator. It uses
* stored procedure configuration (J2SDK 1.4+).</li>
*
* <li>Here is a configuration-file example ( <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/log4j.properties">log4j.properties
* </a>), which can be used as argument for the PropertyConfigurator. Some
* options (e.g. usage of prepared statements) are not available in a property
* configuration file.</li>
* </ul>
* </li>
* <li>Call the methods of JDBCAppender directly to do it
*
* <p>
* Here is a another code-example ( <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/SourceConfigOracleTest.java">SourceConfigOracleTest.java
* </a>) to configure the JDBCAppender without a configuration-file.
* </p>
* </li>
* </ol>
*
* <p>
* <b>Configuration parameters </b>
* </p>
*
* <p>
* Generally there are just a few basic things to get the JDBCAppender running :
* </p>
*
* <ol>
* <li>
* <p>
* We need a database connection anyway ! There are 3 ways to to this :
* </p>
*
* <p>
* a) Specify the URL, password and username (use the url-param, username-param
* and password-param or the setUrl(), setUsername() and setPassword()-methods)
* This will create a static connection by JDBCAppender.
* </p>
*
* <p>
* b) Specify a JDBCConnectionHandler (use the connector-param or the
* setConnector()-method) This handler will be called to return a connection.
* When its a JDBCPoolConnectionHandler, the connection is checked in and out
* everytime needing it.
* </p>
*
* <p>
* c) Specify URL, password and username AND a JDBCConnectionHandler, then the
* handler returns the desired connection.
* </p>
* </li>
* <li>
* <p>
* We need to know the statement which should be inserted into the database !
* There are also 5 ways to to this :
* </p>
*
* <p>
* a) Specify a JDBCSqlHandler (use the sqlhandler-param or the
* setSqlhandler()-method) This handler will be invoked with every message which
* has to be logged and must return a SQL-statement. It may return null or empty
* string if nothing should be logged.
* </p>
*
* <p>
* b) Specify a static sql-statement (use the sql-param or the setSql()-method)
* This statement which will be performed with every occuring message-event. Use
* wildcards @INC@, @PRIO@, @IPRIO@, @CAT@, @THREAD@, @MSG@, @LAYOUT@, @LAYOUT:x@, @TIMESTAMP@, @THROWABLE@, @NDC@, @MDC:key@ for dynamic replacement. See further description below.
* </p>
*
* <p>
* c) Specify the table and describe the important columns. (use the table-param
* and column-param or the setTable() and setColumn()-methods) Not nullable
* columns are mandatory to describe ! The sql-statement will be created
* automatically. We need to know exactly the column-name, the logical
* columns-logtype and in dependency of that the value. The constants of
* JDBCLogType are described below. This is the most dynamic variant to build
* the sql-statement, because you can apply JDBCIDHandler and JDBCColumnHandler.
* <b>Note: This configuration uses the "updatable ResultSets". This feature is
* not implemented for some databases/drivers. As of 2004, it causes errors on
* MySQL JDBC Connector ("Result Set not updateable"), Firebird JCA-JDBC Driver
* ("not yet implemented"), Postgres. Use other configuration options instead if
* any problems occur. </b>
* </p>
*
* <p>
* d) Same as 2c) but using PreparedStatements. Example: <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/log4j_test_prepstmt.xml">log4j_test_prepstmt.xml
* </a> <b></b>
* </p>
*
* <p>
* e) Same as 2c) but using Stored Procedure (CallableStatement). Specify procedure name parameter instead of table name.
* Requires J2SDK 1.4+.
* Example: <a
* href="../../../../../src/org/apache/log4j/jdbcplus/examples/test/log4j_test_storedproc.xml">log4j_test_storedproc.xml
* </a> <b></b>
* </p>
* </li>
* </ol>
* <p>
* The class JDBCLogType provides you several possibilities to describe a
* columns logtype/wildcard :
* </p>
* <p>
* <ul>
* <li>MSG - The column will get the non-layouted log-message. No explicit
* value necessary.</li>
* <li>LAYOUT, LAYOUT:1, :2, :x - The column will get the layouted log-event.
* If more than one layout is used, configuration of PatternLayout conversion
* pattern separated by .layoutPartsDelimiter is required.
* layoutPartsDelimiter may be longer than one character to avoid mismatches (J2SDK 1.4+)
* </li>
* <li>ID - The value must be a JDBCIDHandler, which returns the columns value.
* </li>
* <li>INC - The column gets a number, which begins with 1 and will be
* incremented with every log-message.</li>
* <li>ORACLE_SEQUENCE - The column gets the result of an Oracle sequence call.
* Value is sequence name</li>
* <li>DYNAMIC - The value must be a JDBCColumnHandler, which returns the
* columns value.</li>
* <li>STATIC - The column always gets this value.</li>
* <li>THROWABLE - The column gets the throwable/exception information if
* available.</li>
* <li>TIMESTAMP - The column gets an actual timestamp.</li>
* <li>PRIO - The column gets the priority/level of the log-message.</li>
* <li>IPRIO - The column gets the integer value of the priority/level of the
* log-message.</li>
* <li>CAT - The column gets the categorys name.</li>
* <li>THREAD - The column gets the threads name.</li>
* <li>NDC - The column gets the NDC (nested diagnostic context).</li>
* <li>MDC:key - The column gets the MDC (mapped diagnostic context) for the
* given key.</li>
* <li>EMPTY - The column will be ignored.</li>
* </ul>
* </p>
*
* @author
* <a href="mailto:t.fenner@klopotek.de">Thomas Fenner</a>,
* <a href="http://www.mannhaupt.com/danko/contact/">Danko Mannhaupt</a>,
* many contributions by the community
* @since 1.0
* @version see jdbcappender.jar/META-INF/MANIFEST.MF for version information
*/
public class JDBCAppender extends AppenderSkeleton {
//Variables to store the options values setted by setXXX()-methods :
/**
* Stores a database url of the form jdbc:subprotocol:subname
*/
private String url = null;
/**
* Stores the database user
*/
private String username = null;
/**
* Stores the database password
*/
private String password = null;
/**
* Stores the table in which the logging will be done
*/
private String table = null;
/**
* Stores the procedure which will be called
*/
private String procedure = null;
/**
* Stores a classname which is implementing the
* JDBCConnectionHandler-interface.
*/
private String connector = null;
/**
* Stores a sql-statement which will be used to insert into the database
*/
private String sql = null;
/**
* Defines the class load string necessary to access the database driver
*/
private String dbclass = null;
/**
* Defines the maximum number of characters in a throwable stack trace. -1 if there is no limit.
*/
private int throwableMaxChars = -1;
/**
* Define whether to replace single quotes (') by 2 single quotes ('') in
* sql parameters. Will be applied to these wildcards:
*
* @MSG@,
* @LAYOUT:x@,
* @PRIO@,
* @CAT@,
* @THREAD@,
* @NDC@,
* @MDC:x@,
* @THROWABLE@
*/
private boolean quoteReplace = true;
/**
* character to separate parts of layout if more than one part is to be used
*/
private String layoutPartsDelimiter = "#";
/**
* Defines whether updated messages should be committed to the database
*/
private boolean commit = true;
/**
* Defines how many messages will be buffered until they will be updated to
* the database
*/
private int buffer_size = 1;
/**
* Defines whether to use Prepared Statements instead of updateable result
* sets (default false)
*/
private boolean usePreparedStatements = false;
/**
* Stores a JDBCConnectionHandler, which is instantiated from connector
*/
private JDBCConnectionHandler connectionHandler = null;
/**
* Stores a JDBCSqlHandler, which allows you to build dynamic
* insert-statements
*/
private JDBCSqlHandler sqlHandler = null;
/**
* Stores message-events. When the buffer_size is reached, the buffer will
* be flushed and the messages will inserted to the database.
*/
private ArrayList buffer = new ArrayList();
/**
* Stores the columns, which will be used in the statement
*/
private ArrayList columns = new ArrayList();
/**
* Stores the database-connection, if any static is given
*/
private Connection con = null;
/**
* This class encapsulate the logic which is necessary to log into a table
*/
private JDBCLogger jlogger = new JDBCLogger();
/**
* A flag to indicate a established database connection
*/
private boolean connected = false;
/**
* A flag to indicate configuration status
*/
private boolean configured = false;
/**
* A flag to indicate that everything is ready to execute append()-commands
*/
private boolean ready = false;
/**
* Constructor for the JDBCAppender object
*/
public JDBCAppender() {
super();
}
/**
* Constructor for the JDBCAppender object
*
* @param layout
* Allows you to set your Layout-instance
*/
public JDBCAppender(Layout layout) {
super();
this.setLayout(layout);
}
/**
* Sets the Layout attribute of the JDBCAppender object
*
* @param layout
* The new Layout value
*/
public void setLayout(Layout layout) {
super.setLayout(layout);
}
/**
* Specify your own JDBCConnectionHandler / JDBCPoolConnectionHandler for
* connecting to the database. If the Database-Options are given, the
* handler is called with the desired database-params. If you give a
* JDBCPoolConnectionHandler, the connection will be checked out only when
* needed and checked in after .
*
* @param value
* The new Connector value
*/
public void setConnector(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
connector = value;
}
/**
* Specify your own JDBCConnectionHandler / JDBCPoolConnectionHandler for
* connecting to the database. If the Database-Options are given, the
* handler is called with the desired database-params. If you give a
* JDBCPoolConnectionHandler, the connection will be checked out only when
* needed and checked in after .
*
* @param value
* The new Connector value
*/
public void setConnectionHandler(JDBCConnectionHandler connectionHandler) {
if (connectionHandler == null) return;
this.connectionHandler = connectionHandler;
}
/**
* Specify your own JDBCSqlHandler to let him create dynamic sql-statements.
*
* @param value
* The new Sqlhandler value
*/
public void setSqlhandler(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
try {
sqlHandler = (JDBCSqlHandler) (Class.forName(value).newInstance());
} catch (Exception e) {
String errorMsg = "JDBCAppender::setSqlhandler(), sqlhandler must be derived of JDBCSqlHandler !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
}
/**
* Specify your own JDBCSqlHandler to let him create dynamic sql-statements.
*
* @param value
* The new Sqlhandler value
*/
public void setSqlHandler(JDBCSqlHandler sqlHandler) throws Exception {
if (sqlHandler == null) return;
this.sqlHandler = sqlHandler;
}
/**
* Sets database url of the form jdbc:subprotocol:subname
*
* @param value
* The new Url value
*/
public void setUrl(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
url = value;
}
/**
* Sets the database user
*
* @param value
* The new Username value
*/
public void setUsername(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
username = value;
}
/**
* Sets the database password
*
* @param value
* The new Password value
*/
public void setPassword(String value) {
if (value == null) { return; }
value = value.trim();
password = value;
}
/**
* Specify a database class loader string. E.g.
* oracle.jdbc.driver.OracleDriver
*
* @param value
* The new database driver class
*/
public void setDbclass(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
dbclass = value;
}
/**
* Specify an sql-statement. Use wildcards @INC@, @PRIO@, @CAT@, @THREAD@, @MSG@,
* ... for dynamic replacement. See class JDBCLogType for further
* description.
* @param value
* The new Sql value
*/
public void setSql(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
sql = value;
}
/**
* Specify the table, when you also describe all columns by setColumn()
*
* @param value
* The new Table value
*/
public void setTable(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
if (sql != null) { return; }
table = value;
}
/**
* Sets the Column attribute of the JDBCAppender object.
* Last two parameters only required for Stored Procedure configuration on Oracle.
*
* @param column
* The columns name
* @param logtype
* Constant of class JDBCLogType
* @param value
* The columns value depending by the logtype
* @param type
* Column type name
* @param sqlType
* Column SQL type
*/
public void setColumn(String column, int logtype, Object value, String type, int sqlType) {
if (table == null && procedure == null) {
String errorMsg = "JDBCAppender::setColumn(), table or procedure has to be set before !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
if (sql != null || sqlHandler != null) { return; }
if (column == null || value == null) {
String errorMsg = "JDBCAppender::setColumn(), Invalid arguments : column = " + column
+ ", logtype = " + logtype + ", value = " + value + " !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
column = column.trim();
if (column.length() == 0) {
String errorMsg = "JDBCAppender::setColumn(), Argument column is missing !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
columns.add(new JDBCColumnStorage(column, logtype, value, type, sqlType));
}
/**
* Defines one colum in the format column~logtype~value~typeName~sqlType, e.g.
* id~ID~org.apache.log4j.jdbcplus.examples.MyIDHandler or
* id~ID~org.apache.log4j.jdbcplus.examples.MyIDHandler~INTEGER~4.
*
* typeName and sqlType are required, if JDBC driver does not support
* Statement.getParamaterMetaData, e.g. Oracle.
*
* @param value
* Concatenated string column~logtype~value~typeName
*/
public void setColumn(String value) {
if (table == null && procedure == null) {
String errorMsg = "JDBCAppender::setColumn(), table or procedure has to be set before !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
if (sql != null || sqlHandler != null) { return; }
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
String name = null;
int logtype = -1;
String typeName = null;
int sqlType = -1;
String arg = null;
int num_args = 0;
StringTokenizer st_arg;
//Arguments are ~-separated
st_arg = new StringTokenizer(value, "~");
num_args = st_arg.countTokens();
if (num_args < 2 || num_args > 5) {
String errorMsg = "JDBCAppender::setColumn(), Invalid column-option value : " + value
+ " !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
for (int j = 1; j <= num_args; j++) {
arg = st_arg.nextToken();
if (j == 1) {
name = arg;
} else if (j == 2) {
try {
logtype = Integer.parseInt(arg);
} catch (Exception e) {
logtype = JDBCLogType.parseLogType(arg);
}
if (!JDBCLogType.isLogType(logtype)) {
String errorMsg = "JDBCAppender::setColumn(), Invalid column-option JDBCLogType : "
+ arg + " !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
} else if (j == 3) {
value = arg;
} else if (j == 4) {
typeName = arg;
} else if (j == 5) {
try {
sqlType = Integer.parseInt(arg);
} catch (NumberFormatException nfe) {
String errorMsg = "JDBCAppender::setColumn(), Invalid column-option sqlType : "
+ arg + " !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
}
}
if (num_args == 2) {
value = null;
}
columns.add(new JDBCColumnStorage(name, logtype, value, typeName, sqlType));
}
/**
* Defines how many messages will be buffered until they will be updated to
* the database.
*
* @param value
* The new Buffer value
*/
public void setBuffer(String value) {
if (value == null) { return; }
value = value.trim();
if (value.length() == 0) { return; }
try {
buffer_size = Integer.parseInt(value);
} catch (Exception e) {
String errorMsg = "JDBCAppender::setBuffer(), Invalid BUFFER_OPTION value : " + value
+ " !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
}
/**
* Defines whether updated messages should be committed to the database.
*
* @param value
* The new Commit value
*/
public void setCommit(boolean value) {
this.commit = value;
}
/**
* Gets the ConnectionHandler attribute of the JDBCAppender object
*
* @return The ConnectionHandler value
*/
public JDBCConnectionHandler getConnectionHandler() {
return this.connectionHandler;
}
/**
* Gets the Connector attribute of the JDBCAppender object
*
* @return The Connector value
*/
public String getConnector() {
return this.connector;
}
/**
* Gets the Url attribute of the JDBCAppender object
*
* @return The Url value
*/
public String getUrl() {
return url;
}
/**
* Gets the Username attribute of the JDBCAppender object
*
* @return The Username value
*/
public String getUsername() {
return username;
}
/**
* Gets the Password attribute of the JDBCAppender object
*
* @return The Password value
*/
public String getPassword() {
return password;
}
/**
* Gets the Sql attribute of the JDBCAppender object
*
* @return The Sql value
*/
public String getSql() {
return sql;
}
/**
* Gets the class loader string
*
* @return The db class loader string
*/
public String getDbclass() {
return dbclass;
}
/**
* Gets the Table attribute of the JDBCAppender object
*
* @return The Table value
*/
public String getTable() {
return table;
}
/**
* Gets the Buffer attribute of the JDBCAppender object
*
* @return The Buffer value
*/
public String getBuffer() {
return Integer.toString(buffer_size);
}
/**
* Gets the Commit attribute of the JDBCAppender object
*
* @return The Commit value
*/
public boolean getCommit() {
return this.commit;
}
/**
* If program terminates close the database-connection and flush the buffer
*/
public void finalize() {
close();
super.finalize();
}
/**
* Internal method. Returns true, you may define your own layout...
*
* @return Description of the Returned Value
*/
public boolean requiresLayout() {
return true;
}
/**
* Internal method. Close the database connection & flush the buffer.
*/
public void close() {
flush_buffer();
if (connector == null && con != null) {
try {
con.close();
} catch (Exception e) {
String errorMsg = "JDBCAppender::close(), ";
LogLog.error(errorMsg, e);
errorHandler.error(errorMsg, e, 0);
}
}
this.closed = true;
}
/**
* Internal method. Appends the message to the database table.
*
* @param event
* Description of Parameter
*/
public void append(LoggingEvent event) {
try {
if (!ready) {
if (!ready()) {
String errorMsg = "JDBCAppender::append(), Not ready to append !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
}
buffer.add(event);
if (buffer_size > 1) {
// MDC problem fix for buffer_size > 1 from Patrick Carlos
// --- Taken from AsyncAppender ---
// Set the NDC and thread name for the calling thread as these
// LoggingEvent fields were not set at event creation time.
event.getNDC();
event.getThreadName();
// Get a copy of this thread's MDC.
event.getMDCCopy();
// make sure to also remember locationinfo in the event
event.getLocationInformation();
}
if (buffer.size() >= buffer_size) {
flush_buffer();
}
} catch (Exception e) {
String errorMsg = "JDBCAppender::append(), ";
LogLog.error(errorMsg, e);
errorHandler.error(errorMsg, e, 0);
}
}
/**
* Internal method. Flushes the buffer.
*/
public void flush_buffer() {
try {
int size = buffer.size();
if (size < 1) { return; }
for (int i = 0; i < size; i++) {
LoggingEvent event = (LoggingEvent) buffer.get(i);
jlogger.append(event, layout);
}
buffer.clear();
if (this.getCommit()) {
if (con != null) con.commit();
}
} catch (Exception e) {
String errorMsg = "JDBCAppender::flush_buffer(), : " + jlogger.getErrorMsg();
LogLog.error(errorMsg, e);
errorHandler.error(errorMsg, e, 0);
buffer.clear();
try {
if (this.getCommit()) {
if (con != null) con.rollback();
}
} catch (Exception ex) {
/* empty */
}
return;
}
}
/**
* Internal method. Returns true, when the JDBCAppender is ready to append
* messages to the database, else false.
*
* @return Description of the Returned Value
*/
public boolean ready() {
if (ready) { return true; }
if (!configured) {
if (!configure()) { return false; }
}
ready = jlogger.ready();
if (!ready) {
errorHandler.error(jlogger.getErrorMsg(), null, 0);
}
//Default Message-Layout
if (layout == null) {
layout = new PatternLayout("%m");
}
return ready;
}
/**
* Internal method. Connect to the database.
*
* @exception Exception
* Description of Exception
*/
protected void connect() throws Exception {
if (connected) { return; }
try {
if (connectionHandler == null) {
if (connector == null) {
if (url == null) { throw new Exception(
"JDBCAppender::connect(), No URL defined."); }
if (username == null) { throw new Exception(
"JDBCAppender::connect(), No USERNAME defined."); }
if (password == null) { throw new Exception(
"JDBCAppender::connect(), No PASSWORD defined."); }
connectionHandler = new JDBCDefaultConnectionHandler(url, username, password);
} else {
connectionHandler = (JDBCConnectionHandler) (Class.forName(connector)
.newInstance());
}
}
if (connectionHandler instanceof JDBCPoolConnectionHandler) {
jlogger.setConnection(connectionHandler);
} else {
if (url != null && username != null && password != null) {
con = connectionHandler.getConnection(url, username, password);
} else {
con = connectionHandler.getConnection();
}
if (con.isClosed()) { throw new Exception(
"JDBCAppender::connect(), JDBCConnectionHandler returns no connected Connection !"); }
jlogger.setConnection(con);
}
} catch (Exception e) {
throw new Exception("JDBCAppender::connect(), " + e);
}
connected = true;
}
/**
* Internal method. Configures for appending...
*
* @return Description of the Returned Value
*/
protected boolean configure() {
try {
if (configured) { return true; }
if (this.getDbclass() != null) {
Class.forName(this.getDbclass());
}
connect();
if (!connected) return false;
if (sqlHandler != null) {
jlogger.setSqlHandler(sqlHandler);
} else if (sql != null) {
jlogger.setSQL(sql);
} else if (table != null) {
jlogger.setTable(table);
} else if (procedure != null) {
jlogger.setProcedure(procedure, columns);
} else {
String errorMsg = "JDBCAppender::configure(), No SqlHandler or sql, table, procedure option given !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return false;
}
// set options in jlogger
jlogger.setCommit(this.getCommit());
jlogger.setQuoteReplace(this.isQuoteReplace());
jlogger.setLayoutPartsDelimiter(this.getLayoutPartsDelimiter());
jlogger.setThrowableMaxChars(this.getThrowableMaxChars());
jlogger.setUsePreparedStatements(this.isUsePreparedStatements());
for (int i = 0; i < columns.size(); i++) {
JDBCColumnStorage col = (JDBCColumnStorage) columns.get(i);
jlogger.setLogType(col.column, col.logtype, col.value);
}
} catch (Exception e) {
String errorMsg = "JDBCAppender::configure()";
LogLog.error(errorMsg, e);
errorHandler.error(errorMsg, e, 0);
return false;
}
configured = true;
return true;
}
/**
* Define whether to replace single quotes (') by 2 single quotes ('') in
* sql parameters.
* @return quoteReplace
*/
public boolean isQuoteReplace() {
return quoteReplace;
}
/**
* Define whether to replace single quotes (') by 2 single quotes ('') in
* sql parameters.
*
* @param b
*/
public void setQuoteReplace(boolean b) {
quoteReplace = b;
}
/**
* character to separate parts of layout if more than one part is to be used
* @return layoutPartsDelimiter
*/
public String getLayoutPartsDelimiter() {
return layoutPartsDelimiter;
}
/**
* character to separate parts of layout if more than one part is to be used
* @param c
*/
public void setLayoutPartsDelimiter(String c) {
layoutPartsDelimiter = c;
}
/**
* @return Returns the usePreparedStatements.
*/
public boolean isUsePreparedStatements() {
return usePreparedStatements;
}
/**
* Defines whether to use Prepared Statements instead of updateable result
* sets (default false).
*
* @param usePreparedStatements
* The usePreparedStatements to set.
*/
public void setUsePreparedStatements(boolean usePreparedStatements) {
if (table == null) {
String errorMsg = "JDBCAppender::setUsePreparedStatements(), Table-Option has to be set before !";
LogLog.error(errorMsg);
errorHandler.error(errorMsg, null, 0);
return;
}
this.usePreparedStatements = usePreparedStatements;
}
/**
* Returns the procedure.
* @return Returns the procedure.
*/
public String getProcedure() {
return procedure;
}
/**
* Stores the procedure which will be called.
* @param procedure The procedure to set.
*/
public void setProcedure(String procedure) {
this.procedure = procedure;
}
/**
* Returns the maximum number of characters in throwable/exception stack trace. Used to limit very long stack traces.
* @return Returns the throwableMaxChars.
*/
public int getThrowableMaxChars() {
return throwableMaxChars;
}
/**
* Sets the maximum number of characters in throwable/exception stack trace. Used to limit very long stack traces.
* @param throwableMaxChars The throwableMaxChars to set.
*/
public void setThrowableMaxChars(int throwableMaxChars) {
this.throwableMaxChars = throwableMaxChars;
}
}