From 8c8bb69b5737f8e5260be6ef408468b6c53b15de Mon Sep 17 00:00:00 2001 From: BerndBreier <33351391+BerndBreier@users.noreply.github.com> Date: Wed, 22 Jan 2020 10:09:32 +0100 Subject: [PATCH] TSK-1021 persist timestamps in UTC representation --- .../java/pro/taskana/impl/JobServiceImpl.java | 3 +- .../pro/taskana/impl/TaskanaEngineImpl.java | 6 +- .../impl/persistence/InstantTypeHandler.java | 55 ++++ .../java/pro/taskana/jobs/ScheduledJob.java | 64 +++-- .../java/pro/taskana/mappings/JobMapper.java | 5 +- .../test/java/acceptance/AbstractAccTest.java | 6 +- .../UpdateObjectsUseUtcTimeStampsAccTest.java | 243 ++++++++++++++++++ .../sampledata/SampleDataGenerator.java | 10 +- .../pro/taskana/sampledata/SqlReplacer.java | 10 +- .../main/resources/sql/clear/drop-tables.sql | 3 +- .../sql/monitor-data/monitor-sample-data.sql | 148 +++++------ .../sql/sample-data/classification.sql | 82 +++--- .../sql/sample-data/history-event.sql | 102 ++++---- .../resources/sql/sample-data/workbasket.sql | 50 ++-- .../sql/test-data/classification.sql | 82 +++--- .../resources/sql/test-data/workbasket.sql | 48 ++-- .../taskana/sampledata/SqlReplacerTest.java | 8 +- 17 files changed, 631 insertions(+), 294 deletions(-) create mode 100644 lib/taskana-core/src/main/java/pro/taskana/impl/persistence/InstantTypeHandler.java create mode 100644 lib/taskana-core/src/test/java/acceptance/persistence/UpdateObjectsUseUtcTimeStampsAccTest.java diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/JobServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/JobServiceImpl.java index f8b927dd3..96c324c30 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/JobServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/JobServiceImpl.java @@ -30,7 +30,8 @@ public class JobServiceImpl implements JobService { try { taskanaEngineImpl.openConnection(); job = initializeJobDefault(job); - jobMapper.insertJob(job); + Integer jobId = jobMapper.insertJob(job); + job.setJobId(jobId); LOGGER.debug("Created job {}", job); } finally { taskanaEngineImpl.returnConnection(); diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java index ee39ac2c3..7fa6cfd28 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java @@ -2,6 +2,7 @@ package pro.taskana.impl; import java.sql.Connection; import java.sql.SQLException; +import java.time.Instant; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Deque; @@ -35,6 +36,7 @@ import pro.taskana.exceptions.ConnectionNotSetException; import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.SystemException; import pro.taskana.history.HistoryEventProducer; +import pro.taskana.impl.persistence.InstantTypeHandler; import pro.taskana.impl.persistence.MapTypeHandler; import pro.taskana.impl.util.LoggerUtils; import pro.taskana.mappings.AttachmentMapper; @@ -232,6 +234,9 @@ public class TaskanaEngineImpl implements TaskanaEngine { e.getCause()); } + // register type handlers + configuration.getTypeHandlerRegistry().register(MapTypeHandler.class); + configuration.getTypeHandlerRegistry().register(Instant.class, InstantTypeHandler.class); // add mappers configuration.addMapper(TaskMapper.class); configuration.addMapper(TaskMonitorMapper.class); @@ -243,7 +248,6 @@ public class TaskanaEngineImpl implements TaskanaEngine { configuration.addMapper(QueryMapper.class); configuration.addMapper(AttachmentMapper.class); configuration.addMapper(JobMapper.class); - configuration.getTypeHandlerRegistry().register(MapTypeHandler.class); SqlSessionFactory localSessionFactory = new SqlSessionFactoryBuilder().build(configuration); return SqlSessionManager.newInstance(localSessionFactory); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/InstantTypeHandler.java b/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/InstantTypeHandler.java new file mode 100644 index 000000000..b5854b6d8 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/InstantTypeHandler.java @@ -0,0 +1,55 @@ +package pro.taskana.impl.persistence; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.Instant; +import java.util.Calendar; +import java.util.TimeZone; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +/** + * Instruct jdbc driver to interpret timestamps as being in utc timezone. + * + * @author bbr + */ +public class InstantTypeHandler extends BaseTypeHandler { + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, Instant parameter, JdbcType jdbcType) + throws SQLException { + ps.setTimestamp( + i, Timestamp.from(parameter), Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + } + + @Override + public Instant getNullableResult(ResultSet rs, String columnName) throws SQLException { + Timestamp timestamp = + rs.getTimestamp(columnName, Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + return getInstant(timestamp); + } + + @Override + public Instant getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + Timestamp timestamp = + rs.getTimestamp(columnIndex, Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + return getInstant(timestamp); + } + + @Override + public Instant getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + Timestamp timestamp = + cs.getTimestamp(columnIndex, Calendar.getInstance(TimeZone.getTimeZone("UTC"))); + return getInstant(timestamp); + } + + private static Instant getInstant(Timestamp timestamp) { + if (timestamp != null) { + return timestamp.toInstant(); + } + return null; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/jobs/ScheduledJob.java b/lib/taskana-core/src/main/java/pro/taskana/jobs/ScheduledJob.java index d28e18bed..39d9ce2ea 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/jobs/ScheduledJob.java +++ b/lib/taskana-core/src/main/java/pro/taskana/jobs/ScheduledJob.java @@ -2,6 +2,7 @@ package pro.taskana.jobs; import java.time.Instant; import java.util.Map; +import java.util.Objects; /** * This class holds all data that go into the Job table. @@ -107,6 +108,51 @@ public class ScheduledJob { this.retryCount = retryCount; } + /** + * This enum tracks the state of a job. + * + * @author bbr + */ + public enum State { + READY, + FAILED + } + + /** This enum controls the type of a job. */ + public enum Type { + CLASSIFICATIONCHANGEDJOB, + UPDATETASKSJOB, + TASKCLEANUPJOB, + WORKBASKETCLEANUPJOB; + } + + @Override + public int hashCode() { + return Objects.hash( + arguments, created, due, jobId, lockExpires, lockedBy, priority, retryCount, state, type); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ScheduledJob)) { + return false; + } + ScheduledJob other = (ScheduledJob) obj; + return Objects.equals(arguments, other.arguments) + && Objects.equals(created, other.created) + && Objects.equals(due, other.due) + && Objects.equals(jobId, other.jobId) + && Objects.equals(lockExpires, other.lockExpires) + && Objects.equals(lockedBy, other.lockedBy) + && Objects.equals(priority, other.priority) + && retryCount == other.retryCount + && state == other.state + && type == other.type; + } + @Override public String toString() { return "ScheduledJob [jobId=" @@ -131,22 +177,4 @@ public class ScheduledJob { + arguments + "]"; } - - /** - * This enum tracks the state of a job. - * - * @author bbr - */ - public enum State { - READY, - FAILED - } - - /** This enum controls the type of a job. */ - public enum Type { - CLASSIFICATIONCHANGEDJOB, - UPDATETASKSJOB, - TASKCLEANUPJOB, - WORKBASKETCLEANUPJOB; - } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java b/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java index 828be6449..2986a2ecd 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java @@ -31,7 +31,10 @@ public interface JobMapper { + "" + ", #{job.priority}, #{job.created}, #{job.due}, #{job.state}, #{job.lockedBy}, #{job.lockExpires}, #{job.type}, #{job.retryCount}, #{job.arguments,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler} )" + "") - void insertJob(@Param("job") ScheduledJob job); + @Results( + value = { + @Result(property = "jobId", column = "JOB_ID")}) + Integer insertJob(@Param("job") ScheduledJob job); @Select( "