package org.agnitas.dao.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.agnitas.util.AgnUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobCreator;
public abstract class BaseDaoImpl {
// ----------------------------------------------------------------------------------------------------------------
// Dependency Injection
protected DataSource dataSource;
private SimpleJdbcTemplate simpleJdbcTemplate = null;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public DataSource getDataSource() {
return dataSource;
}
protected SimpleJdbcTemplate getSimpleJdbcTemplate() {
if (simpleJdbcTemplate == null)
simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
return simpleJdbcTemplate;
}
protected void logSqlStatement(Logger logger, String statement, Object... parameter) {
if (logger.isDebugEnabled()) {
if (parameter != null && parameter.length > 0) {
logger.debug("SQL:" + statement + " Parameter: " + StringUtils.join(parameter, ", "));
} else {
logger.debug("SQL:" + statement);
}
}
}
protected void logSqlError(Exception e, Logger logger, String statement, Object... parameter) {
AgnUtils.sendExceptionMail("SQL: " + statement + " Parameter: " + StringUtils.join(parameter, ", "), e);
logger.error("Error:" + e, e);
}
protected void closeSilently(Statement... statements) {
for (Statement statement : statements) {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* Logs the statement and parameter in debug-level, executes select and logs error.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected List<Map<String, Object>> select(Logger logger, String statement, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
return getSimpleJdbcTemplate().queryForList(statement, parameter);
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Logs the statement and parameter in debug-level, executes select and logs error.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected <T> List<T> select(Logger logger, String statement, ParameterizedRowMapper<T> rowMapper, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
return getSimpleJdbcTemplate().query(statement, rowMapper, parameter);
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Logs the statement and parameter in debug-level, executes select and logs error.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected <T> T select(Logger logger, String statement, Class<T> requiredType, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
return getSimpleJdbcTemplate().queryForObject(statement, requiredType, parameter);
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Logs the statement and parameter in debug-level, executes select and logs error.
* If the searched entry does not exist an DataAccessException is thrown.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected <T> T selectObject(Logger logger, String statement, ParameterizedRowMapper<T> rowMapper, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
return getSimpleJdbcTemplate().queryForObject(statement, rowMapper, parameter);
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Logs the statement and parameter in debug-level, executes select and logs error.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected int selectInt(Logger logger, String statement, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
return getSimpleJdbcTemplate().queryForInt(statement, parameter);
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Logs the statement and parameter in debug-level, executes select and logs error.
* The given default value is returned, if the statement return an EmptyResultDataAccessException,
* which indicates that the selected value is missing and no rows are returned by DB.
* All other Exceptions are not touched and will be thrown in the usual way.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected int selectIntWithDefaultValue(Logger logger, String statement, int defaultValue, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
return getSimpleJdbcTemplate().queryForInt(statement, parameter);
} catch (EmptyResultDataAccessException e) {
if (logger.isDebugEnabled()) {
logger.debug("Empty result, using default value: " + defaultValue);
}
return defaultValue;
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Logs the statement and parameter in debug-level, executes update and logs error.
*
* @param logger
* @param statement
* @param parameter
* @return
* @throws Exception
*/
protected int update(Logger logger, String statement, Object... parameter) {
try {
logSqlStatement(logger, statement, parameter);
int touchedLines = getSimpleJdbcTemplate().update(statement, parameter);
if (logger.isDebugEnabled()) {
logger.debug("lines changed by update: " + touchedLines);
}
return touchedLines;
} catch (DataAccessException e) {
logSqlError(e, logger, statement, parameter);
throw e;
} catch (RuntimeException e) {
logSqlError(e, logger, statement, parameter);
throw e;
}
}
/**
* Method to update the data of an blob.
* This method should be DB-Vendor independent.
* The update statement must contain at least one parameter for the blob data and this must be the first parameter within the statement.
*
* Example: updateBlob(logger, "UPDATE tableName SET blobField = ? WHERE idField1 = ? AND idField2 = ?", blobDataArray, id1Object, id2Object);
*
* @param statementString
* @param blobData
* @param parameter
* @throws Exception
*/
public void updateBlob(Logger logger, String statement, final byte[] blobData, final Object... parameter) throws Exception {
final InputStream dataStream = new ByteArrayInputStream(blobData);
try {
logSqlStatement(logger, statement, "blobDataLength:" + blobData.length, parameter);
new JdbcTemplate(dataSource).execute(statement, new AbstractLobCreatingPreparedStatementCallback(new DefaultLobHandler()) {
protected void setValues(PreparedStatement preparedStatement, LobCreator lobCreator) throws SQLException {
lobCreator.setBlobAsBinaryStream(preparedStatement, 1, dataStream, (int) blobData.length);
int parameterIndex = 2;
for (Object parameterObject : parameter) {
preparedStatement.setObject(parameterIndex++, parameterObject);
}
}
});
} catch(Exception e) {
logSqlError(e, logger, statement, "blobDataLength:" + blobData.length, parameter);
throw e;
} finally {
try {
dataStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}