Skip to content

Commit

Permalink
Add plain JDBC ApplicationErrorDao implementation
Browse files Browse the repository at this point in the history
* Add JdbcApplicationErrorDao, a plain JDBC implementation of
  ApplicationErrorDao
* Since the logic to map from a ResultSet is identical for the
  JDBC and JDBI implementations, move that logic from the
  Jdbi3ApplicationErrorRowMapper into ApplicationErrorJdbc in
  a new method 'mapFrom(ResultSet)'. Also, fix how the port
  is set, using rs.getInt instead of intValueOrNull, since
  the port field in ApplicationError is an int, not Integer
* Add new constructor accepting only a Throwable to
  ApplicationErrorJdbc.ApplicationErrorJdbcException
* Add several new helper methods to ApplicationErrorJdbc
  for the JDBC implementation, nextOrThrow and shutdownH2Database
* Add abstract base test class, AbstractJdbcApplicationErrorDaoTest,
  and two subclasses for testing against H2 and Postgres
* Make sure to shut down the in-memory H2 database in both
  H2Jdbi3ApplicationErrorDaoTest and H2JdbcApplicationErrorDaoTest.
  Otherwise, if the H2 JDBI test runs after the JDBC one, the
  tests fail because they expect the database to be empty.
  By shutting the in-memory database down, we ensure the tests
  are completely isolated.

Misc:

* Remove two redundant warning suppression annotations from
  ErrorContextUtilitiesTest

Closes #248
  • Loading branch information
sleberknight committed Nov 13, 2023
1 parent 41c00b4 commit fe67efb
Show file tree
Hide file tree
Showing 9 changed files with 612 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.kiwiproject.dropwizard.error.dao;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.isNull;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.startsWithAny;
import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotNull;
import static org.kiwiproject.base.KiwiStrings.format;
import static org.kiwiproject.jdbc.KiwiJdbc.utcZonedDateTimeFromTimestamp;

import com.google.common.annotations.VisibleForTesting;
import io.dropwizard.db.DataSourceFactory;
Expand All @@ -20,10 +22,13 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.h2.jdbcx.JdbcDataSource;
import org.kiwiproject.dropwizard.error.model.ApplicationError;
import org.kiwiproject.dropwizard.error.model.DataStoreType;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Locale;

Expand Down Expand Up @@ -192,10 +197,44 @@ private static boolean isNotH2AutomaticMixedMode(String url) {
return !url.toUpperCase(Locale.US).contains(H2_AUTOMATIC_MIXED_MODE);
}

public static ApplicationError mapFrom(ResultSet rs) throws SQLException {
return ApplicationError.builder()
.id(rs.getLong("id"))
.createdAt(utcZonedDateTimeFromTimestamp(rs, "created_at"))
.updatedAt(utcZonedDateTimeFromTimestamp(rs, "updated_at"))
.numTimesOccurred(rs.getInt("num_times_occurred"))
.description(rs.getString("description"))
.exceptionType(rs.getString("exception_type"))
.exceptionMessage(rs.getString("exception_message"))
.exceptionCauseType(rs.getString("exception_cause_type"))
.exceptionCauseMessage(rs.getString("exception_cause_message"))
.stackTrace(rs.getString("stack_trace"))
.resolved(rs.getBoolean("resolved"))
.hostName(rs.getString("host_name"))
.ipAddress(rs.getString("ip_address"))
.port(rs.getInt("port"))
.build();
}

public static void nextOrThrow(ResultSet rs) throws SQLException {
checkState(rs.next(), "ResultSet.next() returned false");
}

@SuppressWarnings({ "SqlDialectInspection", "SqlNoDataSourceInspection" })
public static void shutdownH2Database(JdbcDataSource h2DataSource) throws SQLException {
try (var conn = h2DataSource.getConnection(); var stmt = conn.createStatement()) {
stmt.executeUpdate("shutdown");
}
}

/**
* Runtime exception wrapper around JDBC-related exceptions, e.g. {@link SQLException}.
*/
public static class ApplicationErrorJdbcException extends RuntimeException {
public ApplicationErrorJdbcException(Throwable cause) {
super(cause);
}

ApplicationErrorJdbcException(String message, Throwable cause) {
super(message, cause);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package org.kiwiproject.dropwizard.error.dao.jdbi3;

import static org.kiwiproject.jdbc.KiwiJdbc.intValueOrNull;
import static org.kiwiproject.jdbc.KiwiJdbc.utcZonedDateTimeFromTimestamp;

import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.statement.StatementContext;
import org.kiwiproject.dropwizard.error.dao.ApplicationErrorJdbc;
import org.kiwiproject.dropwizard.error.model.ApplicationError;

import java.sql.ResultSet;
Expand All @@ -17,21 +15,6 @@ public class Jdbi3ApplicationErrorRowMapper implements RowMapper<ApplicationErro

@Override
public ApplicationError map(ResultSet rs, StatementContext ctx) throws SQLException {
return ApplicationError.builder()
.id(rs.getLong("id"))
.createdAt(utcZonedDateTimeFromTimestamp(rs, "created_at"))
.updatedAt(utcZonedDateTimeFromTimestamp(rs, "updated_at"))
.numTimesOccurred(rs.getInt("num_times_occurred"))
.description(rs.getString("description"))
.exceptionType(rs.getString("exception_type"))
.exceptionMessage(rs.getString("exception_message"))
.exceptionCauseType(rs.getString("exception_cause_type"))
.exceptionCauseMessage(rs.getString("exception_cause_message"))
.stackTrace(rs.getString("stack_trace"))
.resolved(rs.getBoolean("resolved"))
.hostName(rs.getString("host_name"))
.ipAddress(rs.getString("ip_address"))
.port(intValueOrNull(rs, "port"))
.build();
return ApplicationErrorJdbc.mapFrom(rs);
}
}
Loading

0 comments on commit fe67efb

Please sign in to comment.