quickfix.JdbcLog Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quickfixj-core Show documentation
Show all versions of quickfixj-core Show documentation
The core QuickFIX/J engine
/*******************************************************************************
* Copyright (c) quickfixengine.org All rights reserved.
*
* This file is part of the QuickFIX FIX Engine
*
* This file may be distributed under the terms of the quickfixengine.org
* license as defined by quickfixengine.org and appearing in the file
* LICENSE included in the packaging of this file.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
* THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE.
*
* See http://www.quickfixengine.org/LICENSE for licensing information.
*
* Contact [email protected] if any conditions of this licensing
* are not clear to you.
******************************************************************************/
package quickfix;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import static quickfix.JdbcSetting.SETTING_JDBC_LOG_HEARTBEATS;
import static quickfix.JdbcSetting.SETTING_JDBC_SESSION_ID_DEFAULT_PROPERTY_VALUE;
import static quickfix.JdbcSetting.SETTING_LOG_EVENT_TABLE;
import static quickfix.JdbcSetting.SETTING_LOG_INCOMING_TABLE;
import static quickfix.JdbcSetting.SETTING_LOG_OUTGOING_TABLE;
import static quickfix.JdbcUtil.determineSessionIdSupport;
import static quickfix.JdbcUtil.getIDColumns;
import static quickfix.JdbcUtil.getIDPlaceholders;
import static quickfix.JdbcUtil.getIDWhereClause;
class JdbcLog extends AbstractLog {
private static final String DEFAULT_MESSAGES_LOG_TABLE = "messages_log";
private static final String DEFAULT_EVENT_LOG_TABLE = "event_log";
private final String outgoingMessagesTableName;
private final String incomingMessagesTableName;
private final String eventTableName;
private final SessionID sessionID;
private final DataSource dataSource;
private final boolean logHeartbeats;
private final boolean extendedSessionIdSupported;
private final String defaultSessionIdPropertyValue;
private Throwable recursiveException = null;
private final Map insertItemSqlCache = new HashMap<>();
private final Map deleteItemsSqlCache = new HashMap<>();
public JdbcLog(SessionSettings settings, SessionID sessionID, DataSource ds)
throws SQLException, ClassNotFoundException, ConfigError, FieldConvertError {
this.sessionID = sessionID;
dataSource = ds == null
? JdbcUtil.getDataSource(settings, sessionID)
: ds;
logHeartbeats = !settings.isSetting(sessionID, SETTING_JDBC_LOG_HEARTBEATS)
|| settings.getBool(sessionID, SETTING_JDBC_LOG_HEARTBEATS);
setLogHeartbeats(logHeartbeats);
if (settings.isSetting(sessionID, SETTING_LOG_OUTGOING_TABLE)) {
outgoingMessagesTableName = settings.getString(sessionID, SETTING_LOG_OUTGOING_TABLE);
} else {
outgoingMessagesTableName = DEFAULT_MESSAGES_LOG_TABLE;
}
if (settings.isSetting(sessionID, SETTING_LOG_INCOMING_TABLE)) {
incomingMessagesTableName = settings.getString(sessionID, SETTING_LOG_INCOMING_TABLE);
} else {
incomingMessagesTableName = DEFAULT_MESSAGES_LOG_TABLE;
}
if (settings.isSetting(sessionID, SETTING_LOG_EVENT_TABLE)) {
eventTableName = settings.getString(sessionID, SETTING_LOG_EVENT_TABLE);
} else {
eventTableName = DEFAULT_EVENT_LOG_TABLE;
}
if (settings.isSetting(sessionID, SETTING_JDBC_SESSION_ID_DEFAULT_PROPERTY_VALUE)) {
defaultSessionIdPropertyValue = settings.getString(sessionID,
SETTING_JDBC_SESSION_ID_DEFAULT_PROPERTY_VALUE);
} else {
defaultSessionIdPropertyValue = SessionID.NOT_SET;
}
// One table is sampled for the extended session ID columns. Be sure
// that all tables are extended if you extend any of them.
extendedSessionIdSupported = determineSessionIdSupport(dataSource,
outgoingMessagesTableName);
createCachedSql();
}
private void createCachedSql() {
createInsertItemSql(outgoingMessagesTableName);
createInsertItemSql(incomingMessagesTableName);
createInsertItemSql(eventTableName);
createDeleteItemsSql(outgoingMessagesTableName);
createDeleteItemsSql(incomingMessagesTableName);
createDeleteItemsSql(eventTableName);
}
private void createInsertItemSql(String tableName) {
insertItemSqlCache.put(tableName, "INSERT INTO " + tableName + " (time, "
+ getIDColumns(extendedSessionIdSupported) + ", text) " + "VALUES (?,"
+ getIDPlaceholders(extendedSessionIdSupported) + ",?)");
}
private String getInsertItemSql(String tableName) {
return insertItemSqlCache.get(tableName);
}
private void createDeleteItemsSql(String tableName) {
deleteItemsSqlCache.put(tableName, "DELETE FROM " + tableName + " WHERE "
+ getIDWhereClause(extendedSessionIdSupported));
}
private String getDeleteItemsSql(String tableName) {
return deleteItemsSqlCache.get(tableName);
}
public void onEvent(String value) {
insert(eventTableName, value);
}
protected void logIncoming(String message) {
insert(incomingMessagesTableName, message);
}
protected void logOutgoing(String message) {
insert(outgoingMessagesTableName, message);
}
/**
* Protect from the situation when you have recursive calls
* into the logger b/c the previous one failed (in case of a failed DB connection, for example).
* In case of going into a failure mode set a flag, ignore the recursive request and reset the flag.
*
* @param tableName
* @param value
*/
private void insert(String tableName, String value) {
Connection connection = null;
PreparedStatement insert = null;
if (recursiveException != null) {
System.err.println("JdbcLog cannot log SQLException due to recursive log errors!");
recursiveException.printStackTrace();
recursiveException = null;
return;
}
recursiveException = null;
try {
connection = dataSource.getConnection();
insert = connection.prepareStatement(getInsertItemSql(tableName));
insert.setTimestamp(1, new Timestamp(SystemTime.getUtcCalendar().getTimeInMillis()));
int offset = setSessionIdParameters(insert, 2);
insert.setString(offset, value);
insert.execute();
} catch (SQLException e) {
recursiveException = e;
LogUtil.logThrowable(sessionID, e.getMessage(), e);
} finally {
JdbcUtil.close(sessionID, insert);
JdbcUtil.close(sessionID, connection);
}
}
/**
* Deletes all rows from the log tables.
*/
public void clear() {
clearTable(eventTableName);
clearTable(incomingMessagesTableName);
if (!incomingMessagesTableName.equals(outgoingMessagesTableName)) {
clearTable(outgoingMessagesTableName);
}
}
private void clearTable(String tableName) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement(getDeleteItemsSql(tableName));
setSessionIdParameters(statement, 1);
statement.execute();
} catch (SQLException e) {
LogUtil.logThrowable(sessionID, e.getMessage(), e);
} finally {
JdbcUtil.close(sessionID, statement);
JdbcUtil.close(sessionID, connection);
}
}
public String getIncomingMessagesTableName() {
return incomingMessagesTableName;
}
public String getOutgoingMessagesTableName() {
return outgoingMessagesTableName;
}
public String getEventTableName() {
return eventTableName;
}
private int setSessionIdParameters(PreparedStatement query, int offset) throws SQLException {
return JdbcUtil.setSessionIdParameters(sessionID, query, offset,
extendedSessionIdSupported, defaultSessionIdPropertyValue);
}
public void onErrorEvent(String text) {
onEvent(text);
}
}