diff --git a/donkey/donkeydbconf/default.xml b/donkey/donkeydbconf/default.xml index e552f9935b..fd52fa2939 100644 --- a/donkey/donkeydbconf/default.xml +++ b/donkey/donkeydbconf/default.xml @@ -11,11 +11,6 @@ VALUES (?, ?, ?, ?, ?, ?) - - INSERT INTO D_MC${localChannelId} (METADATA_ID, MESSAGE_ID, CONTENT_TYPE, CONTENT, DATA_TYPE, IS_ENCRYPTED) - VALUES (?, ?, ?, ?, ?, ?) - - UPDATE D_MC${localChannelId} SET CONTENT = ?, DATA_TYPE = ?, IS_ENCRYPTED = ? WHERE METADATA_ID = ? diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/DonkeyConnectionPools.java b/donkey/src/main/java/com/mirth/connect/donkey/server/DonkeyConnectionPools.java index e8c11696aa..2a84e6a012 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/DonkeyConnectionPools.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/DonkeyConnectionPools.java @@ -12,15 +12,18 @@ import java.util.Properties; import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import com.google.inject.Inject; import com.mirth.connect.donkey.model.DatabaseConstants; import com.mirth.connect.donkey.server.data.jdbc.ConnectionPool; -import com.mirth.connect.donkey.server.data.jdbc.DBCPConnectionPool; import com.mirth.connect.donkey.server.data.jdbc.HikariConnectionPool; public class DonkeyConnectionPools { + private static final Logger logger = LogManager.getLogger(DonkeyConnectionPools.class); + @Inject private static volatile DonkeyConnectionPools instance = null; @@ -59,7 +62,8 @@ public void init(Properties dbProperties) { String url = dbProperties.getProperty(DatabaseConstants.DATABASE_URL); String username = dbProperties.getProperty(DatabaseConstants.DATABASE_USERNAME); String password = dbProperties.getProperty(DatabaseConstants.DATABASE_PASSWORD); - String pool = dbProperties.getProperty(DatabaseConstants.DATABASE_POOL); + warnIfPoolConfigured(dbProperties); + boolean jdbc4 = Boolean.parseBoolean(dbProperties.getProperty(DatabaseConstants.DATABASE_JDBC4)); String testQuery = dbProperties.getProperty(DatabaseConstants.DATABASE_TEST_QUERY); int maxConnections; @@ -70,7 +74,7 @@ public void init(Properties dbProperties) { throw new Exception("Failed to read the " + DatabaseConstants.DATABASE_MAX_CONNECTIONS + " configuration property"); } - connectionPool = createConnectionPool(database, driver, url, username, password, pool, jdbc4, testQuery, maxConnections, false); + connectionPool = createConnectionPool(database, driver, url, username, password, jdbc4, testQuery, maxConnections, false); boolean splitReadWrite = Boolean.parseBoolean(dbProperties.getProperty(DatabaseConstants.DATABASE_ENABLE_READ_WRITE_SPLIT)); @@ -80,7 +84,6 @@ public void init(Properties dbProperties) { String readOnlyUrl = dbProperties.getProperty(DatabaseConstants.DATABASE_READONLY_URL, url); String readOnlyUsername = dbProperties.getProperty(DatabaseConstants.DATABASE_READONLY_USERNAME, username); String readOnlyPassword = dbProperties.getProperty(DatabaseConstants.DATABASE_READONLY_PASSWORD, password); - String readOnlyPool = dbProperties.getProperty(DatabaseConstants.DATABASE_READONLY_POOL, pool); boolean readOnlyJdbc4 = Boolean.parseBoolean(dbProperties.getProperty(DatabaseConstants.DATABASE_READONLY_JDBC4, dbProperties.getProperty(DatabaseConstants.DATABASE_JDBC4))); String readOnlyTestQuery = dbProperties.getProperty(DatabaseConstants.DATABASE_READONLY_TEST_QUERY, testQuery); int readOnlyMaxConnections; @@ -91,7 +94,7 @@ public void init(Properties dbProperties) { throw new Exception("Failed to read the " + DatabaseConstants.DATABASE_READONLY_MAX_CONNECTIONS + " configuration property"); } - readOnlyConnectionPool = createConnectionPool(readOnlyDatabase, readOnlyDriver, readOnlyUrl, readOnlyUsername, readOnlyPassword, readOnlyPool, readOnlyJdbc4, readOnlyTestQuery, readOnlyMaxConnections, true); + readOnlyConnectionPool = createConnectionPool(readOnlyDatabase, readOnlyDriver, readOnlyUrl, readOnlyUsername, readOnlyPassword, readOnlyJdbc4, readOnlyTestQuery, readOnlyMaxConnections, true); } else { readOnlyConnectionPool = connectionPool; } @@ -100,15 +103,21 @@ public void init(Properties dbProperties) { } } - public ConnectionPool createConnectionPool(String database, String driver, String url, String username, String password, String pool, boolean jdbc4, String testQuery, int maxConnections, boolean readOnly) throws Exception { + public ConnectionPool createConnectionPool(String database, String driver, String url, String username, String password, boolean jdbc4, String testQuery, int maxConnections, boolean readOnly) throws Exception { if (driver != null) { Class.forName(driver); } - if (StringUtils.equalsIgnoreCase(pool, "DBCP")) { - return new DBCPConnectionPool(url, username, password, maxConnections, readOnly); - } else { - return new HikariConnectionPool(driver, url, username, password, maxConnections, jdbc4, testQuery, readOnly); + return new HikariConnectionPool(driver, url, username, password, maxConnections, jdbc4, testQuery, readOnly); + } + + private void warnIfPoolConfigured(Properties dbProperties) { + for (String property : new String[] { DatabaseConstants.DATABASE_POOL, + DatabaseConstants.DATABASE_READONLY_POOL }) { + // Only DBCP was defined. Anything but DBCP was taken to be Hikari. + if (StringUtils.equalsIgnoreCase(dbProperties.getProperty(property), "DBCP")) { + logger.warn("The {} setting is no longer supported and will be ignored; HikariCP is always used.", property); + } } } } diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/channel/Channel.java b/donkey/src/main/java/com/mirth/connect/donkey/server/channel/Channel.java index a78f2371f7..19b2db6530 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/channel/Channel.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/channel/Channel.java @@ -1728,26 +1728,23 @@ protected Message process(ConnectorMessage sourceMessage, boolean markAsProcesse } // store the raw, transformed and encoded content - boolean insertedContent = false; + List contentToInsert = new ArrayList(); ThreadUtils.checkInterruptedStatus(); if (storageSettings.isStoreProcessedRaw() && sourceMessage.getProcessedRaw() != null) { - dao.batchInsertMessageContent(sourceMessage.getProcessedRaw()); - insertedContent = true; + contentToInsert.add(sourceMessage.getProcessedRaw()); } if (storageSettings.isStoreTransformed() && sourceMessage.getTransformed() != null) { - dao.batchInsertMessageContent(sourceMessage.getTransformed()); - insertedContent = true; + contentToInsert.add(sourceMessage.getTransformed()); } if (storageSettings.isStoreSourceEncoded() && sourceMessage.getEncoded() != null) { - dao.batchInsertMessageContent(sourceMessage.getEncoded()); - insertedContent = true; + contentToInsert.add(sourceMessage.getEncoded()); } - if (insertedContent) { - dao.executeBatchInsertMessageContent(channelId); + if (!contentToInsert.isEmpty()) { + dao.insertMessageContentBatch(contentToInsert); } // create a message for each destination chain diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/DonkeyDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/DonkeyDao.java index 032d65986e..90fa466710 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/DonkeyDao.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/DonkeyDao.java @@ -29,9 +29,7 @@ public interface DonkeyDao { public void insertMessageContent(MessageContent messageContent); - public void batchInsertMessageContent(MessageContent messageContent); - - public void executeBatchInsertMessageContent(String channelId); + public void insertMessageContentBatch(List messageContents); public void insertMessageAttachment(String channelId, long messageId, Attachment attachment); diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/BufferedDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/BufferedDao.java index fc1c2efbaa..3d41f34116 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/BufferedDao.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/BufferedDao.java @@ -103,6 +103,7 @@ private DonkeyDao getDelegateDao() { return dao; } + @SuppressWarnings("unchecked") private void executeTasks(Boolean durable) { DonkeyDao dao = getDelegateDao(); boolean commitSuccess = false; @@ -117,8 +118,7 @@ private void executeTasks(Boolean durable) { case INSERT_MESSAGE: dao.insertMessage((Message) p[0]); break; case INSERT_CONNECTOR_MESSAGE: dao.insertConnectorMessage((ConnectorMessage) p[0], (Boolean) p[1], (Boolean) p[2]); break; case INSERT_MESSAGE_CONTENT: dao.insertMessageContent((MessageContent) p[0]); break; - case BATCH_INSERT_MESSAGE_CONTENT: dao.batchInsertMessageContent((MessageContent) p[0]); break; - case EXECUTE_BATCH_INSERT_MESSAGE_CONTENT: dao.executeBatchInsertMessageContent((String) p[0]); break; + case INSERT_MESSAGE_CONTENT_BATCH: dao.insertMessageContentBatch((List) p[0]); break; case INSERT_MESSAGE_ATTACHMENT: dao.insertMessageAttachment((String) p[0], (Long) p[1], (Attachment) p[2]); break; case UPDATE_MESSAGE_ATTACHMENT: dao.updateMessageAttachment((String) p[0], (Long) p[1], (Attachment) p[2]); break; case INSERT_META_DATA: dao.insertMetaData((ConnectorMessage) p[0], (List) p[1]); break; @@ -203,15 +203,9 @@ public void insertMessageContent(MessageContent messageContent) { } @Override - public void batchInsertMessageContent(MessageContent messageContent) { - tasks.add(new DaoTask(DaoTaskType.BATCH_INSERT_MESSAGE_CONTENT, new Object[] { - messageContent })); - } - - @Override - public void executeBatchInsertMessageContent(String channelId) { - tasks.add(new DaoTask(DaoTaskType.EXECUTE_BATCH_INSERT_MESSAGE_CONTENT, new Object[] { - channelId })); + public void insertMessageContentBatch(List messageContents) { + tasks.add(new DaoTask(DaoTaskType.INSERT_MESSAGE_CONTENT_BATCH, new Object[] { + messageContents })); } @Override diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/DaoTaskType.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/DaoTaskType.java index fbccf8c551..94b63fc7ec 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/DaoTaskType.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/buffered/DaoTaskType.java @@ -10,5 +10,5 @@ package com.mirth.connect.donkey.server.data.buffered; public enum DaoTaskType { - INSERT_MESSAGE, INSERT_CONNECTOR_MESSAGE, INSERT_MESSAGE_CONTENT, BATCH_INSERT_MESSAGE_CONTENT, EXECUTE_BATCH_INSERT_MESSAGE_CONTENT, INSERT_MESSAGE_ATTACHMENT, UPDATE_MESSAGE_ATTACHMENT, INSERT_META_DATA, STORE_META_DATA, INSERT_EVENT, STORE_MESSAGE_CONTENT, STORE_CHANNEL_STATISTICS, UPDATE_SEND_ATTEMPTS, UPDATE_STATUS, UPDATE_ERRORS, UPDATE_MAPS, UPDATE_SOURCE_MAP, UPDATE_RESPONSE_MAP, MARK_AS_PROCESSED, RESET_MESSAGE, DELETE_MESSAGE, DELETE_CONNECTOR_MESSAGES, DELETE_MESSAGE_STATISTICS, DELETE_ALL_MESSAGES, DELETE_MESSAGE_CONTENT, DELETE_MESSAGE_CONTENT_BY_META_DATA_IDS, DELETE_MESSAGE_ATTACHMENTS, CREATE_CHANNEL, REMOVE_CHANNEL, CHECK_CHANNEL_TABLES, ADD_META_DATA_COLUMN, REMOVE_META_DATA_COLUMN, RESET_STATISTICS, RESET_ALL_STATISTICS, GET_PORTS_IN_USE; + INSERT_MESSAGE, INSERT_CONNECTOR_MESSAGE, INSERT_MESSAGE_CONTENT, INSERT_MESSAGE_CONTENT_BATCH, INSERT_MESSAGE_ATTACHMENT, UPDATE_MESSAGE_ATTACHMENT, INSERT_META_DATA, STORE_META_DATA, INSERT_EVENT, STORE_MESSAGE_CONTENT, STORE_CHANNEL_STATISTICS, UPDATE_SEND_ATTEMPTS, UPDATE_STATUS, UPDATE_ERRORS, UPDATE_MAPS, UPDATE_SOURCE_MAP, UPDATE_RESPONSE_MAP, MARK_AS_PROCESSED, RESET_MESSAGE, DELETE_MESSAGE, DELETE_CONNECTOR_MESSAGES, DELETE_MESSAGE_STATISTICS, DELETE_ALL_MESSAGES, DELETE_MESSAGE_CONTENT, DELETE_MESSAGE_CONTENT_BY_META_DATA_IDS, DELETE_MESSAGE_ATTACHMENTS, CREATE_CHANNEL, REMOVE_CHANNEL, CHECK_CHANNEL_TABLES, ADD_META_DATA_COLUMN, REMOVE_META_DATA_COLUMN, RESET_STATISTICS, RESET_ALL_STATISTICS, GET_PORTS_IN_USE; } diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/CachedPreparedStatementSource.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/CachedPreparedStatementSource.java deleted file mode 100644 index ac11a56817..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/CachedPreparedStatementSource.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.jdbc; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; - -public class CachedPreparedStatementSource implements PreparedStatementSource { - private Map> statements = new HashMap>(); - private QuerySource querySource; - private Connection connection; - - public CachedPreparedStatementSource(Connection connection, QuerySource querySource) { - this.connection = connection; - this.querySource = querySource; - } - - @Override - public PreparedStatement getPreparedStatement(String queryId, Long localChannelId) throws SQLException { - PreparedStatement statement = null; - Map channelStatements = statements.get(localChannelId); - - if (channelStatements == null) { - channelStatements = new HashMap(); - statements.put(localChannelId, channelStatements); - } else { - statement = channelStatements.get(queryId); - } - - if (statement == null || statement.isClosed()) { - statement = null; - - if (localChannelId == null) { - String query = querySource.getQuery(queryId); - - if (query != null) { - statement = connection.prepareStatement(query); - } - } else { - Map values = new HashMap(); - values.put("localChannelId", localChannelId); - - String query = querySource.getQuery(queryId, values); - - if (query != null) { - statement = connection.prepareStatement(query); - } - } - - channelStatements.put(queryId, statement); - } - - return statement; - } -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/ConnectionPool.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/ConnectionPool.java index ef0f8349b3..d13a3373d8 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/ConnectionPool.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/ConnectionPool.java @@ -9,14 +9,13 @@ package com.mirth.connect.donkey.server.data.jdbc; +import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; public interface ConnectionPool { - public PooledConnection getConnection() throws SQLException; - - public Integer getMaxConnections(); + public Connection getConnection() throws SQLException; public DataSource getDataSource(); } diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/DBCPConnectionPool.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/DBCPConnectionPool.java deleted file mode 100644 index 643d1b70b8..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/DBCPConnectionPool.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.jdbc; - -import java.sql.Connection; -import java.sql.SQLException; - -import javax.sql.DataSource; - -import org.apache.commons.dbcp2.ConnectionFactory; -import org.apache.commons.dbcp2.DelegatingConnection; -import org.apache.commons.dbcp2.DriverManagerConnectionFactory; -import org.apache.commons.dbcp2.PoolableConnection; -import org.apache.commons.dbcp2.PoolableConnectionFactory; -import org.apache.commons.dbcp2.PoolingDataSource; -import org.apache.commons.pool2.impl.GenericObjectPool; - -public class DBCPConnectionPool implements ConnectionPool { - private DataSource dataSource; - private int maxConnections; - - public DBCPConnectionPool(String url, String username, String password, int maxConnections, boolean readOnly) { - this.maxConnections = maxConnections; - - ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(url, username, password); - PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null); - poolableConnectionFactory.setDefaultAutoCommit(false); - poolableConnectionFactory.setDefaultReadOnly(readOnly); - - GenericObjectPool connectionPool = new GenericObjectPool(poolableConnectionFactory); - connectionPool.setMaxTotal(maxConnections); - connectionPool.setMaxIdle(maxConnections); - - poolableConnectionFactory.setPool(connectionPool); - - PoolingDataSource dataSource = new PoolingDataSource(connectionPool); - dataSource.setAccessToUnderlyingConnectionAllowed(true); - - this.dataSource = dataSource; - } - - @Override - public PooledConnection getConnection() throws SQLException { - Connection connection = dataSource.getConnection(); - return new PooledConnection(connection, ((DelegatingConnection) connection).getInnermostDelegate()); - } - - @Override - public Integer getMaxConnections() { - return maxConnections; - } - - @Override - public DataSource getDataSource() { - return dataSource; - } -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/DisabledConnectionPool.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/DisabledConnectionPool.java deleted file mode 100644 index d823de620c..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/DisabledConnectionPool.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.jdbc; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - -import javax.sql.DataSource; - -public class DisabledConnectionPool implements ConnectionPool { - private String url; - private String username; - private String password; - private boolean readOnly; - - public DisabledConnectionPool(String url, String username, String password, boolean readOnly) { - this.url = url; - this.username = username; - this.password = password; - this.readOnly = readOnly; - } - - @Override - public PooledConnection getConnection() throws SQLException { - Connection connection = DriverManager.getConnection(url, username, password); - connection.setAutoCommit(false); - if (readOnly) { - connection.setReadOnly(true); - } - return new PooledConnection(connection, connection); - } - - @Override - public Integer getMaxConnections() { - return null; - } - - @Override - public DataSource getDataSource() { - return null; - } -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/HikariConnectionPool.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/HikariConnectionPool.java index 54bc41ad6c..434a6c6bd8 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/HikariConnectionPool.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/HikariConnectionPool.java @@ -18,11 +18,8 @@ public class HikariConnectionPool implements ConnectionPool { private HikariDataSource dataSource; - private int maxConnections; public HikariConnectionPool(String driver, String url, String username, String password, int maxConnections, boolean jdbc4, String testQuery, boolean readOnly) { - this.maxConnections = maxConnections; - dataSource = new HikariDataSource(); dataSource.setDriverClassName(driver); dataSource.setJdbcUrl(url); @@ -40,14 +37,8 @@ public HikariConnectionPool(String driver, String url, String username, String p } @Override - public PooledConnection getConnection() throws SQLException { - Connection connection = dataSource.getConnection(); - return new PooledConnection(connection, connection.unwrap(Connection.class)); - } - - @Override - public Integer getMaxConnections() { - return maxConnections; + public Connection getConnection() throws SQLException { + return dataSource.getConnection(); } @Override diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java index 999b863f0c..1ff1034560 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDao.java @@ -33,7 +33,6 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.dbutils.DbUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -65,7 +64,6 @@ public class JdbcDao implements DonkeyDao { private Donkey donkey; private Connection connection; private QuerySource querySource; - private PreparedStatementSource statementSource; private SerializerProvider serializerProvider; private boolean encryptMessageContent; private boolean encryptAttachments; @@ -87,11 +85,10 @@ public class JdbcDao implements DonkeyDao { private char quoteChar = '"'; private Logger logger = LogManager.getLogger(this.getClass()); - protected JdbcDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { + protected JdbcDao(Donkey donkey, Connection connection, QuerySource querySource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { this.donkey = donkey; this.connection = connection; this.querySource = querySource; - this.statementSource = statementSource; this.serializerProvider = serializerProvider; this.encryptMessageContent = encryptMessageContent; this.encryptAttachments = encryptAttachments; @@ -137,9 +134,7 @@ public void setQuoteChar(char quoteChar) { public void insertMessage(Message message) { logger.debug(message.getChannelId() + "/" + message.getMessageId() + ": inserting message"); - PreparedStatement statement = null; - try { - statement = prepareStatement("insertMessage", message.getChannelId()); + try (PreparedStatement statement = prepareStatement("insertMessage", message.getChannelId())) { statement.setLong(1, message.getMessageId()); statement.setString(2, message.getServerId()); statement.setTimestamp(3, new Timestamp(message.getReceivedDate().getTimeInMillis())); @@ -172,8 +167,6 @@ public void insertMessage(Message message) { statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -184,9 +177,7 @@ public void updateSendAttempts(ConnectorMessage connectorMessage) { Calendar sendDate = connectorMessage.getSendDate(); Calendar responseDate = connectorMessage.getResponseDate(); - PreparedStatement statement = null; - try { - statement = prepareStatement("updateSendAttempts", connectorMessage.getChannelId()); + try (PreparedStatement statement = prepareStatement("updateSendAttempts", connectorMessage.getChannelId())) { statement.setInt(1, connectorMessage.getSendAttempts()); statement.setTimestamp(2, sendDate == null ? null : new Timestamp(sendDate.getTimeInMillis())); statement.setTimestamp(3, responseDate == null ? null : new Timestamp(responseDate.getTimeInMillis())); @@ -196,8 +187,6 @@ public void updateSendAttempts(ConnectorMessage connectorMessage) { statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -208,83 +197,47 @@ public void insertMessageContent(MessageContent messageContent) { insertContent(messageContent.getChannelId(), messageContent.getMessageId(), messageContent.getMetaDataId(), messageContent.getContentType(), messageContent.getContent(), messageContent.getDataType(), messageContent.isEncrypted()); } - /* - * The statement is deliberately left open here. It is the cached statement that holds the - * accumulated batch, so closing it would discard every addBatch() made so far; - * executeBatchInsertMessageContent() runs the batch and closes the statement if the - * subclass needs that. - */ @Override - public void batchInsertMessageContent(MessageContent messageContent) { - logger.debug(messageContent.getChannelId() + "/" + messageContent.getMessageId() + "/" + messageContent.getMetaDataId() + ": batch inserting message content (" + messageContent.getContentType().toString() + ")"); + public void insertMessageContentBatch(List messageContents) { + if (messageContents.isEmpty()) { + return; + } - PreparedStatement statement = null; - try { - String content; - boolean encrypted; + String channelId = messageContents.get(0).getChannelId(); + logger.debug(channelId + ": batch inserting message content"); - // Only encrypt if the content is not already encrypted - if (encryptMessageContent && encryptor != null && !messageContent.isEncrypted()) { - content = encryptor.encrypt(messageContent.getContent()); - encrypted = true; - } else { - content = messageContent.getContent(); - encrypted = messageContent.isEncrypted(); - } + try (PreparedStatement statement = prepareStatement("insertMessageContent", channelId)) { + for (MessageContent messageContent : messageContents) { + if (!channelId.equals(messageContent.getChannelId())) { + throw new DonkeyDaoException("Cannot batch insert content for channel " + messageContent.getChannelId() + " along with content for channel " + channelId); + } - statement = prepareStatement("batchInsertMessageContent", messageContent.getChannelId()); - statement.setInt(1, messageContent.getMetaDataId()); - statement.setLong(2, messageContent.getMessageId()); - statement.setInt(3, messageContent.getContentType().getContentTypeCode()); - statement.setString(4, content); - statement.setString(5, messageContent.getDataType()); - statement.setBoolean(6, encrypted); + String content; + boolean encrypted; - statement.addBatch(); - statement.clearParameters(); - } catch (SQLException e) { - // The batch will never be executed now, so do not leave it for the next message. - clearBatchQuietly(statement); - closeDatabaseObjectIfNeeded(statement); - throw new DonkeyDaoException(e); - } - } + // Only encrypt if the content is not already encrypted + if (encryptMessageContent && encryptor != null && !messageContent.isEncrypted()) { + content = encryptor.encrypt(messageContent.getContent()); + encrypted = true; + } else { + content = messageContent.getContent(); + encrypted = messageContent.isEncrypted(); + } - @Override - public void executeBatchInsertMessageContent(String channelId) { - logger.debug(channelId + ": executing batch message content insert"); + statement.setInt(1, messageContent.getMetaDataId()); + statement.setLong(2, messageContent.getMessageId()); + statement.setInt(3, messageContent.getContentType().getContentTypeCode()); + statement.setString(4, content); + statement.setString(5, messageContent.getDataType()); + statement.setBoolean(6, encrypted); + + statement.addBatch(); + statement.clearParameters(); + } - PreparedStatement statement = null; - try { - /* - * MIRTH-3597 Batch statements need to have their own prepared statement object due to a - * bug? in the Oracle 12 JDBC driver. Therefore we need to have both - * insertMessageContent and insertMessageContentBatch even though they are the same - * query. We should also call clearBatch() after each batch execution to verify that all - * internal buffers are cleared. - */ - statement = prepareStatement("batchInsertMessageContent", channelId); statement.executeBatch(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - clearBatchQuietly(statement); - closeDatabaseObjectIfNeeded(statement); - } - } - - /** - * Empties a cached statement's batch without letting the cleanup itself fail. The statement - * outlives the DAO in the prepared statement cache, so anything left on its batch would be - * executed along with the next message's rows. - */ - private void clearBatchQuietly(Statement statement) { - if (statement != null) { - try { - statement.clearBatch(); - } catch (SQLException e) { - logger.debug("Failed to clear batch", e); - } } } @@ -296,15 +249,13 @@ public void storeMessageContent(MessageContent messageContent) { } private void insertContent(String channelId, long messageId, int metaDataId, ContentType contentType, String content, String dataType, boolean encrypted) { - PreparedStatement statement = null; - try { - // Only encrypt if the content is not already encrypted - if (encryptMessageContent && encryptor != null && !encrypted) { - content = encryptor.encrypt(content); - encrypted = true; - } + // Only encrypt if the content is not already encrypted + if (encryptMessageContent && encryptor != null && !encrypted) { + content = encryptor.encrypt(content); + encrypted = true; + } - statement = prepareStatement("insertMessageContent", channelId); + try (PreparedStatement statement = prepareStatement("insertMessageContent", channelId)) { statement.setInt(1, metaDataId); statement.setLong(2, messageId); statement.setInt(3, contentType.getContentTypeCode()); @@ -316,22 +267,19 @@ private void insertContent(String channelId, long messageId, int metaDataId, Con statement.clearParameters(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } public void storeContent(String channelId, long messageId, int metaDataId, ContentType contentType, String content, String dataType, boolean encrypted) { - PreparedStatement statement = null; - try { - // Only encrypt if the content is not already encrypted - if (encryptMessageContent && encryptor != null && !encrypted) { - content = encryptor.encrypt(content); - encrypted = true; - } + // Only encrypt if the content is not already encrypted + if (encryptMessageContent && encryptor != null && !encrypted) { + content = encryptor.encrypt(content); + encrypted = true; + } - statement = prepareStatement("storeMessageContent", channelId); + int rowCount; + try (PreparedStatement statement = prepareStatement("storeMessageContent", channelId)) { if (content == null) { statement.setNull(1, Types.LONGVARCHAR); } else { @@ -344,29 +292,17 @@ public void storeContent(String channelId, long messageId, int metaDataId, Conte statement.setLong(5, messageId); statement.setInt(6, contentType.getContentTypeCode()); - int rowCount = statement.executeUpdate(); + rowCount = statement.executeUpdate(); statement.clearParameters(); - - if (rowCount == 0) { - // This is the same code as insertContent, without going through the encryption process again - logger.debug(channelId + "/" + messageId + "/" + metaDataId + ": updating message content (" + contentType.toString() + ")"); - - closeDatabaseObjectIfNeeded(statement); - statement = prepareStatement("insertMessageContent", channelId); - statement.setInt(1, metaDataId); - statement.setLong(2, messageId); - statement.setInt(3, contentType.getContentTypeCode()); - statement.setString(4, content); - statement.setString(5, dataType); - statement.setBoolean(6, encrypted); - - statement.executeUpdate(); - statement.clearParameters(); - } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); + } + + if (rowCount == 0) { + logger.debug(channelId + "/" + messageId + "/" + metaDataId + ": updating message content (" + contentType.toString() + ")"); + + // The content is already encrypted, so insertContent() will pass it straight through + insertContent(channelId, messageId, metaDataId, contentType, content, dataType, encrypted); } } @@ -436,31 +372,24 @@ private void updateStatistics(String channelId, Integer metaDataId, Map 0; + } catch (SQLException e) { + throw new DonkeyDaoException(e); + } - if (metaDataId == null) { - statement.setNull(1, Types.INTEGER); - } else { - statement.setInt(1, metaDataId); - } + if (updated) { + return; + } - statement.setString(2, statsServerId); - statement.setLong(3, received); - statement.setLong(4, received); - statement.setLong(5, filtered); - statement.setLong(6, filtered); - statement.setLong(7, sent); - statement.setLong(8, sent); - statement.setLong(9, error); - statement.setLong(10, error); - statement.executeUpdate(); + try (PreparedStatement statement = prepareStatement("insertChannelStatistics", channelId)) { + if (metaDataId == null) { + statement.setNull(1, Types.INTEGER); + } else { + statement.setInt(1, metaDataId); } + + statement.setString(2, statsServerId); + statement.setLong(3, received); + statement.setLong(4, received); + statement.setLong(5, filtered); + statement.setLong(6, filtered); + statement.setLong(7, sent); + statement.setLong(8, sent); + statement.setLong(9, error); + statement.setLong(10, error); + statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -531,17 +463,15 @@ private void updateStatistics(String channelId, Integer metaDataId, Map 0) { - // Determine the segment size. If there are more bytes left than the chunk size, the size is the chunk size. Otherwise it is the number of remaining bytes - int segmentSize = Math.min(chunkSize, inputStream.available()); - // Create a byte array to store the chunk - byte[] segment = new byte[segmentSize]; - // Read the chunk from the input stream to the byte array - inputStream.read(segment, 0, segmentSize); - // Set the segment size - statement.setInt(attachmentSizeIndex, segmentSize); - // Set the byte data - statement.setBytes(contentIndex, segment); - // Perform the update + // Set the segment number + statement.setInt(segmentIdIndex, currentSegmentId); + + if (content.length <= chunkSize) { + // If there is only one segment, just store it + statement.setInt(attachmentSizeIndex, content.length); + statement.setBytes(contentIndex, content); statement.executeUpdate(); currentSegmentId++; - } else { done = true; + } else { + if (inputStream == null) { + inputStream = new ByteArrayInputStream(content); + } + + // As long as there are bytes left + if (inputStream.available() > 0) { + // Determine the segment size. If there are more bytes left than the chunk size, the size is the chunk size. Otherwise it is the number of remaining bytes + int segmentSize = Math.min(chunkSize, inputStream.available()); + // Create a byte array to store the chunk + byte[] segment = new byte[segmentSize]; + // Read the chunk from the input stream to the byte array + inputStream.read(segment, 0, segmentSize); + // Set the segment size + statement.setInt(attachmentSizeIndex, segmentSize); + // Set the byte data + statement.setBytes(contentIndex, segment); + // Perform the update + statement.executeUpdate(); + currentSegmentId++; + } else { + done = true; + } } } - } - // Clear the parameters because the data held in memory could be quite large. - updateStatement.clearParameters(); - insertStatement.clearParameters(); + // Clear the parameters because the data held in memory could be quite large. + updateStatement.clearParameters(); + insertStatement.clearParameters(); + } // Delete lingering segments if (totalSegmentCount >= currentSegmentId) { - PreparedStatement deleteStatement = prepareStatement("deleteMessageAttachmentLingeringSegments", channelId); - deleteStatement.setString(1, attachment.getId()); - deleteStatement.setLong(2, messageId); - deleteStatement.setInt(3, currentSegmentId); - deleteStatement.executeUpdate(); + try (PreparedStatement deleteStatement = prepareStatement("deleteMessageAttachmentLingeringSegments", channelId)) { + deleteStatement.setString(1, attachment.getId()); + deleteStatement.setLong(2, messageId); + deleteStatement.setInt(3, currentSegmentId); + deleteStatement.executeUpdate(); + } } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - List dbObjects = new ArrayList<>(); - dbObjects.add(segmentCountStatement); - dbObjects.add(segmentCountResult); - dbObjects.add(updateStatement); - dbObjects.add(insertStatement); - closeDatabaseObjectsIfNeeded(dbObjects); } } @Override public void insertMetaData(ConnectorMessage connectorMessage, List metaDataColumns) { logger.debug(connectorMessage.getChannelId() + "/" + connectorMessage.getMessageId() + "/" + connectorMessage.getMetaDataId() + ": inserting custom meta data"); - PreparedStatement statement = null; try { List metaDataColumnNames = new ArrayList(); @@ -739,51 +661,49 @@ public void insertMetaData(ConnectorMessage connectorMessage, List metaDataColumns) { logger.debug(connectorMessage.getChannelId() + "/" + connectorMessage.getMessageId() + "/" + connectorMessage.getMetaDataId() + ": updating custom meta data"); - PreparedStatement statement = null; try { List metaDataColumnNames = new ArrayList(); @@ -803,45 +723,44 @@ public void storeMetaData(ConnectorMessage connectorMessage, List values = new HashMap(); values.put("localChannelId", localChannelId); @@ -943,20 +856,13 @@ public void deleteConnectorMessages(String channelId, long messageId, Set getLocalChannelIds() { if (localChannelIds == null) { - ResultSet resultSet = null; - - try { - localChannelIds = new HashMap(); - resultSet = prepareStatement("getLocalChannelIds", null).executeQuery(); + localChannelIds = new HashMap(); + try (PreparedStatement statement = prepareStatement("getLocalChannelIds", null); + ResultSet resultSet = statement.executeQuery()) { while (resultSet.next()) { localChannelIds.put(resultSet.getString(1), resultSet.getLong(2)); } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); } } @@ -1201,47 +1087,35 @@ public void removeChannel(String channelId) { transactionAlteredChannels = true; - List statements = new ArrayList<>(); try { - statements.add(prepareStatement("dropStatisticsTable", channelId)); - statements.add(prepareStatement("dropAttachmentsTable", channelId)); - statements.add(prepareStatement("dropCustomMetadataTable", channelId)); - statements.add(prepareStatement("dropMessageContentTable", channelId)); - statements.add(prepareStatement("dropMessageMetadataTable", channelId)); - statements.add(prepareStatement("dropMessageSequence", channelId)); - statements.add(prepareStatement("dropMessageTable", channelId)); - statements.add(prepareStatement("deleteChannel", channelId)); - - for (AutoCloseable statement : statements) { - ((PreparedStatement) statement).executeUpdate(); + for (String queryId : new String[] { "dropStatisticsTable", "dropAttachmentsTable", + "dropCustomMetadataTable", "dropMessageContentTable", + "dropMessageMetadataTable", "dropMessageSequence", "dropMessageTable", + "deleteChannel" }) { + try (PreparedStatement statement = prepareStatement(queryId, channelId)) { + statement.executeUpdate(); + } } removedChannelIds.add(channelId); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectsIfNeeded(statements); } } @Override public Long selectMaxLocalChannelId() { - ResultSet resultSet = null; - - try { + try (PreparedStatement statement = prepareStatement("selectMaxLocalChannelId", null); + ResultSet resultSet = statement.executeQuery()) { Long maxLocalChannelId = 0L; - resultSet = prepareStatement("selectMaxLocalChannelId", null).executeQuery(); if (resultSet.next()) { maxLocalChannelId = resultSet.getLong(1); } - resultSet.close(); return maxLocalChannelId; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); } } @@ -1249,74 +1123,37 @@ public Long selectMaxLocalChannelId() { public void deleteAllMessages(String channelId) { logger.debug(channelId + ": deleting all messages"); - List statements = new ArrayList<>(); try { // delete tables without constraints cascadeMessageDelete("deleteAllMessagesCascadeAttachments", channelId); cascadeMessageDelete("deleteAllMessagesCascadeMetadata", channelId); cascadeMessageDelete("deleteAllMessagesCascadeContent", channelId); - PreparedStatement statement = null; // remove constraints so truncate can execute - if (querySource.queryExists("dropConstraintMessageContentTable")) { - statement = prepareStatement("dropConstraintMessageContentTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } - if (querySource.queryExists("dropConstraintMessageCustomMetaDataTable")) { - statement = prepareStatement("dropConstraintMessageCustomMetaDataTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } + executeUpdateIfDefined("dropConstraintMessageContentTable", channelId); + executeUpdateIfDefined("dropConstraintMessageCustomMetaDataTable", channelId); // delete cascadeMessageDelete("deleteAllMessagesCascadeConnectorMessage", channelId); // re-add constraints - if (querySource.queryExists("addConstraintMessageCustomMetaDataTable")) { - statement = prepareStatement("addConstraintMessageCustomMetaDataTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } - if (querySource.queryExists("addConstraintMessageContentTable")) { - statement = prepareStatement("addConstraintMessageContentTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } + executeUpdateIfDefined("addConstraintMessageCustomMetaDataTable", channelId); + executeUpdateIfDefined("addConstraintMessageContentTable", channelId); // remove constraints so truncate can execute - if (querySource.queryExists("dropConstraintConnectorMessageTable")) { - statement = prepareStatement("dropConstraintConnectorMessageTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } - if (querySource.queryExists("dropConstraintAttachmentTable")) { - statement = prepareStatement("dropConstraintAttachmentTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } + executeUpdateIfDefined("dropConstraintConnectorMessageTable", channelId); + executeUpdateIfDefined("dropConstraintAttachmentTable", channelId); // delete - statement = prepareStatement("deleteAllMessages", channelId); - statements.add(statement); - statement.executeUpdate(); - - // re-add constraints - if (querySource.queryExists("addConstraintAttachmentTable")) { - statement = prepareStatement("addConstraintAttachmentTable", channelId); - statements.add(statement); - statement.executeUpdate(); - } - if (querySource.queryExists("addConstraintConnectorMessageTable")) { - statement = prepareStatement("addConstraintConnectorMessageTable", channelId); - statements.add(statement); + try (PreparedStatement statement = prepareStatement("deleteAllMessages", channelId)) { statement.executeUpdate(); } + // re-add constraints + executeUpdateIfDefined("addConstraintAttachmentTable", channelId); + executeUpdateIfDefined("addConstraintConnectorMessageTable", channelId); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectsIfNeeded(statements); } } @@ -1324,15 +1161,11 @@ public void deleteAllMessages(String channelId) { public void deleteMessageContent(String channelId, long messageId) { logger.debug(channelId + "/" + messageId + ": deleting content"); - PreparedStatement statement = null; - try { - statement = prepareStatement("deleteMessageContent", channelId); + try (PreparedStatement statement = prepareStatement("deleteMessageContent", channelId)) { statement.setLong(1, messageId); statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -1340,36 +1173,28 @@ public void deleteMessageContent(String channelId, long messageId) { public void deleteMessageContentByMetaDataIds(String channelId, long messageId, Set metaDataIds) { logger.debug(channelId + "/" + messageId + ": deleting content by metadata IDs: " + String.valueOf(metaDataIds)); - PreparedStatement statement = null; - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - values.put("metaDataIds", StringUtils.join(metaDataIds, ',')); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); + values.put("metaDataIds", StringUtils.join(metaDataIds, ',')); - statement = getConnection().prepareStatement(querySource.getQuery("deleteMessageContentByMetaDataIds", values)); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("deleteMessageContentByMetaDataIds", values))) { statement.setLong(1, messageId); statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } private void deleteMessageContentByMetaDataIdAndContentType(String channelId, long messageId, int metaDataId, ContentType contentType) { logger.debug(channelId + "/" + messageId + ": deleting content"); - PreparedStatement statement = null; - try { - statement = prepareStatement("deleteMessageContentByMetaDataIdAndContentType", channelId); + try (PreparedStatement statement = prepareStatement("deleteMessageContentByMetaDataIdAndContentType", channelId)) { statement.setLong(1, messageId); statement.setInt(2, metaDataId); statement.setInt(3, contentType.getContentTypeCode()); statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -1377,71 +1202,61 @@ private void deleteMessageContentByMetaDataIdAndContentType(String channelId, lo public void deleteMessageAttachments(String channelId, long messageId) { logger.debug(channelId + "/" + messageId + ": deleting attachments"); - PreparedStatement statement = null; - try { - statement = prepareStatement("deleteMessageAttachments", channelId); + try (PreparedStatement statement = prepareStatement("deleteMessageAttachments", channelId)) { statement.setLong(1, messageId); statement.executeUpdate(); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - closeDatabaseObjectIfNeeded(statement); } } @Override public List getMetaDataColumns(String channelId) { - ResultSet columns = null; - try { List metaDataColumns = new ArrayList(); long localChannelId = getLocalChannelId(channelId); - columns = connection.getMetaData().getColumns(connection.getCatalog(), null, "d_mcm" + localChannelId, null); + // Databases disagree on identifier case folding, so try both spellings + for (String tableName : new String[] { "d_mcm" + localChannelId, + "D_MCM" + localChannelId }) { + try (ResultSet columns = connection.getMetaData().getColumns(connection.getCatalog(), null, tableName, null)) { + if (!columns.next()) { + continue; + } - if (!columns.next()) { - columns.close(); - columns = connection.getMetaData().getColumns(connection.getCatalog(), null, "D_MCM" + localChannelId, null); + do { + String name = columns.getString("COLUMN_NAME"); - if (!columns.next()) { - return metaDataColumns; - } - } - - do { - String name = columns.getString("COLUMN_NAME"); + if (!name.equalsIgnoreCase("METADATA_ID") && !name.equalsIgnoreCase("MESSAGE_ID")) { + MetaDataColumnType columnType = MetaDataColumnType.fromSqlType(columns.getInt("DATA_TYPE")); - if (!name.equalsIgnoreCase("METADATA_ID") && !name.equalsIgnoreCase("MESSAGE_ID")) { - MetaDataColumnType columnType = MetaDataColumnType.fromSqlType(columns.getInt("DATA_TYPE")); + if (columnType == null) { + logger.error("Invalid custom metadata column: " + name + " (type: " + sqlTypeToString(columns.getInt("DATA_TYPE")) + ")."); + } else { + metaDataColumns.add(new MetaDataColumn(name, columnType, null)); + } + } + } while (columns.next()); - if (columnType == null) { - logger.error("Invalid custom metadata column: " + name + " (type: " + sqlTypeToString(columns.getInt("DATA_TYPE")) + ")."); - } else { - metaDataColumns.add(new MetaDataColumn(name, columnType, null)); - } + return metaDataColumns; } - } while (columns.next()); + } return metaDataColumns; } catch (Exception e) { throw new DonkeyDaoException("Failed to retrieve meta data columns", e); - } finally { - close(columns); } } @Override public void removeMetaDataColumn(String channelId, String columnName) { logger.debug(channelId + "/" + ": removing custom meta data column (" + columnName + ")"); - Statement statement = null; - - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - values.put("columnName", columnName); - statement = connection.createStatement(); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); + values.put("columnName", columnName); + try (Statement statement = connection.createStatement()) { if (querySource.queryExists("removeMetaDataColumnIndex")) { statement.executeUpdate(querySource.getQuery("removeMetaDataColumnIndex", values)); } @@ -1449,64 +1264,45 @@ public void removeMetaDataColumn(String channelId, String columnName) { statement.executeUpdate(querySource.getQuery("removeMetaDataColumn", values)); } catch (SQLException e) { throw new DonkeyDaoException("Failed to remove meta-data column", e); - } finally { - close(statement); } } @Override public long getMaxMessageId(String channelId) { - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - statement = prepareStatement("getMaxMessageId", channelId); - resultSet = statement.executeQuery(); + try (PreparedStatement statement = prepareStatement("getMaxMessageId", channelId); + ResultSet resultSet = statement.executeQuery()) { return (resultSet.next()) ? resultSet.getLong(1) : null; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public long getMinMessageId(String channelId) { - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - statement = prepareStatement("getMinMessageId", channelId); - resultSet = statement.executeQuery(); + try (PreparedStatement statement = prepareStatement("getMinMessageId", channelId); + ResultSet resultSet = statement.executeQuery()) { return (resultSet.next()) ? resultSet.getLong(1) : null; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public long getNextMessageId(String channelId) { - Statement statement = null; - ResultSet resultSet = null; - - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - - statement = connection.createStatement(); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); + try (Statement statement = connection.createStatement()) { if (querySource.queryExists("lockMessageSequenceTable")) { statement.executeUpdate(querySource.getQuery("lockMessageSequenceTable", values)); } - resultSet = statement.executeQuery(querySource.getQuery("getNextMessageId", values)); - resultSet.next(); - long id = resultSet.getLong(1); - close(resultSet); + long id; + + try (ResultSet resultSet = statement.executeQuery(querySource.getQuery("getNextMessageId", values))) { + resultSet.next(); + id = resultSet.getLong(1); + } if (querySource.queryExists("incrementMessageIdSequence")) { statement.executeUpdate(querySource.getQuery("incrementMessageIdSequence", values)); @@ -1515,194 +1311,182 @@ public long getNextMessageId(String channelId) { return id; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @Override public List getMessageAttachment(String channelId, long messageId) { - ResultSet resultSet = null; - PreparedStatement statement = null; - try { + Map attachmentSize = new HashMap(); + // Get the total size of each attachment by summing the sizes of its segments - statement = prepareStatement("selectMessageAttachmentSizeByMessageId", channelId); - statement.setLong(1, messageId); - resultSet = statement.executeQuery(); + try (PreparedStatement statement = prepareStatement("selectMessageAttachmentSizeByMessageId", channelId)) { + statement.setLong(1, messageId); - Map attachmentSize = new HashMap(); - while (resultSet.next()) { - // Store the attachment size in a map with the attachment id as the key - attachmentSize.put(resultSet.getString("id"), resultSet.getInt("attachment_size")); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + // Store the attachment size in a map with the attachment id as the key + attachmentSize.put(resultSet.getString("id"), resultSet.getInt("attachment_size")); + } + } } - close(resultSet); - closeDatabaseObjectIfNeeded(statement); - // Get the attachment data - statement = prepareStatement("selectMessageAttachmentByMessageId", channelId); - statement.setLong(1, messageId); - // Set the number of rows to be fetched into memory at a time. This limits the amount of memory required for the query. - statement.setFetchSize(1); - resultSet = statement.executeQuery(); - - // Initialize the return object - List attachments = new ArrayList(); - // The current attachment id that is being stitched together - String currentAttachmentId = null; - // The type of the current attachment - String type = null; - // Encryption header, if encrypted - String encryptionHeader = null; - // Use an byte array to combine the segments - byte[] content = null; - int offset = 0; + try (PreparedStatement statement = prepareStatement("selectMessageAttachmentByMessageId", channelId)) { + statement.setLong(1, messageId); + // Set the number of rows to be fetched into memory at a time. This limits the amount of memory required for the query. + statement.setFetchSize(1); + + try (ResultSet resultSet = statement.executeQuery()) { + // Initialize the return object + List attachments = new ArrayList(); + // The current attachment id that is being stitched together + String currentAttachmentId = null; + // The type of the current attachment + String type = null; + // Encryption header, if encrypted + String encryptionHeader = null; + // Use an byte array to combine the segments + byte[] content = null; + int offset = 0; + + while (resultSet.next()) { + // Get the attachment id of the current segment + String attachmentId = resultSet.getString("id"); + + // Ensure that the attachmentId is in the map we created earlier, otherwise don't return this attachment + if (attachmentSize.containsKey(attachmentId)) { + // If starting a new attachment + if (!attachmentId.equals(currentAttachmentId)) { + // If there was a previous attachment, we need to finish it. + if (content != null) { + // Add the data in the output stream to the list of attachments to return + if (decryptData && encryptor != null && encryptionHeader != null) { + content = encryptor.decrypt(encryptionHeader, content); + attachments.add(new Attachment(currentAttachmentId, content, type)); + } else { + attachments.add(new Attachment(currentAttachmentId, content, type, encryptionHeader)); + } + } + currentAttachmentId = attachmentId; + type = resultSet.getString("type"); + encryptionHeader = resultSet.getString("encryption_header"); + + // Initialize the byte array size to the exact size of the attachment. This should minimize the memory requirements if the numbers are correct. + // Use 0 as a backup in case the size is not in the map. (If trying to return an attachment that no longer exists) + content = new byte[attachmentSize.get(attachmentId)]; + offset = 0; + } - while (resultSet.next()) { - // Get the attachment id of the current segment - String attachmentId = resultSet.getString("id"); - - // Ensure that the attachmentId is in the map we created earlier, otherwise don't return this attachment - if (attachmentSize.containsKey(attachmentId)) { - // If starting a new attachment - if (!attachmentId.equals(currentAttachmentId)) { - // If there was a previous attachment, we need to finish it. - if (content != null) { - // Add the data in the output stream to the list of attachments to return - if (decryptData && encryptor != null && encryptionHeader != null) { - content = encryptor.decrypt(encryptionHeader, content); - attachments.add(new Attachment(currentAttachmentId, content, type)); - } else { - attachments.add(new Attachment(currentAttachmentId, content, type, encryptionHeader)); + // write the current segment to the output stream buffer + byte[] segment = resultSet.getBytes("content"); + + if (segment != null) { + System.arraycopy(segment, 0, content, offset, segment.length); + + offset += segment.length; } } - currentAttachmentId = attachmentId; - type = resultSet.getString("type"); - encryptionHeader = resultSet.getString("encryption_header"); - - // Initialize the byte array size to the exact size of the attachment. This should minimize the memory requirements if the numbers are correct. - // Use 0 as a backup in case the size is not in the map. (If trying to return an attachment that no longer exists) - content = new byte[attachmentSize.get(attachmentId)]; - offset = 0; } - // write the current segment to the output stream buffer - byte[] segment = resultSet.getBytes("content"); - - if (segment != null) { - System.arraycopy(segment, 0, content, offset, segment.length); - - offset += segment.length; + // Finish the message if one exists by adding it to the list of attachments to return + if (content != null) { + if (decryptData && encryptor != null && encryptionHeader != null) { + content = encryptor.decrypt(encryptionHeader, content); + attachments.add(new Attachment(currentAttachmentId, content, type)); + } else { + attachments.add(new Attachment(currentAttachmentId, content, type, encryptionHeader)); + } } - } - } + content = null; - // Finish the message if one exists by adding it to the list of attachments to return - if (content != null) { - if (decryptData && encryptor != null && encryptionHeader != null) { - content = encryptor.decrypt(encryptionHeader, content); - attachments.add(new Attachment(currentAttachmentId, content, type)); - } else { - attachments.add(new Attachment(currentAttachmentId, content, type, encryptionHeader)); + return attachments; } } - content = null; - - return attachments; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public Attachment getMessageAttachment(String channelId, String attachmentId, Long messageId) { - ResultSet resultSet = null; Attachment attachment = new Attachment(); - PreparedStatement statement = null; + try { + int size = 0; + // Get the total size of each attachment by summing the sizes of its segments - statement = prepareStatement("selectMessageAttachmentSize", channelId); - statement.setString(1, attachmentId); - statement.setLong(2, messageId); - resultSet = statement.executeQuery(); + try (PreparedStatement statement = prepareStatement("selectMessageAttachmentSize", channelId)) { + statement.setString(1, attachmentId); + statement.setLong(2, messageId); - int size = 0; - if (resultSet.next()) { - // Store the attachment size in a map with the attachment id as the key - size = resultSet.getInt("attachment_size"); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + // Store the attachment size in a map with the attachment id as the key + size = resultSet.getInt("attachment_size"); + } + } } - close(resultSet); - closeDatabaseObjectIfNeeded(statement); - // Get the attachment data - statement = prepareStatement("selectMessageAttachment", channelId); - statement.setString(1, attachmentId); - statement.setLong(2, messageId); - // Set the number of rows to be fetched into memory at a time. This limits the amount of memory required for the query. - statement.setFetchSize(1); - resultSet = statement.executeQuery(); + try (PreparedStatement statement = prepareStatement("selectMessageAttachment", channelId)) { + statement.setString(1, attachmentId); + statement.setLong(2, messageId); + // Set the number of rows to be fetched into memory at a time. This limits the amount of memory required for the query. + statement.setFetchSize(1); - // The type of the current attachment - String type = null; + try (ResultSet resultSet = statement.executeQuery()) { + // The type of the current attachment + String type = null; - // Encryption header, if encrypted - String encryptionHeader = null; + // Encryption header, if encrypted + String encryptionHeader = null; - // Initialize the output stream's buffer size to the exact size of the attachment. This should minimize the memory requirements if the numbers are correct. - byte[] content = null; - int offset = 0; + // Initialize the output stream's buffer size to the exact size of the attachment. This should minimize the memory requirements if the numbers are correct. + byte[] content = null; + int offset = 0; - while (resultSet.next()) { - if (content == null) { - type = resultSet.getString("type"); - encryptionHeader = resultSet.getString("encryption_header"); - content = new byte[size]; - } + while (resultSet.next()) { + if (content == null) { + type = resultSet.getString("type"); + encryptionHeader = resultSet.getString("encryption_header"); + content = new byte[size]; + } - // write the current segment to the output stream buffer - byte[] segment = resultSet.getBytes("content"); + // write the current segment to the output stream buffer + byte[] segment = resultSet.getBytes("content"); - if (segment != null) { - System.arraycopy(segment, 0, content, offset, segment.length); + if (segment != null) { + System.arraycopy(segment, 0, content, offset, segment.length); - offset += segment.length; - } - } + offset += segment.length; + } + } - // Finish the message if one exists by adding it to the list of attachments to return - if (content != null) { - attachment.setId(attachmentId); - attachment.setType(type); - if (decryptData && encryptor != null && encryptionHeader != null) { - content = encryptor.decrypt(encryptionHeader, content); - } else { - attachment.setEncryptionHeader(encryptionHeader); - attachment.setEncrypted(true); + // Finish the message if one exists by adding it to the list of attachments to return + if (content != null) { + attachment.setId(attachmentId); + attachment.setType(type); + if (decryptData && encryptor != null && encryptionHeader != null) { + content = encryptor.decrypt(encryptionHeader, content); + } else { + attachment.setEncryptionHeader(encryptionHeader); + attachment.setEncrypted(true); + } + attachment.setContent(content); + } + content = null; + + return attachment; } - attachment.setContent(content); } - content = null; - - return attachment; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public List getUnfinishedMessages(String channelId, String serverId, int limit, Long minMessageId) { - PreparedStatement statement = null; - ResultSet resultSet = null; - try { Map messageMap = new HashMap(); List messageList = new ArrayList(); @@ -1712,49 +1496,42 @@ public List getUnfinishedMessages(String channelId, String serverId, in params.put("localChannelId", getLocalChannelId(channelId)); params.put("limit", limit); - statement = connection.prepareStatement(querySource.getQuery("getUnfinishedMessages", params)); - statement.setLong(1, minMessageId); - statement.setString(2, serverId); - resultSet = statement.executeQuery(); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getUnfinishedMessages", params))) { + statement.setLong(1, minMessageId); + statement.setString(2, serverId); - while (resultSet.next()) { - Message message = getMessageFromResultSet(channelId, resultSet); - messageMap.put(message.getMessageId(), message); - messageList.add(message); - messageIds.add(message.getMessageId()); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + Message message = getMessageFromResultSet(channelId, resultSet); + messageMap.put(message.getMessageId(), message); + messageList.add(message); + messageIds.add(message.getMessageId()); + } + } } - close(resultSet); - close(statement); - if (!messageIds.isEmpty()) { params = new HashMap(); params.put("localChannelId", getLocalChannelId(channelId)); params.put("messageIds", StringUtils.join(messageIds, ",")); - statement = connection.prepareStatement(querySource.getQuery("getConnectorMessagesByMessageIds", params)); - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, true, true); - messageMap.get(connectorMessage.getMessageId()).getConnectorMessages().put(connectorMessage.getMetaDataId(), connectorMessage); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getConnectorMessagesByMessageIds", params)); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, true, true); + messageMap.get(connectorMessage.getMessageId()).getConnectorMessages().put(connectorMessage.getMetaDataId(), connectorMessage); + } } } return messageList; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @Override public List getPendingConnectorMessages(String channelId, String serverId, int limit, Long minMessageId) { - PreparedStatement statement = null; - ResultSet resultSet = null; - try { Map messageMap = new HashMap(); List messageList = new ArrayList(); @@ -1764,45 +1541,41 @@ public List getPendingConnectorMessages(String channelId, String server params.put("localChannelId", getLocalChannelId(channelId)); params.put("limit", limit); - statement = connection.prepareStatement(querySource.getQuery("getPendingMessageIds", params)); - statement.setLong(1, minMessageId); - statement.setString(2, serverId); - - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - Message message = new Message(); - message.setMessageId(resultSet.getLong(1)); - messageMap.put(message.getMessageId(), message); - messageList.add(message); - messageIds.add(message.getMessageId()); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getPendingMessageIds", params))) { + statement.setLong(1, minMessageId); + statement.setString(2, serverId); + + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + Message message = new Message(); + message.setMessageId(resultSet.getLong(1)); + messageMap.put(message.getMessageId(), message); + messageList.add(message); + messageIds.add(message.getMessageId()); + } + } } - close(resultSet); - close(statement); - if (!messageIds.isEmpty()) { params = new HashMap(); params.put("localChannelId", getLocalChannelId(channelId)); params.put("messageIds", StringUtils.join(messageIds, ",")); - statement = connection.prepareStatement(querySource.getQuery("getPendingConnectorMessages", params)); - statement.setString(1, serverId); - - resultSet = statement.executeQuery(); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getPendingConnectorMessages", params))) { + statement.setString(1, serverId); - while (resultSet.next()) { - ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, true, true); - messageMap.get(connectorMessage.getMessageId()).getConnectorMessages().put(connectorMessage.getMetaDataId(), connectorMessage); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, true, true); + messageMap.get(connectorMessage.getMessageId()).getConnectorMessages().put(connectorMessage.getMetaDataId(), connectorMessage); + } + } } } return messageList; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @@ -1812,8 +1585,6 @@ public List getMessages(String channelId, List messageIds) { throw new DonkeyDaoException("Only up to 1000 message Ids at a time are supported."); } - PreparedStatement statement = null; - ResultSet resultSet = null; Map messageMap = new LinkedHashMap(); try { @@ -1821,19 +1592,16 @@ public List getMessages(String channelId, List messageIds) { params.put("localChannelId", getLocalChannelId(channelId)); params.put("messageIds", StringUtils.join(messageIds, ",")); - statement = connection.prepareStatement(querySource.getQuery("getMessagesByMessageIds", params)); - resultSet = statement.executeQuery(); - - // Get all message objects in the list and store them so they are accessible by message Id - while (resultSet.next()) { - Message message = getMessageFromResultSet(channelId, resultSet); - messageMap.put(message.getMessageId(), message); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getMessagesByMessageIds", params)); + ResultSet resultSet = statement.executeQuery()) { + // Get all message objects in the list and store them so they are accessible by message Id + while (resultSet.next()) { + Message message = getMessageFromResultSet(channelId, resultSet); + messageMap.put(message.getMessageId(), message); + } } if (!messageIds.isEmpty()) { - close(resultSet); - close(statement); - // Cache all message content for all messages in the list Map>> messageContentMap = getMessageContent(channelId, messageIds); // Cache all metadata maps for all messages in the list @@ -1844,52 +1612,52 @@ public List getMessages(String channelId, List messageIds) { params.put("messageIds", StringUtils.join(messageIds, ",")); // Perform a single query to retrieve all connector messages in the list at once - statement = connection.prepareStatement(querySource.getQuery("getConnectorMessagesByMessageIds", params)); - resultSet = statement.executeQuery(); - - ConnectorMessage sourceConnectorMessage = null; - long currentMessageId = 0; - while (resultSet.next()) { - // Create the connector from the result set without content or metadata map - ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, false, false); - // Store the reference to the connector in the message - messageMap.get(connectorMessage.getMessageId()).getConnectorMessages().put(connectorMessage.getMetaDataId(), connectorMessage); - - // Whenever we start a new message, null the sourceConnectorMessage. This is in case the message has no source connector so we don't use the previous message's source - if (currentMessageId != connectorMessage.getMessageId()) { - currentMessageId = connectorMessage.getMessageId(); - sourceConnectorMessage = null; - } + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getConnectorMessagesByMessageIds", params)); + ResultSet resultSet = statement.executeQuery()) { + ConnectorMessage sourceConnectorMessage = null; + long currentMessageId = 0; + while (resultSet.next()) { + // Create the connector from the result set without content or metadata map + ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, false, false); + // Store the reference to the connector in the message + messageMap.get(connectorMessage.getMessageId()).getConnectorMessages().put(connectorMessage.getMetaDataId(), connectorMessage); + + // Whenever we start a new message, null the sourceConnectorMessage. This is in case the message has no source connector so we don't use the previous message's source + if (currentMessageId != connectorMessage.getMessageId()) { + currentMessageId = connectorMessage.getMessageId(); + sourceConnectorMessage = null; + } - if (connectorMessage.getMetaDataId() == 0) { - // Store a reference to a message's source connector - sourceConnectorMessage = connectorMessage; - } else if (sourceConnectorMessage != null) { - // Load the destination's raw content and source map from the source - connectorMessage.setSourceMap(sourceConnectorMessage.getSourceMap()); - MessageContent sourceEncoded = sourceConnectorMessage.getEncoded(); - if (sourceEncoded != null) { - // If the source encoded exists, set it as the destination raw - MessageContent destinationRaw = new MessageContent(channelId, sourceEncoded.getMessageId(), connectorMessage.getMetaDataId(), ContentType.RAW, sourceEncoded.getContent(), sourceEncoded.getDataType(), sourceEncoded.isEncrypted()); - connectorMessage.setRaw(destinationRaw); + if (connectorMessage.getMetaDataId() == 0) { + // Store a reference to a message's source connector + sourceConnectorMessage = connectorMessage; + } else if (sourceConnectorMessage != null) { + // Load the destination's raw content and source map from the source + connectorMessage.setSourceMap(sourceConnectorMessage.getSourceMap()); + MessageContent sourceEncoded = sourceConnectorMessage.getEncoded(); + if (sourceEncoded != null) { + // If the source encoded exists, set it as the destination raw + MessageContent destinationRaw = new MessageContent(channelId, sourceEncoded.getMessageId(), connectorMessage.getMetaDataId(), ContentType.RAW, sourceEncoded.getContent(), sourceEncoded.getDataType(), sourceEncoded.isEncrypted()); + connectorMessage.setRaw(destinationRaw); + } } - } - // Get this connector's message content from the cache and store it in the connector - Map> connectorMessageContentMap = messageContentMap.get(connectorMessage.getMessageId()); - if (connectorMessageContentMap != null) { - List messageContents = connectorMessageContentMap.get(connectorMessage.getMetaDataId()); - if (messageContents != null) { - loadMessageContent(connectorMessage, messageContents); + // Get this connector's message content from the cache and store it in the connector + Map> connectorMessageContentMap = messageContentMap.get(connectorMessage.getMessageId()); + if (connectorMessageContentMap != null) { + List messageContents = connectorMessageContentMap.get(connectorMessage.getMetaDataId()); + if (messageContents != null) { + loadMessageContent(connectorMessage, messageContents); + } } - } - // Get this connector's metadata map from the cache and store it in the connector - Map> connectorMetaDataMap = metaDataMaps.get(connectorMessage.getMessageId()); - if (connectorMetaDataMap != null) { - Map metaDataMap = connectorMetaDataMap.get(connectorMessage.getMetaDataId()); - if (metaDataMap != null) { - connectorMessage.setMetaDataMap(metaDataMap); + // Get this connector's metadata map from the cache and store it in the connector + Map> connectorMetaDataMap = metaDataMaps.get(connectorMessage.getMessageId()); + if (connectorMetaDataMap != null) { + Map metaDataMap = connectorMetaDataMap.get(connectorMessage.getMetaDataId()); + if (metaDataMap != null) { + connectorMessage.setMetaDataMap(metaDataMap); + } } } } @@ -1898,9 +1666,6 @@ public List getMessages(String channelId, List messageIds) { return new ArrayList(messageMap.values()); } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @@ -1912,159 +1677,132 @@ public List getConnectorMessages(String channelId, String serv return connectorMessages; } - PreparedStatement statement = null; - ResultSet resultSet = null; + Map params = new HashMap(); + params.put("localChannelId", getLocalChannelId(channelId)); + params.put("offset", offset); + params.put("limit", limit); - try { - Map params = new HashMap(); - params.put("localChannelId", getLocalChannelId(channelId)); - params.put("offset", offset); - params.put("limit", limit); + boolean withRange = minMessageId != null && maxMessageId != null; + String queryId; + + if (withRange) { + queryId = serverId != null ? "getConnectorMessagesByMetaDataIdAndStatusWithLimitAndRange" : "getConnectorMessagesByMetaDataIdAndStatusWithLimitAndRangeAllServers"; + } else { + queryId = serverId != null ? "getConnectorMessagesByMetaDataIdAndStatusWithLimit" : "getConnectorMessagesByMetaDataIdAndStatusWithLimitAllServers"; + } + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery(queryId, params))) { int index = 1; + statement.setInt(index++, metaDataId); + statement.setString(index++, Character.toString(status.getStatusCode())); - if (minMessageId == null || maxMessageId == null) { - statement = connection.prepareStatement(querySource.getQuery(serverId != null ? "getConnectorMessagesByMetaDataIdAndStatusWithLimit" : "getConnectorMessagesByMetaDataIdAndStatusWithLimitAllServers", params)); - statement.setInt(index++, metaDataId); - statement.setString(index++, Character.toString(status.getStatusCode())); - if (serverId != null) { - statement.setString(index++, serverId); - } - } else { - statement = connection.prepareStatement(querySource.getQuery(serverId != null ? "getConnectorMessagesByMetaDataIdAndStatusWithLimitAndRange" : "getConnectorMessagesByMetaDataIdAndStatusWithLimitAndRangeAllServers", params)); - statement.setInt(index++, metaDataId); - statement.setString(index++, Character.toString(status.getStatusCode())); - if (serverId != null) { - statement.setString(index++, serverId); - } + if (serverId != null) { + statement.setString(index++, serverId); + } + + if (withRange) { statement.setLong(index++, minMessageId); statement.setLong(index++, maxMessageId); } - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - connectorMessages.add(getConnectorMessageFromResultSet(channelId, resultSet, true, true)); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + connectorMessages.add(getConnectorMessageFromResultSet(channelId, resultSet, true, true)); + } } return connectorMessages; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @Override public List getConnectorMessages(String channelId, long messageId, Set metaDataIds, boolean includeContent) { - PreparedStatement statement = null; - ResultSet resultSet = null; - - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - values.put("metaDataIds", StringUtils.join(metaDataIds, ',')); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); + values.put("metaDataIds", StringUtils.join(metaDataIds, ',')); - statement = connection.prepareStatement(querySource.getQuery("getConnectorMessagesByMessageIdAndMetaDataIds", values)); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getConnectorMessagesByMessageIdAndMetaDataIds", values))) { statement.setLong(1, messageId); - resultSet = statement.executeQuery(); - List connectorMessages = new ArrayList(); + try (ResultSet resultSet = statement.executeQuery()) { + List connectorMessages = new ArrayList(); - while (resultSet.next()) { - connectorMessages.add(getConnectorMessageFromResultSet(channelId, resultSet, includeContent, true)); - } + while (resultSet.next()) { + connectorMessages.add(getConnectorMessageFromResultSet(channelId, resultSet, includeContent, true)); + } - return connectorMessages; + return connectorMessages; + } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @Override public Map getConnectorMessages(String channelId, long messageId, List metaDataIds) { - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - boolean includeMetaDataIds = CollectionUtils.isNotEmpty(metaDataIds); - Map params = new HashMap(); - params.put("localChannelId", getLocalChannelId(channelId)); + boolean includeMetaDataIds = CollectionUtils.isNotEmpty(metaDataIds); + Map params = new HashMap(); + params.put("localChannelId", getLocalChannelId(channelId)); - if (includeMetaDataIds) { - params.put("metaDataIds", StringUtils.join(metaDataIds, ',')); - } + if (includeMetaDataIds) { + params.put("metaDataIds", StringUtils.join(metaDataIds, ',')); + } - statement = getConnection().prepareStatement(querySource.getQuery(includeMetaDataIds ? "getConnectorMessagesByMessageIdAndMetaDataIds" : "getConnectorMessagesByMessageId", params)); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery(includeMetaDataIds ? "getConnectorMessagesByMessageIdAndMetaDataIds" : "getConnectorMessagesByMessageId", params))) { statement.setLong(1, messageId); - resultSet = statement.executeQuery(); - Map connectorMessages = new HashMap(); + try (ResultSet resultSet = statement.executeQuery()) { + Map connectorMessages = new HashMap(); - while (resultSet.next()) { - ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, true, true); - connectorMessages.put(connectorMessage.getMetaDataId(), connectorMessage); - } + while (resultSet.next()) { + ConnectorMessage connectorMessage = getConnectorMessageFromResultSet(channelId, resultSet, true, true); + connectorMessages.put(connectorMessage.getMetaDataId(), connectorMessage); + } - return connectorMessages; + return connectorMessages; + } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public Map getConnectorMessageStatuses(String channelId, long messageId, boolean checkProcessed) { - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - statement = prepareStatement(checkProcessed ? "getConnectorMessageStatusesCheckProcessed" : "getConnectorMessageStatuses", channelId); + try (PreparedStatement statement = prepareStatement(checkProcessed ? "getConnectorMessageStatusesCheckProcessed" : "getConnectorMessageStatuses", channelId)) { statement.setLong(1, messageId); - resultSet = statement.executeQuery(); - Map statusMap = new HashMap(); + try (ResultSet resultSet = statement.executeQuery()) { + Map statusMap = new HashMap(); - while (resultSet.next()) { - statusMap.put(resultSet.getInt(1), Status.fromChar(resultSet.getString(2).charAt(0))); - } + while (resultSet.next()) { + statusMap.put(resultSet.getInt(1), Status.fromChar(resultSet.getString(2).charAt(0))); + } - return statusMap; + return statusMap; + } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public int getConnectorMessageCount(String channelId, String serverId, int metaDataId, Status status) { if (donkey.getDeployedChannels().get(channelId) != null || getLocalChannelIds().get(channelId) != null) { - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - statement = statementSource.getPreparedStatement(serverId != null ? "getConnectorMessageCountByMetaDataIdAndStatus" : "getConnectorMessageCountByMetaDataIdAndStatusAllServers", getLocalChannelId(channelId)); + try (PreparedStatement statement = prepareStatement(serverId != null ? "getConnectorMessageCountByMetaDataIdAndStatus" : "getConnectorMessageCountByMetaDataIdAndStatusAllServers", channelId)) { statement.setInt(1, metaDataId); statement.setString(2, Character.toString(status.getStatusCode())); if (serverId != null) { statement.setString(3, serverId); } - resultSet = statement.executeQuery(); - resultSet.next(); - return resultSet.getInt(1); + + try (ResultSet resultSet = statement.executeQuery()) { + resultSet.next(); + return resultSet.getInt(1); + } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } else { // the channel has never been deployed @@ -2074,40 +1812,33 @@ public int getConnectorMessageCount(String channelId, String serverId, int metaD @Override public long getConnectorMessageMaxMessageId(String channelId, String serverId, int metaDataId, Status status) { - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - statement = prepareStatement(serverId != null ? "getConnectorMessageMaxMessageIdByMetaDataIdAndStatus" : "getConnectorMessageMaxMessageIdByMetaDataIdAndStatusAllServers", channelId); + try (PreparedStatement statement = prepareStatement(serverId != null ? "getConnectorMessageMaxMessageIdByMetaDataIdAndStatus" : "getConnectorMessageMaxMessageIdByMetaDataIdAndStatusAllServers", channelId)) { statement.setInt(1, metaDataId); statement.setString(2, Character.toString(status.getStatusCode())); if (serverId != null) { statement.setString(3, serverId); } - resultSet = statement.executeQuery(); - resultSet.next(); - return resultSet.getLong(1); + + try (ResultSet resultSet = statement.executeQuery()) { + resultSet.next(); + return resultSet.getLong(1); + } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @Override public void addMetaDataColumn(String channelId, MetaDataColumn metaDataColumn) { logger.debug(channelId + ": adding custom meta data column (" + metaDataColumn.getName() + ")"); - Statement statement = null; - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - values.put("columnName", metaDataColumn.getName()); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); + values.put("columnName", metaDataColumn.getName()); - String queryName = "addMetaDataColumn" + StringUtils.capitalize(StringUtils.lowerCase(metaDataColumn.getType().toString())); + String queryName = "addMetaDataColumn" + StringUtils.capitalize(StringUtils.lowerCase(metaDataColumn.getType().toString())); - statement = connection.createStatement(); + try (Statement statement = connection.createStatement()) { statement.executeUpdate(querySource.getQuery(queryName, values)); if (querySource.queryExists(queryName + "Index")) { @@ -2115,23 +1846,20 @@ public void addMetaDataColumn(String channelId, MetaDataColumn metaDataColumn) { } } catch (SQLException e) { throw new DonkeyDaoException("Failed to add meta-data column", e); - } finally { - close(statement); } } @Override public void createChannel(String channelId, long localChannelId) { logger.debug(channelId + ": creating channel"); - Statement initSequenceStatement = null; transactionAlteredChannels = true; - PreparedStatement statement = null; try { - statement = prepareStatement("createChannel", null); - statement.setString(1, channelId); - statement.setLong(2, localChannelId); - statement.executeUpdate(); + try (PreparedStatement statement = prepareStatement("createChannel", null)) { + statement.setString(1, channelId); + statement.setLong(2, localChannelId); + statement.executeUpdate(); + } Map values = new HashMap(); values.put("localChannelId", localChannelId); @@ -2145,24 +1873,20 @@ public void createChannel(String channelId, long localChannelId) { createTable("createMessageSequence", values); if (querySource.queryExists("initMessageSequence")) { - initSequenceStatement = getConnection().createStatement(); - initSequenceStatement.executeUpdate(querySource.getQuery("initMessageSequence", values)); + try (Statement initSequenceStatement = connection.createStatement()) { + initSequenceStatement.executeUpdate(querySource.getQuery("initMessageSequence", values)); + } } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(initSequenceStatement); - closeDatabaseObjectIfNeeded(statement); } } private void createTable(String query, Map values) { if (querySource.queryExists(query)) { - Statement statement = null; int n = 1; - try { - statement = connection.createStatement(); + try (Statement statement = connection.createStatement()) { statement.executeUpdate(querySource.getQuery(query, values)); String sequenceQuery = querySource.getQuery(query + "Sequence", values); @@ -2179,8 +1903,6 @@ private void createTable(String query, Map values) { } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(statement); } } } @@ -2199,17 +1921,15 @@ public void checkAndCreateChannelTables() { channelTablesMap.put("d_msq" + localChannelId, "createMessageSequence"); } - ResultSet rs = null; - Statement statement = null; try { DatabaseMetaData dbMetaData = connection.getMetaData(); - rs = dbMetaData.getTables(null, null, "%", null); - while (rs.next()) { - String tableName = rs.getString("TABLE_NAME").toLowerCase(); - channelTablesMap.remove(tableName); + try (ResultSet rs = dbMetaData.getTables(null, null, "%", null)) { + while (rs.next()) { + String tableName = rs.getString("TABLE_NAME").toLowerCase(); + channelTablesMap.remove(tableName); + } } - close(rs); /* * MIRTH-2851 - Oracle does not return sequences in the DatabaseMetaData.getTables @@ -2219,22 +1939,19 @@ public void checkAndCreateChannelTables() { */ if (querySource.queryExists("getSequenceMetadata")) { - statement = connection.createStatement(); - rs = statement.executeQuery(querySource.getQuery("getSequenceMetadata")); - while (rs.next()) { - String sequenceName = rs.getString("SEQUENCE_NAME").toLowerCase(); - channelTablesMap.remove(sequenceName); + try (Statement statement = connection.createStatement(); + ResultSet rs = statement.executeQuery(querySource.getQuery("getSequenceMetadata"))) { + while (rs.next()) { + String sequenceName = rs.getString("SEQUENCE_NAME").toLowerCase(); + channelTablesMap.remove(sequenceName); + } } } } catch (Exception e) { throw new DonkeyDaoException(e); - } finally { - close(rs); - close(statement); } for (Entry entry : channelTablesMap.entrySet()) { - Statement initSequenceStatement = null; try { Long localChannelId = Long.parseLong(entry.getKey().replaceAll("[^0-9]", "")); Map values = new HashMap(); @@ -2242,13 +1959,12 @@ public void checkAndCreateChannelTables() { createTable(entry.getValue(), values); if (entry.getKey().toLowerCase().contains("d_msq") && querySource.queryExists("initMessageSequence")) { - initSequenceStatement = connection.createStatement(); - initSequenceStatement.executeUpdate(querySource.getQuery("initMessageSequence", values)); + try (Statement initSequenceStatement = connection.createStatement()) { + initSequenceStatement.executeUpdate(querySource.getQuery("initMessageSequence", values)); + } } } catch (Exception e) { throw new DonkeyDaoException(e); - } finally { - close(initSequenceStatement); } } } @@ -2256,30 +1972,29 @@ public void checkAndCreateChannelTables() { @Override public void resetStatistics(String channelId, Integer metaDataId, Set statuses) { logger.debug(channelId + ": resetting statistics" + (metaDataId == null ? "" : (" for metadata id " + metaDataId))); - PreparedStatement statement = null; - try { - if (statuses == null || statuses.size() == 0) { - return; - } + if (statuses == null || statuses.size() == 0) { + return; + } - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); - int count = 0; - StringBuilder builder = new StringBuilder(); - for (Status status : statuses) { - count++; + int count = 0; + StringBuilder builder = new StringBuilder(); + for (Status status : statuses) { + count++; - if (count > 1) { - builder.append(","); - } - builder.append(status.toString() + " = 0"); + if (count > 1) { + builder.append(","); } - values.put("statuses", builder.toString()); + builder.append(status.toString() + " = 0"); + } + values.put("statuses", builder.toString()); - String queryName = (metaDataId == null) ? "resetChannelStatistics" : "resetConnectorStatistics"; - statement = connection.prepareStatement(querySource.getQuery(queryName, values)); + String queryName = (metaDataId == null) ? "resetChannelStatistics" : "resetConnectorStatistics"; + + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery(queryName, values))) { statement.setString(1, statsServerId); if (metaDataId != null) { @@ -2297,24 +2012,19 @@ public void resetStatistics(String channelId, Integer metaDataId, Set st if (!metaDataIds.containsKey(metaDataId)) { metaDataIds.put(metaDataId, statuses); } - } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(statement); } } @Override public void resetAllStatistics(String channelId) { logger.debug(channelId + ": resetting all statistics (including lifetime)"); - PreparedStatement statement = null; - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); - statement = connection.prepareStatement(querySource.getQuery("resetAllStatistics", values)); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("resetAllStatistics", values))) { statement.setString(1, statsServerId); statement.executeUpdate(); @@ -2347,8 +2057,6 @@ public void resetAllStatistics(String channelId) { } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(statement); } } @@ -2366,35 +2074,30 @@ private Statistics getChannelStatistics(String serverId, boolean total) { Map channelIds = getLocalChannelIds(); String queryId = (total) ? "getChannelTotalStatistics" : "getChannelStatistics"; Statistics statistics = new Statistics(!total); - ResultSet resultSet = null; for (String channelId : channelIds.keySet()) { - PreparedStatement statement = null; - try { - statement = prepareStatement(queryId, channelId); + try (PreparedStatement statement = prepareStatement(queryId, channelId)) { statement.setString(1, serverId); - resultSet = statement.executeQuery(); - while (resultSet.next()) { - Integer metaDataId = resultSet.getInt("metadata_id"); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + Integer metaDataId = resultSet.getInt("metadata_id"); - if (resultSet.wasNull()) { - metaDataId = null; - } + if (resultSet.wasNull()) { + metaDataId = null; + } - Map stats = new HashMap(); - stats.put(Status.RECEIVED, resultSet.getLong("received")); - stats.put(Status.FILTERED, resultSet.getLong("filtered")); - stats.put(Status.SENT, resultSet.getLong("sent")); - stats.put(Status.ERROR, resultSet.getLong("error")); + Map stats = new HashMap(); + stats.put(Status.RECEIVED, resultSet.getLong("received")); + stats.put(Status.FILTERED, resultSet.getLong("filtered")); + stats.put(Status.SENT, resultSet.getLong("sent")); + stats.put(Status.ERROR, resultSet.getLong("error")); - statistics.overwrite(channelId, metaDataId, stats); + statistics.overwrite(channelId, metaDataId, stats); + } } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } } @@ -2412,13 +2115,8 @@ public void commit(boolean durable) { try { if (!durable && asyncCommitCommand != null) { - Statement statement = null; - - try { - statement = connection.createStatement(); + try (Statement statement = connection.createStatement()) { statement.execute(asyncCommitCommand); - } finally { - close(statement); } } else { connection.commit(); @@ -2526,20 +2224,6 @@ public boolean isClosed() { } } - /* - * Closes Statement or ResultSet, if needed - */ - protected void closeDatabaseObjectIfNeeded(AutoCloseable dbObject) { - // no op - } - - /* - * Closes any Statements or ResultSets, if needed - */ - protected void closeDatabaseObjectsIfNeeded(List dbObjects) { - // no op - } - @Override public boolean initTableStructure() { if (!tableExists("d_channels")) { @@ -2551,24 +2235,22 @@ public boolean initTableStructure() { } } - @SuppressWarnings("resource") private boolean tableExists(String tableName) { - ResultSet resultSet = null; - try { DatabaseMetaData metaData = connection.getMetaData(); - resultSet = metaData.getTables(null, null, tableName, null); - if (resultSet.next()) { - return true; + // Databases disagree on identifier case folding, so try both spellings + for (String name : new String[] { tableName, tableName.toUpperCase() }) { + try (ResultSet resultSet = metaData.getTables(null, null, name, null)) { + if (resultSet.next()) { + return true; + } + } } - resultSet = metaData.getTables(null, null, tableName.toUpperCase(), null); - return resultSet.next(); + return false; } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); } } @@ -2675,34 +2357,28 @@ private ConnectorMessage getConnectorMessageFromResultSet(String channelId, Resu */ private List getMessageContent(String channelId, long messageId, int metaDataId) { List messageContents = new ArrayList(); - ResultSet resultSet = null; - PreparedStatement statement = null; - try { - statement = prepareStatement("getMessageContent", channelId); + try (PreparedStatement statement = prepareStatement("getMessageContent", channelId)) { statement.setLong(1, messageId); statement.setInt(2, metaDataId); - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - String content = resultSet.getString("content"); - ContentType contentType = ContentType.fromCode(resultSet.getInt("content_type")); - String dataType = resultSet.getString("data_type"); - boolean encrypted = resultSet.getBoolean("is_encrypted"); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + String content = resultSet.getString("content"); + ContentType contentType = ContentType.fromCode(resultSet.getInt("content_type")); + String dataType = resultSet.getString("data_type"); + boolean encrypted = resultSet.getBoolean("is_encrypted"); + + if ((decryptData || alwaysDecrypt.contains(contentType)) && encrypted && encryptor != null) { + content = encryptor.decrypt(content); + encrypted = false; + } - if ((decryptData || alwaysDecrypt.contains(contentType)) && encrypted && encryptor != null) { - content = encryptor.decrypt(content); - encrypted = false; + messageContents.add(new MessageContent(channelId, messageId, metaDataId, contentType, content, dataType, encrypted)); } - - messageContents.add(new MessageContent(channelId, messageId, metaDataId, contentType, content, dataType, encrypted)); } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } return messageContents; @@ -2714,18 +2390,13 @@ private Map>> getMessageContent(String c } Map>> messageContentMap = new LinkedHashMap>>(); - PreparedStatement statement = null; - ResultSet resultSet = null; - - try { - Map params = new HashMap(); - params.put("localChannelId", getLocalChannelId(channelId)); - params.put("messageIds", StringUtils.join(messageIds, ",")); - - statement = connection.prepareStatement(querySource.getQuery("getMessageContentByMessageIds", params)); - resultSet = statement.executeQuery(); + Map params = new HashMap(); + params.put("localChannelId", getLocalChannelId(channelId)); + params.put("messageIds", StringUtils.join(messageIds, ",")); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getMessageContentByMessageIds", params)); + ResultSet resultSet = statement.executeQuery()) { while (resultSet.next()) { Long messageId = resultSet.getLong("message_id"); Integer metaDataId = resultSet.getInt("metadata_id"); @@ -2755,9 +2426,6 @@ private Map>> getMessageContent(String c } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } return messageContentMap; @@ -2768,37 +2436,30 @@ private Map>> getMessageContent(String c */ private List getDestinationMessageContentFromSource(String channelId, long messageId, int metaDataId) { List messageContents = new ArrayList(); - ResultSet resultSet = null; - PreparedStatement statement = null; - - try { - statement = prepareStatement("getDestinationMessageContentFromSource", channelId); + try (PreparedStatement statement = prepareStatement("getDestinationMessageContentFromSource", channelId)) { statement.setLong(1, messageId); - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - String content = resultSet.getString("content"); - ContentType contentType = ContentType.fromCode(resultSet.getInt("content_type")); - String dataType = resultSet.getString("data_type"); - boolean encrypted = resultSet.getBoolean("is_encrypted"); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + String content = resultSet.getString("content"); + ContentType contentType = ContentType.fromCode(resultSet.getInt("content_type")); + String dataType = resultSet.getString("data_type"); + boolean encrypted = resultSet.getBoolean("is_encrypted"); + + if ((decryptData || alwaysDecrypt.contains(contentType)) && encrypted && encryptor != null) { + content = encryptor.decrypt(content); + encrypted = false; + } - if ((decryptData || alwaysDecrypt.contains(contentType)) && encrypted && encryptor != null) { - content = encryptor.decrypt(content); - encrypted = false; - } + if (contentType == ContentType.ENCODED) { + contentType = ContentType.RAW; + } - if (contentType == ContentType.ENCODED) { - contentType = ContentType.RAW; + messageContents.add(new MessageContent(channelId, messageId, metaDataId, contentType, content, dataType, encrypted)); } - - messageContents.add(new MessageContent(channelId, messageId, metaDataId, contentType, content, dataType, encrypted)); } } catch (SQLException e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); } return messageContents; @@ -2878,64 +2539,57 @@ private ErrorContent getErrorContentFromMessageContent(MessageContent content) { } private Map getMetaDataMap(String channelId, long messageId, int metaDataId) { - PreparedStatement statement = null; - ResultSet resultSet = null; + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - - // do not cache this statement since metadata columns may be added/removed - statement = connection.prepareStatement(querySource.getQuery("getMetaDataMap", values)); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getMetaDataMap", values))) { statement.setLong(1, messageId); statement.setInt(2, metaDataId); Map metaDataMap = new HashMap(); - resultSet = statement.executeQuery(); - - if (resultSet.next()) { - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - int columnCount = resultSetMetaData.getColumnCount(); - - for (int i = 1; i <= columnCount; i++) { - MetaDataColumnType metaDataColumnType = MetaDataColumnType.fromSqlType(resultSetMetaData.getColumnType(i)); - Object value = null; - switch (metaDataColumnType) {//@formatter:off - case STRING: - value = resultSet.getString(i); - if (encryptor != null && StringUtils.startsWith((String) value, Encryptor.HEADER_INDICATOR)) { - try { - value = encryptor.decrypt((String) value); - } catch (Exception e) { - logger.debug("Unable to decrypt custom metadata column " + resultSetMetaData.getColumnName(i).toUpperCase() + " for channel " + channelId + ", messsage " + messageId + "-" + metaDataId, e); + try (ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + int columnCount = resultSetMetaData.getColumnCount(); + + for (int i = 1; i <= columnCount; i++) { + MetaDataColumnType metaDataColumnType = MetaDataColumnType.fromSqlType(resultSetMetaData.getColumnType(i)); + Object value = null; + + switch (metaDataColumnType) {//@formatter:off + case STRING: + value = resultSet.getString(i); + if (encryptor != null && StringUtils.startsWith((String) value, Encryptor.HEADER_INDICATOR)) { + try { + value = encryptor.decrypt((String) value); + } catch (Exception e) { + logger.debug("Unable to decrypt custom metadata column " + resultSetMetaData.getColumnName(i).toUpperCase() + " for channel " + channelId + ", messsage " + messageId + "-" + metaDataId, e); + } } - } - break; - case NUMBER: value = resultSet.getBigDecimal(i); break; - case BOOLEAN: value = resultSet.getBoolean(i); break; - case TIMESTAMP: + break; + case NUMBER: value = resultSet.getBigDecimal(i); break; + case BOOLEAN: value = resultSet.getBoolean(i); break; + case TIMESTAMP: - Timestamp timestamp = resultSet.getTimestamp(i); - if (timestamp != null) { - value = Calendar.getInstance(); - ((Calendar) value).setTimeInMillis(timestamp.getTime()); - } - break; + Timestamp timestamp = resultSet.getTimestamp(i); + if (timestamp != null) { + value = Calendar.getInstance(); + ((Calendar) value).setTimeInMillis(timestamp.getTime()); + } + break; - default: throw new Exception("Unrecognized MetaDataColumnType"); - } //@formatter:on + default: throw new Exception("Unrecognized MetaDataColumnType"); + } //@formatter:on - metaDataMap.put(resultSetMetaData.getColumnName(i).toUpperCase(), value); + metaDataMap.put(resultSetMetaData.getColumnName(i).toUpperCase(), value); + } } } return metaDataMap; } catch (Exception e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @@ -2945,18 +2599,13 @@ private Map>> getMetaDataMaps(String chan } Map>> metaDataMaps = new HashMap>>(); - PreparedStatement statement = null; - ResultSet resultSet = null; - try { - Map values = new HashMap(); - values.put("localChannelId", getLocalChannelId(channelId)); - values.put("messageIds", StringUtils.join(messageIds, ",")); - - // do not cache this statement since metadata columns may be added/removed - statement = connection.prepareStatement(querySource.getQuery("getMetaDataMapByMessageId", values)); - resultSet = statement.executeQuery(); + Map values = new HashMap(); + values.put("localChannelId", getLocalChannelId(channelId)); + values.put("messageIds", StringUtils.join(messageIds, ",")); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getMetaDataMapByMessageId", values)); + ResultSet resultSet = statement.executeQuery()) { ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); int columnCount = resultSetMetaData.getColumnCount(); MetaDataColumnType[] columnTypes = new MetaDataColumnType[columnCount + 1]; @@ -3017,9 +2666,6 @@ private Map>> getMetaDataMaps(String chan return metaDataMaps; } catch (Exception e) { throw new DonkeyDaoException(e); - } finally { - close(resultSet); - close(statement); } } @@ -3029,15 +2675,11 @@ private Map>> getMetaDataMaps(String chan * deletes, which hinders concurrency and can increase the risk of deadlocks. */ private void cascadeMessageDelete(String queryId, String channelId) throws SQLException { - PreparedStatement statement = null; - try { - statement = prepareStatement(queryId, channelId); + try (PreparedStatement statement = prepareStatement(queryId, channelId)) { if (statement != null) { statement.executeUpdate(); } - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -3047,16 +2689,12 @@ private void cascadeMessageDelete(String queryId, String channelId) throws SQLEx * deletes, which hinders concurrency and can increase the risk of deadlocks. */ private void cascadeMessageDelete(String queryId, long messageId, String channelId) throws SQLException { - PreparedStatement statement = null; - try { - statement = prepareStatement(queryId, channelId); + try (PreparedStatement statement = prepareStatement(queryId, channelId)) { if (statement != null) { statement.setLong(1, messageId); statement.executeUpdate(); } - } finally { - closeDatabaseObjectIfNeeded(statement); } } @@ -3069,20 +2707,17 @@ private void cascadeMessageDelete(String queryId, long messageId, Map values = new HashMap(); + values.put("localChannelId", localChannelId); + query = querySource.getQuery(queryId, values); } + + return (query == null) ? null : connection.prepareStatement(query); } - protected void close(ResultSet resultSet) { - try { - DbUtils.close(resultSet); - } catch (SQLException e) { - logger.error("Failed to close JDBC result set", e); + /** + * Runs the query with the given id, if the current database defines one. Used for the DDL + * that only some databases need, such as dropping and re-adding constraints around a delete. + */ + private void executeUpdateIfDefined(String queryId, String channelId) throws SQLException { + if (!querySource.queryExists(queryId)) { + return; + } + + try (PreparedStatement statement = prepareStatement(queryId, channelId)) { + statement.executeUpdate(); } } @@ -3212,33 +2855,21 @@ protected String getDeployedChannelName(String channelId) { @Override public List getPortsInUse() { - String queryId = "getPortsInUse"; - String query = querySource.getQuery(queryId); - List ports = new ArrayList(); - ResultSet resultSet = null; - PreparedStatement statement = null; - try { - statement = connection.prepareStatement(query); - resultSet = statement.executeQuery(); - - while (resultSet.next()) { - Ports port = new Ports(); - port.setId(resultSet.getString("id")); - port.setName(resultSet.getString("name")); - port.setPort(resultSet.getString("portstring")); - ports.add(port); - } - } catch (SQLException e) { - throw new DonkeyDaoException(e); - } finally { - close(resultSet); - closeDatabaseObjectIfNeeded(statement); + try (PreparedStatement statement = connection.prepareStatement(querySource.getQuery("getPortsInUse")); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + Ports port = new Ports(); + port.setId(resultSet.getString("id")); + port.setName(resultSet.getString("name")); + port.setPort(resultSet.getString("portstring")); + ports.add(port); } - + } catch (SQLException e) { + throw new DonkeyDaoException(e); + } return ports; - } } diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoFactory.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoFactory.java index be702d2c82..cac963c4e7 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoFactory.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoFactory.java @@ -11,11 +11,6 @@ import java.sql.Connection; import java.sql.SQLException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import com.mirth.connect.donkey.server.Donkey; import com.mirth.connect.donkey.server.channel.Statistics; @@ -57,8 +52,6 @@ public static JdbcDaoFactory getInstance(String database) { private boolean encryptAttachments = false; private boolean encryptCustomMetaData = false; private boolean decryptData = true; - private Map statementSources = new ConcurrentHashMap(); - private Logger logger = LogManager.getLogger(getClass()); protected JdbcDaoFactory() { donkey = Donkey.getInstance(); @@ -94,10 +87,6 @@ public void setSerializerProvider(SerializerProvider serializerProvider) { this.serializerProvider = serializerProvider; } - public Map getStatementSources() { - return statementSources; - } - @Override public void setEncryptData(boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData) { this.encryptMessageContent = encryptMessageContent; @@ -122,44 +111,18 @@ public JdbcDao getDao() { @Override public JdbcDao getDao(SerializerProvider serializerProvider) { - PooledConnection pooledConnection; + Connection connection; try { - pooledConnection = connectionPool.getConnection(); + connection = connectionPool.getConnection(); } catch (SQLException e) { throw new DonkeyDaoException(e); } - PreparedStatementSource statementSource = null; - Connection connection = pooledConnection.getConnection(); - Connection internalConnection = pooledConnection.getInternalConnection(); - statementSource = statementSources.get(internalConnection); - - if (statementSource == null) { - statementSource = new CachedPreparedStatementSource(internalConnection, querySource); - statementSources.put(internalConnection, statementSource); - - Integer maxConnections = connectionPool.getMaxConnections(); - - if (maxConnections == null || statementSources.size() > maxConnections) { - logger.debug("cleaning up prepared statement cache"); - - try { - for (Connection currentConnection : statementSources.keySet()) { - if (currentConnection.isClosed()) { - statementSources.remove(currentConnection); - } - } - } catch (SQLException e) { - throw new DonkeyDaoException(e); - } - } - } - - return getDao(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, channelController.getStatistics(), channelController.getTotalStatistics(), statsServerId); + return getDao(donkey, connection, querySource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, channelController.getStatistics(), channelController.getTotalStatistics(), statsServerId); } - protected JdbcDao getDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { - return new JdbcDao(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); + protected JdbcDao getDao(Donkey donkey, Connection connection, QuerySource querySource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { + return new JdbcDao(donkey, connection, querySource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); } } diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleDaoFactory.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleDaoFactory.java index 8247852f68..53a2ac0aa4 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleDaoFactory.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleDaoFactory.java @@ -9,17 +9,13 @@ package com.mirth.connect.donkey.server.data.jdbc; -import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.mirth.connect.donkey.server.Donkey; -import com.mirth.connect.donkey.server.channel.Statistics; import com.mirth.connect.donkey.server.data.DonkeyDaoException; -import com.mirth.connect.donkey.server.data.StatisticsUpdater; import com.mirth.connect.donkey.util.SerializerProvider; public class OracleDaoFactory extends JdbcDaoFactory { @@ -37,11 +33,6 @@ public JdbcDao getDao(SerializerProvider serializerProvider) { return dao; } - @Override - protected JdbcDao getDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { - return new OracleJdbcDao(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); - } - private String getAsyncCommitCommand(JdbcDao dao) { if (supported == null) { try { diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleJdbcDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleJdbcDao.java deleted file mode 100644 index 13dd2a7201..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/OracleJdbcDao.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.jdbc; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.Statement; -import java.util.List; - -import com.mirth.connect.donkey.server.Donkey; -import com.mirth.connect.donkey.server.channel.Statistics; -import com.mirth.connect.donkey.server.data.StatisticsUpdater; -import com.mirth.connect.donkey.util.SerializerProvider; - -public class OracleJdbcDao extends JdbcDao { - - public OracleJdbcDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData, boolean decryptData, StatisticsUpdater statisticsUpdater, Statistics currentStats, Statistics totalStats, String statsServerId) { - super(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); - } - - @Override - protected void closeDatabaseObjectIfNeeded(AutoCloseable dbObject) { - if (dbObject instanceof Statement) { - close((Statement) dbObject); - } else if (dbObject instanceof ResultSet) { - close((ResultSet) dbObject); - } - } - - @Override - protected void closeDatabaseObjectsIfNeeded(List dbObjects) { - for (AutoCloseable obj : dbObjects) { - closeDatabaseObjectIfNeeded(obj); - } - } - -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PooledConnection.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PooledConnection.java deleted file mode 100644 index e8f74f10fc..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PooledConnection.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.jdbc; - -import java.sql.Connection; - -public class PooledConnection { - private Connection connection; - private Connection internalConnection; - - public PooledConnection(Connection connection, Connection internalConnection) { - this.connection = connection; - this.internalConnection = internalConnection; - } - - public Connection getConnection() { - return connection; - } - - public void setConnection(Connection connection) { - this.connection = connection; - } - - public Connection getInternalConnection() { - return internalConnection; - } - - public void setInternalConnection(Connection internalConnection) { - this.internalConnection = internalConnection; - } -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PreparedStatementSource.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PreparedStatementSource.java deleted file mode 100644 index a337c40d3b..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/jdbc/PreparedStatementSource.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.jdbc; - -import java.sql.PreparedStatement; -import java.sql.SQLException; - -public interface PreparedStatementSource { - public PreparedStatement getPreparedStatement(String queryId, Long localChannelId) throws SQLException; -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/passthru/PassthruDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/passthru/PassthruDao.java index 9856290c6f..b2bda11758 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/passthru/PassthruDao.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/server/data/passthru/PassthruDao.java @@ -330,10 +330,7 @@ public void deleteConnectorMessages(String channelId, long messageId, Set metaDataIds) {} @Override - public void batchInsertMessageContent(MessageContent messageContent) {} - - @Override - public void executeBatchInsertMessageContent(String channelId) {} + public void insertMessageContentBatch(List messageContents) {} @Override public Statistics getChannelStatistics(String serverId) { diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/timed/TimedDao.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/timed/TimedDao.java deleted file mode 100644 index b6234ef99d..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/timed/TimedDao.java +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.timed; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.mirth.connect.donkey.model.channel.MetaDataColumn; -import com.mirth.connect.donkey.model.message.ConnectorMessage; -import com.mirth.connect.donkey.model.message.Message; -import com.mirth.connect.donkey.model.message.MessageContent; -import com.mirth.connect.donkey.model.message.Status; -import com.mirth.connect.donkey.model.message.attachment.Attachment; -import com.mirth.connect.donkey.server.channel.Statistics; -import com.mirth.connect.donkey.server.data.DonkeyDao; -import com.mirth.connect.donkey.server.data.StatisticsUpdater; -import com.mirth.connect.donkey.model.channel.Ports; -import com.mirth.connect.donkey.util.ActionTimer; - -public class TimedDao implements DonkeyDao { - private DonkeyDao dao; - private ActionTimer timer; - - protected TimedDao(DonkeyDao dao, ActionTimer timer) { - this.dao = dao; - this.timer = timer; - } - - public DonkeyDao getDao() { - return dao; - } - - public void setDao(DonkeyDao dao) { - this.dao = dao; - } - - public ActionTimer getTimer() { - return timer; - } - - public void setTimer(ActionTimer timer) { - this.timer = timer; - } - - @Override - public void setEncryptData(boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData) { - dao.setEncryptData(encryptMessageContent, encryptAttachments, encryptCustomMetaData); - } - - @Override - public void setDecryptData(boolean decryptData) { - dao.setDecryptData(decryptData); - } - - @Override - public void setStatisticsUpdater(StatisticsUpdater statisticsUpdater) { - dao.setStatisticsUpdater(statisticsUpdater); - } - - @Override - public void commit() { - dao.commit(); - } - - @Override - public void commit(boolean durable) { - dao.commit(durable); - } - - @Override - public void rollback() { - dao.rollback(); - } - - @Override - public void close() { - dao.close(); - } - - @Override - public boolean isClosed() { - return dao.isClosed(); - } - - @Override - public void insertMessage(Message message) { - long startTime = System.currentTimeMillis(); - - try { - dao.insertMessage(message); - } finally { - timer.log("insertMessage", System.currentTimeMillis() - startTime); - } - } - - @Override - public void insertConnectorMessage(ConnectorMessage connectorMessage, boolean storeMaps, boolean updateStats) { - long startTime = System.currentTimeMillis(); - - try { - dao.insertConnectorMessage(connectorMessage, storeMaps, updateStats); - } finally { - timer.log("insertConnectorMessage", System.currentTimeMillis() - startTime); - } - } - - @Override - public void insertMessageContent(MessageContent messageContent) { - long startTime = System.currentTimeMillis(); - - try { - dao.insertMessageContent(messageContent); - } finally { - timer.log("insertMessageContent", System.currentTimeMillis() - startTime); - } - } - - @Override - public void batchInsertMessageContent(MessageContent messageContent) { - long startTime = System.currentTimeMillis(); - - try { - dao.batchInsertMessageContent(messageContent); - } finally { - timer.log("batchInsertMessageContent", System.currentTimeMillis() - startTime); - } - } - - @Override - public void executeBatchInsertMessageContent(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - dao.executeBatchInsertMessageContent(channelId); - } finally { - timer.log("executeBatchInsertMessageContent", System.currentTimeMillis() - startTime); - } - } - - @Override - public void insertMessageAttachment(String channelId, long messageId, Attachment attachment) { - long startTime = System.currentTimeMillis(); - - try { - dao.insertMessageAttachment(channelId, messageId, attachment); - } finally { - timer.log("insertMessageAttachment", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateMessageAttachment(String channelId, long messageId, Attachment attachment) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateMessageAttachment(channelId, messageId, attachment); - } finally { - timer.log("updateMessageAttachment", System.currentTimeMillis() - startTime); - } - } - - @Override - public void insertMetaData(ConnectorMessage connectorMessage, List metaDataColumns) { - long startTime = System.currentTimeMillis(); - - try { - dao.insertMetaData(connectorMessage, metaDataColumns); - } finally { - timer.log("insertMetaData", System.currentTimeMillis() - startTime); - } - } - - @Override - public void storeMetaData(ConnectorMessage connectorMessage, List metaDataColumns) { - long startTime = System.currentTimeMillis(); - - try { - dao.storeMetaData(connectorMessage, metaDataColumns); - } finally { - timer.log("storeMetaData", System.currentTimeMillis() - startTime); - } - } - - @Override - public void storeMessageContent(MessageContent messageContent) { - long startTime = System.currentTimeMillis(); - - try { - dao.storeMessageContent(messageContent); - } finally { - timer.log("storeMessageContent", System.currentTimeMillis() - startTime); - } - } - - @Override - public void addChannelStatistics(Statistics statistics) { - long startTime = System.currentTimeMillis(); - - try { - dao.addChannelStatistics(statistics); - } finally { - timer.log("addChannelStatistics", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateSendAttempts(ConnectorMessage connectorMessage) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateSendAttempts(connectorMessage); - } finally { - timer.log("updateResponseError", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateStatus(ConnectorMessage connectorMessage, Status previousStatus) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateStatus(connectorMessage, previousStatus); - } finally { - timer.log("updateStatus", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateErrors(ConnectorMessage connectorMessage) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateErrors(connectorMessage); - } finally { - timer.log("updateErrors", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateMaps(ConnectorMessage connectorMessage) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateMaps(connectorMessage); - } finally { - timer.log("updateMaps", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateSourceMap(ConnectorMessage connectorMessage) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateSourceMap(connectorMessage); - } finally { - timer.log("updateSourceMap", System.currentTimeMillis() - startTime); - } - } - - @Override - public void updateResponseMap(ConnectorMessage connectorMessage) { - long startTime = System.currentTimeMillis(); - - try { - dao.updateResponseMap(connectorMessage); - } finally { - timer.log("updateResponseMap", System.currentTimeMillis() - startTime); - } - } - - @Override - public void markAsProcessed(String channelId, long messageId) { - long startTime = System.currentTimeMillis(); - - try { - dao.markAsProcessed(channelId, messageId); - } finally { - timer.log("markAsProcessed", System.currentTimeMillis() - startTime); - } - } - - @Override - public void resetMessage(String channelId, long messageId) { - long startTime = System.currentTimeMillis(); - - try { - dao.resetMessage(channelId, messageId); - } finally { - timer.log("resetMessage", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteMessage(String channelId, long messageId) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteMessage(channelId, messageId); - } finally { - timer.log("deleteMessage", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteConnectorMessages(String channelId, long messageId, Set metaDataIds) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteConnectorMessages(channelId, messageId, metaDataIds); - } finally { - timer.log("deleteConnectorMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteMessageStatistics(String channelId, long messageId, Set metaDataIds) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteMessageStatistics(channelId, messageId, metaDataIds); - } finally { - timer.log("deleteMessageStatistics", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteAllMessages(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteAllMessages(channelId); - } finally { - timer.log("deleteAllMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteMessageContent(String channelId, long messageId) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteMessageContent(channelId, messageId); - } finally { - timer.log("deleteMessageContent", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteMessageContentByMetaDataIds(String channelId, long messageId, Set metaDataIds) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteMessageContentByMetaDataIds(channelId, messageId, metaDataIds); - } finally { - timer.log("deleteMessageContentByMetaDataIds", System.currentTimeMillis() - startTime); - } - } - - @Override - public void deleteMessageAttachments(String channelId, long messageId) { - long startTime = System.currentTimeMillis(); - - try { - dao.deleteMessageAttachments(channelId, messageId); - } finally { - timer.log("deleteMessageAttachments", System.currentTimeMillis() - startTime); - } - } - - @Override - public void createChannel(String channelId, long localChannelId) { - long startTime = System.currentTimeMillis(); - - try { - dao.createChannel(channelId, localChannelId); - } finally { - timer.log("createChannel", System.currentTimeMillis() - startTime); - } - } - - @Override - public boolean initTableStructure() { - long startTime = System.currentTimeMillis(); - - try { - return dao.initTableStructure(); - } finally { - timer.log("initTableStructure", System.currentTimeMillis() - startTime); - } - } - - @Override - public void checkAndCreateChannelTables() { - long startTime = System.currentTimeMillis(); - - try { - dao.checkAndCreateChannelTables(); - } finally { - timer.log("checkOrCreateChannelTables", System.currentTimeMillis() - startTime); - } - } - - @Override - public void removeChannel(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - dao.removeChannel(channelId); - } finally { - timer.log("removeChannel", System.currentTimeMillis() - startTime); - } - } - - @Override - public void addMetaDataColumn(String channelId, MetaDataColumn metaDataColumn) { - long startTime = System.currentTimeMillis(); - - try { - dao.addMetaDataColumn(channelId, metaDataColumn); - } finally { - timer.log("addMetaDataColumn", System.currentTimeMillis() - startTime); - } - } - - @Override - public void removeMetaDataColumn(String channelId, String columnName) { - long startTime = System.currentTimeMillis(); - - try { - dao.removeMetaDataColumn(channelId, columnName); - } finally { - timer.log("removeMetaDataColumn", System.currentTimeMillis() - startTime); - } - } - - @Override - public void resetStatistics(String channelId, Integer metaDataId, Set statuses) { - long startTime = System.currentTimeMillis(); - - try { - dao.resetStatistics(channelId, metaDataId, statuses); - } finally { - timer.log("resetStatistics", System.currentTimeMillis() - startTime); - } - } - - @Override - public void resetAllStatistics(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - dao.resetAllStatistics(channelId); - } finally { - timer.log("resetStatistics", System.currentTimeMillis() - startTime); - } - } - - @Override - public Long selectMaxLocalChannelId() { - long startTime = System.currentTimeMillis(); - - try { - return dao.selectMaxLocalChannelId(); - } finally { - timer.log("selectMaxLocalChannelId", System.currentTimeMillis() - startTime); - } - } - - @Override - public Map getLocalChannelIds() { - long startTime = System.currentTimeMillis(); - - try { - return dao.getLocalChannelIds(); - } finally { - timer.log("getLocalChannelIds", System.currentTimeMillis() - startTime); - } - } - - @Override - public long getMaxMessageId(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getMaxMessageId(channelId); - } finally { - timer.log("getMaxMessageId", System.currentTimeMillis() - startTime); - } - } - - @Override - public long getMinMessageId(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getMinMessageId(channelId); - } finally { - timer.log("getMinMessageId", System.currentTimeMillis() - startTime); - } - } - - @Override - public long getNextMessageId(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getNextMessageId(channelId); - } finally { - timer.log("getNextMessageId", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getMessageAttachment(String channelId, long messageId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getMessageAttachment(channelId, messageId); - } finally { - timer.log("getMessageAttachment", System.currentTimeMillis() - startTime); - } - } - - @Override - public Attachment getMessageAttachment(String channelId, String attachmentId, Long messageId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getMessageAttachment(channelId, attachmentId, messageId); - } finally { - timer.log("getMessageAttachment", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getPendingConnectorMessages(String channelId, String serverId, int limit, Long minMessageId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getPendingConnectorMessages(channelId, serverId, limit, minMessageId); - } finally { - timer.log("getPendingConnectorMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getMessages(String channelId, List messageIds) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getMessages(channelId, messageIds); - } finally { - timer.log("getMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getConnectorMessages(String channelId, String serverId, int metaDataId, Status status, int offset, int limit, Long minMessageId, Long maxMessageId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getConnectorMessages(channelId, serverId, metaDataId, status, offset, limit, minMessageId, maxMessageId); - } finally { - timer.log("getConnectorMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getConnectorMessages(String channelId, long messageId, Set metaDataIds, boolean includeContent) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getConnectorMessages(channelId, messageId, metaDataIds, includeContent); - } finally { - timer.log("getConnectorMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public Map getConnectorMessages(String channelId, long messageId, List metaDataIds) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getConnectorMessages(channelId, messageId, metaDataIds); - } finally { - timer.log("getConnectorMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public int getConnectorMessageCount(String channelId, String serverId, int metaDataId, Status status) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getConnectorMessageCount(channelId, serverId, metaDataId, status); - } finally { - timer.log("getConnectorMessageCount", System.currentTimeMillis() - startTime); - } - } - - @Override - public long getConnectorMessageMaxMessageId(String channelId, String serverId, int metaDataId, Status status) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getConnectorMessageMaxMessageId(channelId, serverId, metaDataId, status); - } finally { - timer.log("getConnectorMessageMaxMessageId", System.currentTimeMillis() - startTime); - } - } - - @Override - public Map getConnectorMessageStatuses(String channelId, long messageId, boolean checkProcessed) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getConnectorMessageStatuses(channelId, messageId, checkProcessed); - } finally { - timer.log("getConnectorMessageStatuses", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getUnfinishedMessages(String channelId, String serverId, int limit, Long minMessageId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getUnfinishedMessages(channelId, serverId, limit, minMessageId); - } finally { - timer.log("getUnfinishedMessages", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getMetaDataColumns(String channelId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getMetaDataColumns(channelId); - } finally { - timer.log("getMetaDataColumns", System.currentTimeMillis() - startTime); - } - } - - @Override - public Statistics getChannelStatistics(String serverId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getChannelStatistics(serverId); - } finally { - timer.log("getChannelStatistics", System.currentTimeMillis() - startTime); - } - } - - @Override - public Statistics getChannelTotalStatistics(String serverId) { - long startTime = System.currentTimeMillis(); - - try { - return dao.getChannelTotalStatistics(serverId); - } finally { - timer.log("getChannelTotalStatistics", System.currentTimeMillis() - startTime); - } - } - - @Override - public List getPortsInUse() { - long startTime = System.currentTimeMillis(); - - try { - return dao.getPortsInUse(); - } finally { - timer.log("getPortsInUse", System.currentTimeMillis() - startTime); - } - } -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/server/data/timed/TimedDaoFactory.java b/donkey/src/main/java/com/mirth/connect/donkey/server/data/timed/TimedDaoFactory.java deleted file mode 100644 index 0886803d37..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/server/data/timed/TimedDaoFactory.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.server.data.timed; - -import com.mirth.connect.donkey.server.data.DonkeyDao; -import com.mirth.connect.donkey.server.data.DonkeyDaoFactory; -import com.mirth.connect.donkey.server.data.StatisticsUpdater; -import com.mirth.connect.donkey.server.data.jdbc.ConnectionPool; -import com.mirth.connect.donkey.util.ActionTimer; -import com.mirth.connect.donkey.util.SerializerProvider; - -public class TimedDaoFactory implements DonkeyDaoFactory { - private DonkeyDaoFactory delegateFactory; - private ActionTimer timer; - private boolean encryptMessageContent = false; - private boolean encryptAttachments = false; - private boolean encryptCustomMetaData = false; - private boolean decryptData = true; - private StatisticsUpdater statisticsUpdater; - - public TimedDaoFactory(DonkeyDaoFactory delegateFactory, ActionTimer timer) { - this.delegateFactory = delegateFactory; - this.timer = timer; - } - - public DonkeyDaoFactory getDelegateFactory() { - return delegateFactory; - } - - public void setDelegateFactory(DonkeyDaoFactory delegateFactory) { - this.delegateFactory = delegateFactory; - } - - public ActionTimer getTimer() { - return timer; - } - - public void setTimer(ActionTimer timer) { - this.timer = timer; - } - - @Override - public void setEncryptData(boolean encryptMessageContent, boolean encryptAttachments, boolean encryptCustomMetaData) { - this.encryptMessageContent = encryptMessageContent; - this.encryptAttachments = encryptAttachments; - this.encryptCustomMetaData = encryptCustomMetaData; - } - - @Override - public void setDecryptData(boolean decryptData) { - this.decryptData = decryptData; - } - - @Override - public void setStatisticsUpdater(StatisticsUpdater statisticsUpdater) { - this.statisticsUpdater = statisticsUpdater; - } - - @Override - public DonkeyDao getDao() { - DonkeyDao dao = new TimedDao(delegateFactory.getDao(), timer); - dao.setEncryptData(encryptMessageContent, encryptAttachments, encryptCustomMetaData); - dao.setDecryptData(decryptData); - dao.setStatisticsUpdater(statisticsUpdater); - return dao; - } - - @Override - public DonkeyDao getDao(SerializerProvider serializerProvider) { - DonkeyDao dao = new TimedDao(delegateFactory.getDao(serializerProvider), timer); - dao.setEncryptData(encryptMessageContent, encryptAttachments, encryptCustomMetaData); - dao.setDecryptData(decryptData); - dao.setStatisticsUpdater(statisticsUpdater); - return dao; - } - - @Override - public ConnectionPool getConnectionPool() { - return delegateFactory.getConnectionPool(); - } -} diff --git a/donkey/src/main/java/com/mirth/connect/donkey/util/ActionTimer.java b/donkey/src/main/java/com/mirth/connect/donkey/util/ActionTimer.java deleted file mode 100644 index 240b18d4ac..0000000000 --- a/donkey/src/main/java/com/mirth/connect/donkey/util/ActionTimer.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) Mirth Corporation. All rights reserved. - * - * http://www.mirthcorp.com - * - * The software in this package is published under the terms of the MPL license a copy of which has - * been included with this distribution in the LICENSE.txt file. - */ - -package com.mirth.connect.donkey.util; - -import java.util.Comparator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.lang3.StringUtils; - -public class ActionTimer { - private boolean enabled = true; - private Map times = new ConcurrentHashMap(); - private Map counts = new ConcurrentHashMap(); - - public void log(String eventName, long millis) { - if (!enabled) { - return; - } - - Long oldTime = times.get(eventName); - - if (oldTime == null) { - times.put(eventName, millis); - } else { - times.put(eventName, oldTime + millis); - } - - Integer count = counts.get(eventName); - - if (count == null) { - counts.put(eventName, 1); - } else { - counts.put(eventName, count + 1); - } - } - - public long getTotalTime() { - long total = 0; - - for (Long time : times.values()) { - total += time; - } - - return total; - } - - public int getTotalCount() { - int total = 0; - - for (Integer count : counts.values()) { - total += count; - } - - return total; - } - - public Map getTimes() { - return times; - } - - public Map getCounts() { - return counts; - } - - public String getLog() { - long totalTime = getTotalTime(); - - StringBuilder log = new StringBuilder(); - LongComparator longComparator = new LongComparator(times); - TreeMap sortedTimes = new TreeMap(longComparator); - sortedTimes.putAll(times); - - for (Entry logEntry : sortedTimes.entrySet()) { - String eventName = logEntry.getKey(); - Integer count = counts.get(eventName); - Long time = logEntry.getValue(); - - long pct = (totalTime > 0) ? ((time * 100) / totalTime) : 0; - log.append(StringUtils.rightPad(eventName + ":", 40) + StringUtils.rightPad(count + " occurrence" + ((count != 1) ? "s" : ""), 20) + StringUtils.rightPad(time + "ms", 12) + pct + "%\n"); - } - - int totalCount = getTotalCount(); - log.append(StringUtils.rightPad("Totals:", 40) + StringUtils.rightPad(totalCount + " occurrence" + ((totalCount != 1) ? "s" : ""), 20) + totalTime + "ms\n"); - return log.toString(); - } - - public void reset() { - counts.clear(); - times.clear(); - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - private class LongComparator implements Comparator { - private Map base; - - public LongComparator(Map base) { - this.base = base; - } - - @Override - public int compare(String a, String b) { - return base.get(b).compareTo(base.get(a)); - } - } -} diff --git a/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoTest.java b/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoTest.java index e54b18245b..4cf983e55f 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoTest.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/JdbcDaoTest.java @@ -10,11 +10,15 @@ package com.mirth.connect.donkey.server.data.jdbc; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -34,16 +38,22 @@ import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Test; +import org.mockito.InOrder; import com.mirth.connect.donkey.model.channel.MetaDataColumn; +import com.mirth.connect.donkey.model.message.ContentType; +import com.mirth.connect.donkey.model.message.MessageContent; import com.mirth.connect.donkey.model.message.attachment.Attachment; import com.mirth.connect.donkey.server.Donkey; import com.mirth.connect.donkey.server.channel.Channel; import com.mirth.connect.donkey.server.channel.Statistics; +import com.mirth.connect.donkey.server.data.DonkeyDaoException; import com.mirth.connect.donkey.server.data.StatisticsUpdater; import com.mirth.connect.donkey.util.SerializerProvider; public class JdbcDaoTest { + private static final String BATCH_CHANNEL_ID = "batchChannel"; + private JdbcDao dao; private Donkey donkey; private Connection connection; @@ -53,7 +63,6 @@ public void before() { donkey = mock(Donkey.class); connection = mock(Connection.class); QuerySource querySource = mock(QuerySource.class); - PreparedStatementSource statementSource = mock(PreparedStatementSource.class); SerializerProvider serializerProvider = mock(SerializerProvider.class); boolean encryptMessageContent = false; boolean encryptAttachments = false; @@ -63,7 +72,7 @@ public void before() { Statistics currentStats = mock(Statistics.class); Statistics totalStats = mock(Statistics.class); String statsServerId = ""; - dao = new JdbcDao(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); + dao = new JdbcDao(donkey, connection, querySource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId); } @Test @@ -387,11 +396,55 @@ public void testUpdateMessageAttachment6() throws Exception { verify(deleteStatement, times(0)).executeUpdate(); } + /** + * Every row has to make it onto the batch, and the batch has to run before the statement is + * closed -- closing it early silently discarded the source content. + */ + @Test + public void insertMessageContentBatchBatchesEveryRowThenExecutesOnce() throws Exception { + PreparedStatement statement = mock(PreparedStatement.class); + JdbcDao batchDao = batchDao(statement); + + batchDao.insertMessageContentBatch(Arrays.asList(content(ContentType.PROCESSED_RAW, "processed raw"), content(ContentType.TRANSFORMED, "transformed"), content(ContentType.ENCODED, "encoded"))); + + InOrder inOrder = inOrder(statement); + inOrder.verify(statement, times(3)).addBatch(); + inOrder.verify(statement).executeBatch(); + inOrder.verify(statement).close(); + } + + /** A batch that fails half way through must execute nothing and still release the statement. */ + @Test + public void insertMessageContentBatchClosesTheStatementWhenBindingFails() throws Exception { + PreparedStatement statement = mock(PreparedStatement.class); + doThrow(new SQLException("no")).when(statement).addBatch(); + JdbcDao batchDao = batchDao(statement); + + try { + batchDao.insertMessageContentBatch(Arrays.asList(content(ContentType.ENCODED, "encoded"))); + fail("Expected a DonkeyDaoException"); + } catch (DonkeyDaoException e) { + // expected + } + + verify(statement, never()).executeBatch(); + verify(statement).close(); + } + + private JdbcDao batchDao(PreparedStatement statement) throws SQLException { + JdbcDao batchDao = spy(dao); + doReturn(statement).when(batchDao).prepareStatement(eq("insertMessageContent"), eq(BATCH_CHANNEL_ID)); + return batchDao; + } + + private static MessageContent content(ContentType contentType, String content) { + return new MessageContent(BATCH_CHANNEL_ID, 1L, 0, contentType, content, "RAW", false); + } + private JdbcDao getDao(String channelId, ResultSet segmentCountResult, PreparedStatement segmentCountStatement, PreparedStatement updateStatement, PreparedStatement insertStatement, PreparedStatement deleteStatement) throws Exception { Donkey donkey = mock(Donkey.class); Connection connection = mock(Connection.class); QuerySource querySource = mock(QuerySource.class); - PreparedStatementSource statementSource = mock(PreparedStatementSource.class); SerializerProvider serializerProvider = mock(SerializerProvider.class); boolean encryptMessageContent = false; boolean encryptAttachments = false; @@ -402,7 +455,7 @@ private JdbcDao getDao(String channelId, ResultSet segmentCountResult, PreparedS Statistics totalStats = mock(Statistics.class); String statsServerId = ""; - JdbcDao dao = spy(new JdbcDao(donkey, connection, querySource, statementSource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId)); + JdbcDao dao = spy(new JdbcDao(donkey, connection, querySource, serializerProvider, encryptMessageContent, encryptAttachments, encryptCustomMetaData, decryptData, statisticsUpdater, currentStats, totalStats, statsServerId)); when(segmentCountStatement.executeQuery()).thenReturn(segmentCountResult); doReturn(segmentCountStatement).when(dao).prepareStatement(eq("selectMessageAttachmentSegmentCount"), eq(channelId)); diff --git a/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/OracleJdbcDaoTest.java b/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/OracleJdbcDaoTest.java deleted file mode 100644 index bb0f8e0c69..0000000000 --- a/donkey/src/test/java/com/mirth/connect/donkey/server/data/jdbc/OracleJdbcDaoTest.java +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -// SPDX-FileCopyrightText: Mitch Gaffigan - -package com.mirth.connect.donkey.server.data.jdbc; - -import static org.mockito.ArgumentMatchers.eq; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.InOrder; - -import com.mirth.connect.donkey.model.message.ContentType; -import com.mirth.connect.donkey.model.message.MessageContent; -import com.mirth.connect.donkey.server.Donkey; -import com.mirth.connect.donkey.server.channel.Statistics; -import com.mirth.connect.donkey.server.data.DonkeyDaoException; -import com.mirth.connect.donkey.server.data.StatisticsUpdater; -import com.mirth.connect.donkey.util.SerializerProvider; - -/** - * Oracle is the only DAO that actually closes statements, so it is the only one where closing - * the wrong statement at the wrong time is observable. - */ -public class OracleJdbcDaoTest { - - private static final String CHANNEL_ID = "abc"; - - private OracleJdbcDao dao; - private PreparedStatement statement; - - @Before - public void before() throws SQLException { - Donkey donkey = mock(Donkey.class); - Connection connection = mock(Connection.class); - QuerySource querySource = mock(QuerySource.class); - PreparedStatementSource statementSource = mock(PreparedStatementSource.class); - SerializerProvider serializerProvider = mock(SerializerProvider.class); - StatisticsUpdater statisticsUpdater = mock(StatisticsUpdater.class); - Statistics currentStats = mock(Statistics.class); - Statistics totalStats = mock(Statistics.class); - - dao = spy(new OracleJdbcDao(donkey, connection, querySource, statementSource, serializerProvider, false, false, false, false, statisticsUpdater, currentStats, totalStats, "")); - - statement = mock(PreparedStatement.class); - doReturn(statement).when(dao).prepareStatement(eq("batchInsertMessageContent"), eq(CHANNEL_ID)); - } - - /** - * The batch lives on the cached statement, so the statement has to survive every - * batchInsertMessageContent() call and only be closed once the batch has been executed. - * Closing it earlier silently discarded the source content on Oracle. - */ - @Test - public void testBatchInsertMessageContentKeepsStatementOpenUntilExecuted() throws SQLException { - dao.batchInsertMessageContent(content(ContentType.PROCESSED_RAW, "processed raw")); - dao.batchInsertMessageContent(content(ContentType.TRANSFORMED, "transformed")); - dao.batchInsertMessageContent(content(ContentType.ENCODED, "encoded")); - - verify(statement, times(3)).addBatch(); - verify(statement, never()).close(); - - dao.executeBatchInsertMessageContent(CHANNEL_ID); - - InOrder inOrder = inOrder(statement); - inOrder.verify(statement, times(3)).addBatch(); - inOrder.verify(statement).executeBatch(); - inOrder.verify(statement).clearBatch(); - inOrder.verify(statement).close(); - } - - /** A failed batch must not be left behind for the next message to execute. */ - @Test - public void testFailedBatchInsertClearsAndClosesTheStatement() throws SQLException { - doThrow(new SQLException("no")).when(statement).addBatch(); - - try { - dao.batchInsertMessageContent(content(ContentType.ENCODED, "encoded")); - fail("Expected a DonkeyDaoException"); - } catch (DonkeyDaoException e) { - // expected - } - - InOrder inOrder = inOrder(statement); - inOrder.verify(statement).clearBatch(); - inOrder.verify(statement).close(); - } - - private static MessageContent content(ContentType contentType, String content) { - return new MessageContent(CHANNEL_ID, 1L, 0, contentType, content, "RAW", false); - } -} diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/ChannelControllerTests.java b/donkey/src/test/java/com/mirth/connect/donkey/test/ChannelControllerTests.java index 4927f9b60c..8193703cb7 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/ChannelControllerTests.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/ChannelControllerTests.java @@ -22,7 +22,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -31,24 +30,20 @@ import com.mirth.connect.donkey.server.StartException; import com.mirth.connect.donkey.server.channel.Channel; import com.mirth.connect.donkey.server.controllers.ChannelController; -import com.mirth.connect.donkey.server.data.timed.TimedDaoFactory; import com.mirth.connect.donkey.test.util.TestSourceConnector; import com.mirth.connect.donkey.test.util.TestUtils; -import com.mirth.connect.donkey.util.ActionTimer; public class ChannelControllerTests { private static int TEST_SIZE = 10; private static String channelId = TestUtils.DEFAULT_CHANNEL_ID; private static String serverId = TestUtils.DEFAULT_SERVER_ID; private static String testMessage = TestUtils.TEST_HL7_MESSAGE; - private static ActionTimer daoTimer = new ActionTimer(); private Logger logger = LogManager.getLogger(this.getClass()); @BeforeClass final public static void beforeClass() throws StartException { Donkey donkey = Donkey.getInstance(); donkey.startEngine(TestUtils.getDonkeyTestConfiguration()); - donkey.setDaoFactory(new TimedDaoFactory(donkey.getDaoFactory(), daoTimer)); } @AfterClass @@ -56,11 +51,6 @@ final public static void afterClass() throws StartException { Donkey.getInstance().stopEngine(); } - @Before - final public void before() { - daoTimer.reset(); - } - /* * Remove the channel corresponding to channelId, if applicable Call getLocalChannelId, assert * that: - The channel row was inserted - All channel message tables were created @@ -84,7 +74,6 @@ final public void testGetLocalChannelId() throws Exception { assertEquals(localChannelId, (long) ChannelController.getInstance().getLocalChannelId(channelId)); } - System.out.println(daoTimer.getLog()); } finally { ChannelController.getInstance().removeChannel(channelId); } @@ -122,7 +111,6 @@ public final void testGetTotals() throws Exception { assertEquals(TestUtils.getChannelStatistics(channel.getChannelId()), ChannelController.getInstance().getStatistics().getChannelStats(channelId)); } - System.out.println(daoTimer.getLog()); } finally { if (channel != null) { channel.stop(); @@ -192,7 +180,6 @@ public final void testGetStatistics() throws Exception { assertEquals(subtractedStats, vmStats); } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/DonkeyDaoTests.java b/donkey/src/test/java/com/mirth/connect/donkey/test/DonkeyDaoTests.java index c7a4f8569c..914be1ff57 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/DonkeyDaoTests.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/DonkeyDaoTests.java @@ -28,7 +28,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -53,11 +52,9 @@ import com.mirth.connect.donkey.server.data.DonkeyDaoFactory; import com.mirth.connect.donkey.server.data.buffered.BufferedDaoFactory; import com.mirth.connect.donkey.server.data.jdbc.JdbcDaoFactory; -import com.mirth.connect.donkey.server.data.timed.TimedDaoFactory; import com.mirth.connect.donkey.test.util.TestChannel; import com.mirth.connect.donkey.test.util.TestSourceConnector; import com.mirth.connect.donkey.test.util.TestUtils; -import com.mirth.connect.donkey.util.ActionTimer; import com.mirth.connect.donkey.util.Serializer; import com.mirth.connect.donkey.util.SerializerProvider; import com.mirth.connect.donkey.util.xstream.XStreamSerializer; @@ -69,7 +66,6 @@ public class DonkeyDaoTests { private static String serverId = TestUtils.DEFAULT_SERVER_ID; private static String testMessage = TestUtils.TEST_HL7_MESSAGE; private static DonkeyDaoFactory daoFactory; - private static ActionTimer daoTimer = new ActionTimer(); private Logger logger = LogManager.getLogger(this.getClass()); @@ -82,7 +78,7 @@ final public static void beforeClass() throws StartException { ((JdbcDaoFactory) donkey.getDaoFactory()).setStatsServerId(serverId); } - daoFactory = new BufferedDaoFactory(new TimedDaoFactory(donkey.getDaoFactory(), daoTimer), new SerializerProvider() { + daoFactory = new BufferedDaoFactory(donkey.getDaoFactory(), new SerializerProvider() { @Override public Serializer getSerializer(Integer metaDataId) { return new XStreamSerializer(); @@ -98,11 +94,6 @@ final public static void afterClass() throws StartException { Donkey.getInstance().stopEngine(); } - @Before - final public void before() { - daoTimer.reset(); - } - /* * Create and insert messages, assert that: - The row was inserted correctly - The server ID was * inserted correctly - The received_date column was initialized - The processed column was @@ -161,7 +152,6 @@ public void testInsertMessage() throws Exception { } } - System.out.println(daoTimer.getLog()); } /* @@ -198,14 +188,10 @@ public void testInsertConnectorMessage() throws Exception { connectorMessage.setResponseMap(responseMap); connectorMessage.setProcessingError("errors"); - double averageTime = 0; - logger.info("Testing DonkeyDao.insertConnectorMessage..."); long localChannelId = ChannelController.getInstance().getLocalChannelId(channelId); - daoTimer.reset(); - for (int i = 1; i <= TEST_SIZE; i++) { logger.debug("testInsertConnectorMessage #" + i); connectorMessage.setMetaDataId(i); @@ -259,8 +245,7 @@ public void testInsertConnectorMessage() throws Exception { connection.close(); } - averageTime = daoTimer.getTotalTime() / TEST_SIZE; - logger.info("Success, average transaction time: " + averageTime + " ms"); + logger.info("Success"); } finally { TestUtils.close(result); TestUtils.close(statement); @@ -316,7 +301,6 @@ public final void testInsertMessageContent() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { dao.close(); } @@ -348,7 +332,6 @@ public final void testInsertMessageAttachment() throws Exception { TestUtils.assertAttachmentExists(channel.getChannelId(), sourceMessage.getMessageId(), attachment); } - System.out.println(daoTimer.getLog()); } finally { dao.close(); } @@ -415,7 +398,6 @@ public final void testInsertMetaData() throws Exception { TestUtils.compareMetaDataMaps(channel.getMetaDataColumns(), destinationMap, TestUtils.getCustomMetaData(channel.getChannelId(), sourceMessage.getMessageId(), 1)); } - System.out.println(daoTimer.getLog()); } finally { dao.close(); channel.undeploy(); @@ -450,7 +432,6 @@ public final void testStoreMessageContent() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { dao.close(); } @@ -524,7 +505,6 @@ public final void testUpdateStatus() throws Exception { connection.close(); } - System.out.println(daoTimer.getLog()); } finally { TestUtils.close(result); TestUtils.close(statement); @@ -624,7 +604,6 @@ public final void testUpdateMaps() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { TestUtils.close(connection); } @@ -661,7 +640,6 @@ public final void testUpdateResponseMap() throws Exception { assertTrue(responseMap.equals(insertedResponseMap)); } - System.out.println(daoTimer.getLog()); } finally { dao.close(); } @@ -696,7 +674,6 @@ public final void testMarkAsProcessed() throws Exception { assertTrue(TestUtils.isMessageProcessed(channel.getChannelId(), sourceMessage.getMessageId())); } - System.out.println(daoTimer.getLog()); } finally { dao.close(); } @@ -870,7 +847,6 @@ public final void testDeleteConnectorMessages() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); @@ -951,7 +927,6 @@ public final void testDeleteAllMessages() throws Exception { result.close(); statement.close(); - System.out.println(daoTimer.getLog()); } finally { TestUtils.close(result); TestUtils.close(statement); @@ -1020,7 +995,6 @@ public final void testCreateChannel() throws Exception { } } - System.out.println(daoTimer.getLog()); } /* @@ -1124,7 +1098,6 @@ public final void testRemoveChannel() throws Exception { assertFalse(messageStatisticsTableExists); } - System.out.println(daoTimer.getLog()); } /* @@ -1164,7 +1137,6 @@ public final void testAddMetaDataColumn() throws Exception { assertEquals(metaDataColumns, TestUtils.getExistingMetaDataColumns(channel.getChannelId())); } - System.out.println(daoTimer.getLog()); } finally { channel.undeploy(); } @@ -1217,7 +1189,6 @@ public final void testRemoveMetaDataColumn() throws Exception { assertFalse(databaseMetaDataColumns.contains(metaDataColumn)); } - System.out.println(daoTimer.getLog()); } finally { channel.undeploy(); } @@ -1295,7 +1266,6 @@ public final void testSelectMaxLocalChannelId() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { for (String channelId : localChannelIds.keySet()) { ChannelController.getInstance().removeChannel(channelId); @@ -1380,7 +1350,6 @@ public final void testGetLocalChannelIds() throws Exception { TestUtils.close(dao); } - System.out.println(daoTimer.getLog()); } finally { Connection connection = null; PreparedStatement statement = null; @@ -1474,7 +1443,6 @@ public final void testGetMaxMessageId() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); @@ -1649,7 +1617,6 @@ public final void testGetConnectorMessages() throws Exception { } ChannelController.getInstance().deleteAllMessages(channel.getChannelId()); - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); @@ -1701,7 +1668,6 @@ public final void testGetConnectorMessageCount() throws Exception { } } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); @@ -1754,7 +1720,6 @@ public final void testGetUnfinishedMessages() throws Exception { TestUtils.assertMessagesEqual(messages.get(i), databaseMessages.get(i)); } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); @@ -1797,7 +1762,6 @@ public final void testGetMetaDataColumns() throws Exception { assertTrue(column.getName(), metaDataColumns.contains(column)); } - System.out.println(daoTimer.getLog()); } finally { channel.undeploy(); } @@ -1841,43 +1805,12 @@ public final void testGetChannelStatistics() throws Exception { assertEquals(TestUtils.getChannelStatistics(channel.getChannelId()), ChannelController.getInstance().getStatistics().getChannelStats(channel.getChannelId())); } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); } } - /** - * Sends messages through 5 channels with (maxConnections * 2) asynchronous destinations for 10 - * seconds and verifies that the number of connection caches created is not greater than the - * maximum number of connections in the connection pool - * - * @throws Exception - */ - @Test - public final void testJdbcDaoStatementCache() throws Exception { - DonkeyDaoFactory daoFactory = ((TimedDaoFactory) ((BufferedDaoFactory) Donkey.getInstance().getDaoFactory()).getDelegateFactory()).getDelegateFactory(); - - if (!(daoFactory instanceof JdbcDaoFactory)) { - System.out.println("Skipping testJdbcDaoStatementCache() because the current DonkeyDaoFactory is not an instance of JdbcDaoFactory"); - return; - } - - if (Donkey.getInstance().getConfiguration().getDonkeyProperties().get("database").equals("derby")) { - System.out.println("Skipping testJdbcDaoStatementCache(), not applicable for Derby"); - return; - } - - Integer maxConnections = Integer.parseInt(Donkey.getInstance().getConfiguration().getDonkeyProperties().getProperty("database.max-connections")); - - JdbcDaoFactory jdbcDaoFactory = (JdbcDaoFactory) daoFactory; - - TestUtils.runChannelTest(testMessage, channelId, serverId, "testJdbcDaoStatementCache", 5, maxConnections * 2, 1, true, null, 10000, null, new StorageSettings()); - - assertTrue(jdbcDaoFactory.getStatementSources().size() + " connection caches were created, but the max # of connections is " + maxConnections, jdbcDaoFactory.getStatementSources().size() <= maxConnections); - } - // @Test // public final void testHalt() throws Exception { // TestChannel channel = TestUtils.createDefaultChannel(channelId, serverId); diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/MessageControllerTests.java b/donkey/src/test/java/com/mirth/connect/donkey/test/MessageControllerTests.java index e9dce58d9e..659cc5d558 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/MessageControllerTests.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/MessageControllerTests.java @@ -22,7 +22,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -38,25 +37,21 @@ import com.mirth.connect.donkey.server.controllers.ChannelController; import com.mirth.connect.donkey.server.controllers.MessageController; import com.mirth.connect.donkey.server.data.DonkeyDao; -import com.mirth.connect.donkey.server.data.timed.TimedDaoFactory; import com.mirth.connect.donkey.server.queue.ConnectorMessageQueueDataSource; import com.mirth.connect.donkey.test.util.TestChannel; import com.mirth.connect.donkey.test.util.TestUtils; -import com.mirth.connect.donkey.util.ActionTimer; public class MessageControllerTests { private static int TEST_SIZE = 20; private static String channelId = TestUtils.DEFAULT_CHANNEL_ID; private static String serverId = TestUtils.DEFAULT_SERVER_ID; private static String testMessage = TestUtils.TEST_HL7_MESSAGE; - private static ActionTimer daoTimer = new ActionTimer(); private Logger logger = LogManager.getLogger(this.getClass()); @BeforeClass final public static void beforeClass() throws StartException { Donkey donkey = Donkey.getInstance(); donkey.startEngine(TestUtils.getDonkeyTestConfiguration()); - donkey.setDaoFactory(new TimedDaoFactory(donkey.getDaoFactory(), daoTimer)); } @AfterClass @@ -64,11 +59,6 @@ final public static void afterClass() throws StartException { Donkey.getInstance().stopEngine(); } - @Before - final public void before() { - daoTimer.reset(); - } - /* * Create source connector messages For each message created, assert that: - The raw content was * set - The channel map was set - The Message was inserted into the database - The source @@ -120,7 +110,6 @@ public void testCreateNewMessage() throws Exception { TestUtils.assertMessageContentExists(sourceMessage.getRaw()); } - System.out.println(daoTimer.getLog()); } finally { ChannelController.getInstance().removeChannel(channel.getChannelId()); } diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/PerformanceTests.java b/donkey/src/test/java/com/mirth/connect/donkey/test/PerformanceTests.java index aee3b23976..749cd9d5c5 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/PerformanceTests.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/PerformanceTests.java @@ -17,7 +17,6 @@ import org.apache.commons.io.FileUtils; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -27,14 +26,12 @@ import com.mirth.connect.donkey.server.channel.Channel; import com.mirth.connect.donkey.server.channel.DestinationChainProvider; import com.mirth.connect.donkey.server.channel.DispatchResult; -import com.mirth.connect.donkey.server.data.timed.TimedDaoFactory; import com.mirth.connect.donkey.test.util.TestChannel; import com.mirth.connect.donkey.test.util.TestChannelWriter; import com.mirth.connect.donkey.test.util.TestConnectorProperties; import com.mirth.connect.donkey.test.util.TestDataType; import com.mirth.connect.donkey.test.util.TestUtils; import com.mirth.connect.donkey.test.util.TestUtils.MessageStorageMode; -import com.mirth.connect.donkey.util.ActionTimer; public class PerformanceTests { private final static String TEST_MESSAGE = "src/test/java/com/mirth/connect/donkey/test/hl7/large.hl7"; @@ -47,7 +44,6 @@ public class PerformanceTests { private final static boolean DEFAULT_WAIT_FOR_DESTINATIONS = true; private static String testMessage; - private static ActionTimer daoTimer = null; private static String channelId = TestUtils.DEFAULT_CHANNEL_ID; private static String serverId = TestUtils.DEFAULT_SERVER_ID; @@ -57,10 +53,6 @@ final public static void beforeClass() throws Exception { Donkey donkey = Donkey.getInstance(); donkey.startEngine(TestUtils.getDonkeyTestConfiguration()); - - if (daoTimer != null) { - donkey.setDaoFactory(new TimedDaoFactory(donkey.getDaoFactory(), daoTimer)); - } } @AfterClass @@ -68,13 +60,6 @@ final public static void afterClass() throws StartException { Donkey.getInstance().stopEngine(); } - @Before - final public void before() { - if (daoTimer != null) { - daoTimer.reset(); - } - } - @Test public final void testDevelopment() throws Exception { testStorageMode(MessageStorageMode.DEVELOPMENT); diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/RecoveryTests.java b/donkey/src/test/java/com/mirth/connect/donkey/test/RecoveryTests.java index b346494e30..a07dc17218 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/RecoveryTests.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/RecoveryTests.java @@ -24,7 +24,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.AfterClass; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -44,13 +43,11 @@ import com.mirth.connect.donkey.server.data.DonkeyDao; import com.mirth.connect.donkey.server.data.DonkeyDaoFactory; import com.mirth.connect.donkey.server.data.buffered.BufferedDaoFactory; -import com.mirth.connect.donkey.server.data.timed.TimedDaoFactory; import com.mirth.connect.donkey.test.util.TestChannel; import com.mirth.connect.donkey.test.util.TestDataType; import com.mirth.connect.donkey.test.util.TestDestinationConnector; import com.mirth.connect.donkey.test.util.TestSourceConnector; import com.mirth.connect.donkey.test.util.TestUtils; -import com.mirth.connect.donkey.util.ActionTimer; import com.mirth.connect.donkey.util.Serializer; import com.mirth.connect.donkey.util.SerializerProvider; import com.mirth.connect.donkey.util.xstream.XStreamSerializer; @@ -61,7 +58,6 @@ public class RecoveryTests { private static String channelName = TestUtils.DEFAULT_CHANNEL_ID; private static String serverId = TestUtils.DEFAULT_SERVER_ID; private static RawMessage testMessage = new RawMessage(TestUtils.TEST_HL7_MESSAGE); - private static ActionTimer daoTimer = new ActionTimer(); private static DonkeyDaoFactory daoFactory; private Logger logger = LogManager.getLogger(this.getClass()); @@ -70,7 +66,7 @@ final public static void beforeClass() throws StartException { Donkey donkey = Donkey.getInstance(); donkey.startEngine(TestUtils.getDonkeyTestConfiguration()); - daoFactory = new BufferedDaoFactory(new TimedDaoFactory(donkey.getDaoFactory(), daoTimer), new SerializerProvider() { + daoFactory = new BufferedDaoFactory(donkey.getDaoFactory(), new SerializerProvider() { @Override public Serializer getSerializer(Integer metaDataId) { return new XStreamSerializer(); @@ -84,11 +80,6 @@ final public static void afterClass() throws StartException { Donkey.getInstance().stopEngine(); } - @Before - final public void before() { - daoTimer.reset(); - } - @Test public final void testSourceRecovery() throws Exception { final int testSize = TEST_SIZE; @@ -297,7 +288,6 @@ public final void testProcessedFalseRecovery() throws Exception { assertTrue(TestUtils.isMessageProcessed(channel.getChannelId(), messageId)); } - System.out.println(daoTimer.getLog()); } finally { channel.stop(); channel.undeploy(); diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDao.java b/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDao.java index 6cd1c20c16..959ae0c558 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDao.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDao.java @@ -18,7 +18,6 @@ import com.mirth.connect.donkey.server.channel.Statistics; import com.mirth.connect.donkey.server.data.DonkeyDaoException; import com.mirth.connect.donkey.server.data.jdbc.JdbcDao; -import com.mirth.connect.donkey.server.data.jdbc.PreparedStatementSource; import com.mirth.connect.donkey.server.data.jdbc.QuerySource; import com.mirth.connect.donkey.util.SerializerProvider; @@ -27,8 +26,8 @@ public class TestDao extends JdbcDao { private int hangPct = 0; private int hangMillis = 0; - public TestDao(Donkey donkey, Connection connection, QuerySource querySource, PreparedStatementSource statementSource, SerializerProvider serializerProvider, Statistics currentStats, Statistics totalStats, String statsServerId, int errorPct, int hangPct, int hangMillis) { - super(donkey, connection, querySource, statementSource, serializerProvider, false, false, false, true, null, currentStats, totalStats, statsServerId); + public TestDao(Donkey donkey, Connection connection, QuerySource querySource, SerializerProvider serializerProvider, Statistics currentStats, Statistics totalStats, String statsServerId, int errorPct, int hangPct, int hangMillis) { + super(donkey, connection, querySource, serializerProvider, false, false, false, true, null, currentStats, totalStats, statsServerId); this.errorPct = errorPct; this.hangPct = hangPct; this.hangMillis = hangMillis; diff --git a/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDaoFactory.java b/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDaoFactory.java index c5c1cd3602..ff89b55500 100644 --- a/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDaoFactory.java +++ b/donkey/src/test/java/com/mirth/connect/donkey/test/util/TestDaoFactory.java @@ -11,21 +11,12 @@ import java.sql.Connection; import java.sql.SQLException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import com.mirth.connect.donkey.server.Donkey; import com.mirth.connect.donkey.server.controllers.ChannelController; import com.mirth.connect.donkey.server.data.DonkeyDaoException; -import com.mirth.connect.donkey.server.data.jdbc.CachedPreparedStatementSource; -import com.mirth.connect.donkey.server.data.jdbc.ConnectionPool; import com.mirth.connect.donkey.server.data.jdbc.JdbcDao; import com.mirth.connect.donkey.server.data.jdbc.JdbcDaoFactory; -import com.mirth.connect.donkey.server.data.jdbc.PooledConnection; -import com.mirth.connect.donkey.server.data.jdbc.PreparedStatementSource; import com.mirth.connect.donkey.util.Serializer; import com.mirth.connect.donkey.util.SerializerProvider; import com.mirth.connect.donkey.util.xstream.XStreamSerializer; @@ -33,8 +24,6 @@ public class TestDaoFactory extends JdbcDaoFactory { private Donkey donkey; private ChannelController channelController; - private Logger logger = LogManager.getLogger(getClass()); - private Map statementSources = new ConcurrentHashMap(); private SerializerProvider serializerProvider; private int errorPct = 0; private int hangPct = 0; @@ -77,42 +66,14 @@ public void setHangMillis(int hangMillis) { @Override public JdbcDao getDao() { - ConnectionPool connectionPool = getConnectionPool(); - PooledConnection pooledConnection; + Connection connection; try { - pooledConnection = connectionPool.getConnection(); + connection = getConnectionPool().getConnection(); } catch (SQLException e) { throw new DonkeyDaoException(e); } - PreparedStatementSource statementSource = null; - Connection connection = pooledConnection.getConnection(); - Connection internalConnection = pooledConnection.getInternalConnection(); - statementSource = statementSources.get(internalConnection); - - if (statementSource == null) { - statementSource = new CachedPreparedStatementSource(internalConnection, getQuerySource()); - statementSources.put(internalConnection, statementSource); - - Integer maxConnections = connectionPool.getMaxConnections(); - - // TODO: find a more efficient way of cleaning up old connections - if (maxConnections == null || statementSources.size() > maxConnections) { - logger.debug("cleaning up prepared statement cache"); - - try { - for (Connection currentConnection : statementSources.keySet()) { - if (currentConnection.isClosed()) { - statementSources.remove(currentConnection); - } - } - } catch (SQLException e) { - throw new DonkeyDaoException(e); - } - } - } - - return new TestDao(donkey, connection, getQuerySource(), statementSource, serializerProvider, channelController.getStatistics(), channelController.getTotalStatistics(), getStatsServerId(), errorPct, hangPct, hangMillis); + return new TestDao(donkey, connection, getQuerySource(), serializerProvider, channelController.getStatistics(), channelController.getTotalStatistics(), getStatsServerId(), errorPct, hangPct, hangMillis); } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9eb0f3a5db..1b7f550d88 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -80,7 +80,6 @@ commons-collections = { module = "commons-collections:commons-collections", vers commons-collections4 = { module = "org.apache.commons:commons-collections4", version = "4.4" } commons-compress = { module = "org.apache.commons:commons-compress", version = "1.28.0" } commons-configuration2 = { module = "org.apache.commons:commons-configuration2", version = "2.15.0" } -commons-dbcp2 = { module = "org.apache.commons:commons-dbcp2", version = "2.0.1" } commons-dbutils = { module = "commons-dbutils:commons-dbutils", version = "1.7" } commons-digester3 = { module = "org.apache.commons:commons-digester3", version = "3.2" } commons-el = { module = "commons-el:commons-el", version = "1.0" } @@ -395,7 +394,6 @@ donkey-main = [ "commons-beanutils", "commons-codec", "commons-collections4", - "commons-dbcp2", "commons-dbutils", "commons-io", "commons-lang3", @@ -497,7 +495,6 @@ server-main = [ "commons-collections4", "commons-compress", "commons-configuration2", - "commons-dbcp2", "commons-dbutils", "commons-digester3", "commons-el", diff --git a/gradle/vendored-layout.json b/gradle/vendored-layout.json index 7bffae2a4d..66d6c8676f 100644 --- a/gradle/vendored-layout.json +++ b/gradle/vendored-layout.json @@ -142,7 +142,6 @@ "commons-io:commons-io": "commons", "commons-logging:commons-logging": "commons", "org.apache.commons:commons-collections4": "commons", - "org.apache.commons:commons-dbcp2": "commons", "org.apache.commons:commons-lang3": "commons", "org.apache.commons:commons-math3": "commons", "org.apache.commons:commons-pool2": "commons", @@ -252,7 +251,6 @@ "org.apache.commons:commons-collections4": "commons", "org.apache.commons:commons-compress": "commons", "org.apache.commons:commons-configuration2": "commons", - "org.apache.commons:commons-dbcp2": "commons", "org.apache.commons:commons-digester3": "commons", "org.apache.commons:commons-email": "commons", "org.apache.commons:commons-lang3": "commons", diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index a55f913c97..42ef5a89d7 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1449,14 +1449,6 @@ - - - - - - - - diff --git a/server/conf/base_includes.vmoptions b/server/conf/base_includes.vmoptions index a917ee6069..d458fb1c35 100644 --- a/server/conf/base_includes.vmoptions +++ b/server/conf/base_includes.vmoptions @@ -4,6 +4,7 @@ # -server -Xmx256m +-Dderby.language.statementCacheSize=1000 -Djava.awt.headless=true -Dapple.awt.UIElement=true -Djavax.xml.accessExternalDTD= diff --git a/server/src/test/java/com/mirth/connect/server/DatabaseConnectionPoolTests.java b/server/src/test/java/com/mirth/connect/server/DatabaseConnectionPoolTests.java index 9c2a60fc19..ac39ab140c 100644 --- a/server/src/test/java/com/mirth/connect/server/DatabaseConnectionPoolTests.java +++ b/server/src/test/java/com/mirth/connect/server/DatabaseConnectionPoolTests.java @@ -48,7 +48,6 @@ import com.mirth.connect.donkey.server.DonkeyConnectionPools; import com.mirth.connect.donkey.server.data.ChannelDoesNotExistException; import com.mirth.connect.donkey.server.data.jdbc.ConnectionPool; -import com.mirth.connect.donkey.server.data.jdbc.PooledConnection; import com.mirth.connect.model.Channel; import com.mirth.connect.model.ChannelGroup; import com.mirth.connect.model.ChannelHeader; @@ -332,8 +331,8 @@ private void setup(boolean splitReadWrite, boolean writePoolCache) throws Except if (!USE_REAL_DATABASE_CONNECTIONS) { connection = createConnection(databaseSettings.getDatabase()); readOnlyConnection = createConnection(StringUtils.defaultIfBlank(databaseSettings.getDatabaseReadOnly(), databaseSettings.getDatabase())); - doReturn(createPool(connection)).when(donkeyCP).createConnectionPool(anyString(), anyString(), anyString(), anyString(), anyString(), any(), anyBoolean(), anyString(), anyInt(), eq(false)); - doReturn(createPool(readOnlyConnection)).when(donkeyCP).createConnectionPool(anyString(), anyString(), anyString(), anyString(), anyString(), any(), anyBoolean(), anyString(), anyInt(), eq(true)); + doReturn(createPool(connection)).when(donkeyCP).createConnectionPool(anyString(), anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), anyInt(), eq(false)); + doReturn(createPool(readOnlyConnection)).when(donkeyCP).createConnectionPool(anyString(), anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), anyInt(), eq(true)); } Injector donkeyConnectionPoolsInjector = Guice.createInjector(new AbstractModule() { @@ -422,8 +421,7 @@ private Connection createConnection(String database) throws Exception { private ConnectionPool createPool(Connection connection) throws Exception { ConnectionPool connectionPool = mock(ConnectionPool.class); - when(connectionPool.getConnection()).thenReturn(new PooledConnection(connection, connection)); - when(connectionPool.getMaxConnections()).thenReturn(20); + when(connectionPool.getConnection()).thenReturn(connection); DataSource dataSource = mock(DataSource.class); when(dataSource.getConnection()).thenReturn(connection); when(dataSource.getConnection(anyString(), anyString())).thenReturn(connection);