diff --git a/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java b/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java index 5c2f87666..4c4941ddf 100644 --- a/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java +++ b/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java @@ -29,7 +29,6 @@ import de.rwth.idsg.steve.service.DummyReleaseCheckService; import de.rwth.idsg.steve.service.GithubReleaseCheckService; import de.rwth.idsg.steve.service.ReleaseCheckService; -import de.rwth.idsg.steve.utils.DateTimeUtils; import de.rwth.idsg.steve.utils.InternetChecker; import lombok.extern.slf4j.Slf4j; import org.jooq.DSLContext; @@ -41,8 +40,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; import org.springframework.core.Ordered; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.converter.HttpMessageConverter; @@ -60,6 +57,8 @@ import jakarta.annotation.PreDestroy; import jakarta.validation.Validator; + +import javax.sql.DataSource; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; @@ -82,13 +81,13 @@ @ComponentScan("de.rwth.idsg.steve") public class BeanConfiguration implements WebMvcConfigurer { - private HikariDataSource dataSource; private ScheduledThreadPoolExecutor executor; /** * https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration */ - private void initDataSource() { + @Bean + public DataSource dataSource() { SteveConfiguration.DB dbConfig = CONFIG.getDb(); HikariConfig hc = new HikariConfig(); @@ -110,7 +109,7 @@ private void initDataSource() { // https://github.com/steve-community/steve/issues/736 hc.setMaxLifetime(580_000); - dataSource = new HikariDataSource(hc); + return new HikariDataSource(hc); } /** @@ -126,9 +125,7 @@ private void initDataSource() { * - http://stackoverflow.com/questions/32848865/jooq-dslcontext-correct-autowiring-with-spring */ @Bean - public DSLContext dslContext() { - initDataSource(); - + public DSLContext dslContext(DataSource dataSource) { Settings settings = new Settings() // Normally, the records are "attached" to the Configuration that created (i.e. fetch/insert) them. // This means that they hold an internal reference to the same database connection that was used. @@ -176,17 +173,8 @@ public ReleaseCheckService releaseCheckService() { } } - @EventListener - public void afterStart(ContextRefreshedEvent event) { - DateTimeUtils.checkJavaAndMySQLOffsets(dslContext()); - } - @PreDestroy public void shutDown() { - if (dataSource != null) { - dataSource.close(); - } - if (executor != null) { gracefulShutDown(executor); } diff --git a/src/main/java/de/rwth/idsg/steve/repository/GenericRepository.java b/src/main/java/de/rwth/idsg/steve/repository/GenericRepository.java index 0b976abb1..3c2ab19ac 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/GenericRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/GenericRepository.java @@ -26,6 +26,9 @@ * @since 19.08.2014 */ public interface GenericRepository { + + void checkJavaAndMySQLOffsets(); + Statistics getStats(); /** diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/GenericRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/GenericRepositoryImpl.java index 1c458b059..977c626bd 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/GenericRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/GenericRepositoryImpl.java @@ -18,6 +18,7 @@ */ package de.rwth.idsg.steve.repository.impl; +import de.rwth.idsg.steve.SteveException; import de.rwth.idsg.steve.repository.GenericRepository; import de.rwth.idsg.steve.repository.ReservationStatus; import de.rwth.idsg.steve.repository.dto.DbVersion; @@ -26,13 +27,19 @@ import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.jooq.DSLContext; +import org.jooq.DatePart; import org.jooq.Field; import org.jooq.Record2; import org.jooq.Record8; +import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Repository; import static de.rwth.idsg.steve.utils.CustomDSL.date; +import static de.rwth.idsg.steve.utils.CustomDSL.timestampDiff; +import static de.rwth.idsg.steve.utils.CustomDSL.utcTimestamp; import static jooq.steve.db.Tables.RESERVATION; import static jooq.steve.db.Tables.TRANSACTION; import static jooq.steve.db.tables.ChargeBox.CHARGE_BOX; @@ -52,6 +59,25 @@ public class GenericRepositoryImpl implements GenericRepository { @Autowired private DSLContext ctx; + @EventListener + public void afterStart(ContextRefreshedEvent event) { + checkJavaAndMySQLOffsets(); + } + + @Override + public void checkJavaAndMySQLOffsets() { + long java = DateTimeUtils.getOffsetFromUtcInSeconds(); + + long sql = ctx.select(timestampDiff(DatePart.SECOND, utcTimestamp(), DSL.currentTimestamp())) + .fetchOne() + .getValue(0, Long.class); + + if (sql != java) { + throw new SteveException("MySQL and Java are not using the same time zone. " + + "Java offset in seconds (%s) != MySQL offset in seconds (%s)", java, sql); + } + } + @Override public Statistics getStats() { DateTime now = DateTime.now(); diff --git a/src/main/java/de/rwth/idsg/steve/utils/CustomDSL.java b/src/main/java/de/rwth/idsg/steve/utils/CustomDSL.java index 61ed10b8a..575310525 100644 --- a/src/main/java/de/rwth/idsg/steve/utils/CustomDSL.java +++ b/src/main/java/de/rwth/idsg/steve/utils/CustomDSL.java @@ -22,7 +22,6 @@ import lombok.NoArgsConstructor; import org.joda.time.DateTime; import org.jooq.Condition; -import org.jooq.DSLContext; import org.jooq.DataType; import org.jooq.DatePart; import org.jooq.Field; @@ -71,24 +70,14 @@ public static Condition includes(Field field, String input) { return field.like("%" + input + "%"); } - public static Long selectOffsetFromUtcInSeconds(DSLContext ctx) { - return ctx.select(timestampDiffBetweenUtcAndCurrent(DatePart.SECOND)) - .fetchOne() - .getValue(0, Long.class); - } - - private static Field timestampDiffBetweenUtcAndCurrent(DatePart part) { - return timestampDiff(part, utcTimestamp(), DSL.currentTimestamp()); - } - /** * Taken from https://github.com/jOOQ/jOOQ/issues/4303#issuecomment-105519975 */ - private static Field timestampDiff(DatePart part, Field t1, Field t2) { + public static Field timestampDiff(DatePart part, Field t1, Field t2) { return field("timestampdiff({0}, {1}, {2})", Long.class, DSL.keyword(part.toSQL()), t1, t2); } - private static Field utcTimestamp() { + public static Field utcTimestamp() { return field("{utc_timestamp()}", Timestamp.class); } } diff --git a/src/main/java/de/rwth/idsg/steve/utils/DateTimeUtils.java b/src/main/java/de/rwth/idsg/steve/utils/DateTimeUtils.java index ee379e32d..181dd1281 100644 --- a/src/main/java/de/rwth/idsg/steve/utils/DateTimeUtils.java +++ b/src/main/java/de/rwth/idsg/steve/utils/DateTimeUtils.java @@ -18,7 +18,6 @@ */ package de.rwth.idsg.steve.utils; -import de.rwth.idsg.steve.SteveException; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.joda.time.DateTime; @@ -29,7 +28,6 @@ import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.PeriodFormatter; import org.joda.time.format.PeriodFormatterBuilder; -import org.jooq.DSLContext; import java.util.concurrent.TimeUnit; @@ -100,17 +98,7 @@ public static String timeElapsed(DateTime from, DateTime to) { return PERIOD_FORMATTER.print(new Period(from, to)); } - public static void checkJavaAndMySQLOffsets(DSLContext ctx) { - long sql = CustomDSL.selectOffsetFromUtcInSeconds(ctx); - long java = DateTimeUtils.getOffsetFromUtcInSeconds(); - - if (sql != java) { - throw new SteveException("MySQL and Java are not using the same time zone. " + - "Java offset in seconds (%s) != MySQL offset in seconds (%s)", java, sql); - } - } - - private static long getOffsetFromUtcInSeconds() { + public static long getOffsetFromUtcInSeconds() { DateTimeZone timeZone = DateTimeZone.getDefault(); DateTime now = DateTime.now(); long offsetInMilliseconds = timeZone.getOffset(now.getMillis()); diff --git a/src/test/java/de/rwth/idsg/steve/utils/__DatabasePreparer__.java b/src/test/java/de/rwth/idsg/steve/utils/__DatabasePreparer__.java index 7a4b5308e..bb121e9a5 100644 --- a/src/test/java/de/rwth/idsg/steve/utils/__DatabasePreparer__.java +++ b/src/test/java/de/rwth/idsg/steve/utils/__DatabasePreparer__.java @@ -72,7 +72,7 @@ public class __DatabasePreparer__ { private static final String REGISTERED_OCPP_TAG = "id_tag_2aa6a783d47d"; private static final BeanConfiguration beanConfiguration = new BeanConfiguration(); - private static final DSLContext dslContext = beanConfiguration.dslContext(); + private static final DSLContext dslContext = beanConfiguration.dslContext(beanConfiguration.dataSource()); public static void prepare() { runOperation(ctx -> {