From 8b9ca2550e7fde994d681608d913376f1a2c93fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Heffner?= Date: Tue, 24 Oct 2023 14:47:45 +0200 Subject: [PATCH] Closes #2374: Deadlock when creating HistoryEvents from many connections simultaneously -Write operations are now performed with the regular TaskanEngine and its' SqlSession and TransactionFactory which provides the needed transactionality and doesn't open multiple connections --- .../simplehistory/TaskanaHistoryEngine.java | 31 --- .../impl/ClassificationHistoryQueryImpl.java | 55 ++-- .../impl/SimpleHistoryServiceImpl.java | 180 ++++++++----- .../impl/TaskHistoryQueryImpl.java | 56 ++-- .../impl/TaskanaHistoryEngineImpl.java | 255 ------------------ .../impl/WorkbasketHistoryQueryImpl.java | 53 ++-- .../impl/jobs/HistoryCleanupJob.java | 17 +- .../test/java/acceptance/AbstractAccTest.java | 19 +- ...yEventOnClassificationDeletionAccTest.java | 3 + ...eateHistoryEventOnTaskDeletionAccTest.java | 8 +- .../ClassificationHistoryQueryImplTest.java | 11 +- .../impl/SimpleHistoryServiceImplTest.java | 30 +-- .../impl/WorkbasketHistoryQueryImplTest.java | 11 +- .../rest/TaskHistoryEventController.java | 10 +- .../pro/taskana/common/api/TaskanaEngine.java | 24 +- .../common/internal/TaskanaEngineImpl.java | 26 +- .../internal/SpringTaskanaEngineImpl.java | 4 +- .../boot/ExampleRestConfiguration.java | 3 +- 18 files changed, 262 insertions(+), 534 deletions(-) delete mode 100644 history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/TaskanaHistoryEngine.java delete mode 100644 history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskanaHistoryEngineImpl.java diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/TaskanaHistoryEngine.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/TaskanaHistoryEngine.java deleted file mode 100644 index 0bb759feb..000000000 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/TaskanaHistoryEngine.java +++ /dev/null @@ -1,31 +0,0 @@ -package pro.taskana.simplehistory; - -import pro.taskana.common.api.TaskanaRole; -import pro.taskana.common.api.exceptions.NotAuthorizedException; -import pro.taskana.spi.history.api.TaskanaHistory; - -/** The TaskanaHistoryEngine represents an overall set of all needed services. */ -public interface TaskanaHistoryEngine { - /** - * The TaskanaHistory can be used for operations on all history events. - * - * @return the HistoryService - */ - TaskanaHistory getTaskanaHistoryService(); - - /** - * check whether the current user is member of one of the roles specified. - * - * @param roles The roles that are checked for membership of the current user - * @return true if the current user is a member of at least one of the specified groups - */ - boolean isUserInRole(TaskanaRole... roles); - - /** - * Checks whether current user is member of any of the specified roles. - * - * @param roles The roles that are checked for membership of the current user - * @throws NotAuthorizedException If the current user is not member of any specified role - */ - void checkRoleMembership(TaskanaRole... roles) throws NotAuthorizedException; -} diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImpl.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImpl.java index 8c3c538a7..d57ee191f 100644 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImpl.java +++ b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImpl.java @@ -2,7 +2,6 @@ package pro.taskana.simplehistory.impl; import static pro.taskana.common.api.BaseQuery.toLowerCopy; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.apache.ibatis.session.RowBounds; @@ -12,6 +11,7 @@ import pro.taskana.classification.api.ClassificationCustomField; import pro.taskana.common.api.TimeInterval; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.SystemException; +import pro.taskana.common.internal.InternalTaskanaEngine; import pro.taskana.simplehistory.impl.classification.ClassificationHistoryQuery; import pro.taskana.simplehistory.impl.classification.ClassificationHistoryQueryColumnName; import pro.taskana.spi.history.api.events.classification.ClassificationHistoryEvent; @@ -33,7 +33,7 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer private static final String SQL_EXCEPTION_MESSAGE = "Method openConnection() could not open a connection to the database."; - private final TaskanaHistoryEngineImpl taskanaHistoryEngine; + private final InternalTaskanaEngine internalTaskanaEngine; private final List orderBy = new ArrayList<>(); private final List orderColumns = new ArrayList<>(); @@ -82,8 +82,8 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer private String[] custom7Like; private String[] custom8Like; - public ClassificationHistoryQueryImpl(TaskanaHistoryEngineImpl internalTaskanaHistoryEngine) { - this.taskanaHistoryEngine = internalTaskanaHistoryEngine; + public ClassificationHistoryQueryImpl(InternalTaskanaEngine internalTaskanaEngine) { + this.internalTaskanaEngine = internalTaskanaEngine; } @Override @@ -415,16 +415,13 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer @Override public List list() { - List result = new ArrayList<>(); + List result; try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_MAPPER, this); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -432,15 +429,12 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer public List list(int offset, int limit) { List result = new ArrayList<>(); try { - taskanaHistoryEngine.openConnection(); + internalTaskanaEngine.openConnection(); RowBounds rowBounds = new RowBounds(offset, limit); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_MAPPER, this, rowBounds); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_MAPPER, this, rowBounds); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -454,17 +448,14 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer this.addOrderCriteria(columnName.toString(), sortDirection); try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_VALUE_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_VALUE_MAPPER, this); return result; } finally { this.orderBy.addAll(cacheOrderBy); this.columnName = null; this.orderColumns.remove(orderColumns.size() - 1); - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -473,15 +464,12 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer ClassificationHistoryEvent result = null; try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectOne(LINK_TO_MAPPER, this); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectOne(LINK_TO_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -489,14 +477,11 @@ public class ClassificationHistoryQueryImpl implements ClassificationHistoryQuer public long count() { Long rowCount = null; try { - taskanaHistoryEngine.openConnection(); - rowCount = taskanaHistoryEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); + internalTaskanaEngine.openConnection(); + rowCount = internalTaskanaEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); return (rowCount == null) ? 0L : rowCount; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); - return -1; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImpl.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImpl.java index 0b97637b2..4a113af11 100644 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImpl.java +++ b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImpl.java @@ -1,20 +1,27 @@ package pro.taskana.simplehistory.impl; -import java.sql.SQLException; +import java.lang.reflect.Field; import java.time.Instant; import java.util.List; +import org.apache.ibatis.session.SqlSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pro.taskana.common.api.TaskanaEngine; import pro.taskana.common.api.TaskanaRole; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; +import pro.taskana.common.api.exceptions.SystemException; +import pro.taskana.common.internal.InternalTaskanaEngine; +import pro.taskana.common.internal.TaskanaEngineImpl; import pro.taskana.simplehistory.impl.classification.ClassificationHistoryEventMapper; import pro.taskana.simplehistory.impl.classification.ClassificationHistoryQuery; +import pro.taskana.simplehistory.impl.classification.ClassificationHistoryQueryMapper; import pro.taskana.simplehistory.impl.task.TaskHistoryEventMapper; import pro.taskana.simplehistory.impl.task.TaskHistoryQuery; +import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper; import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryEventMapper; import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryQuery; +import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryQueryMapper; import pro.taskana.spi.history.api.TaskanaHistory; import pro.taskana.spi.history.api.events.classification.ClassificationHistoryEvent; import pro.taskana.spi.history.api.events.task.TaskHistoryEvent; @@ -27,110 +34,149 @@ import pro.taskana.user.internal.UserMapper; public class SimpleHistoryServiceImpl implements TaskanaHistory { private static final Logger LOGGER = LoggerFactory.getLogger(SimpleHistoryServiceImpl.class); - private TaskanaHistoryEngineImpl taskanaHistoryEngine; private TaskHistoryEventMapper taskHistoryEventMapper; private WorkbasketHistoryEventMapper workbasketHistoryEventMapper; private ClassificationHistoryEventMapper classificationHistoryEventMapper; private UserMapper userMapper; + private InternalTaskanaEngine internalTaskanaEngine; + public void initialize(TaskanaEngine taskanaEngine) { - this.taskanaHistoryEngine = getTaskanaEngine(taskanaEngine); + LOGGER.info( + "Simple history service implementation initialized with schemaName: {} ", + taskanaEngine.getConfiguration().getSchemaName()); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug( - "Simple history service implementation initialized with schemaName: {} ", - taskanaEngine.getConfiguration().getSchemaName()); + Field sessionManager = null; + try { + Field internalTaskanaEngineImpl = + TaskanaEngineImpl.class.getDeclaredField("internalTaskanaEngineImpl"); + internalTaskanaEngineImpl.setAccessible(true); + this.internalTaskanaEngine = + (InternalTaskanaEngine) internalTaskanaEngineImpl.get(taskanaEngine); + sessionManager = TaskanaEngineImpl.class.getDeclaredField("sessionManager"); + sessionManager.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new SystemException("SQL Session could not be retrieved. Aborting Startup"); + } catch (IllegalAccessException e) { + throw new SystemException(e.getMessage()); } + try { + SqlSession sqlSession = (SqlSession) sessionManager.get(taskanaEngine); + if (!sqlSession + .getConfiguration() + .getMapperRegistry() + .hasMapper(TaskHistoryEventMapper.class)) { + sqlSession.getConfiguration().addMapper(TaskHistoryEventMapper.class); + } + if (!sqlSession + .getConfiguration() + .getMapperRegistry() + .hasMapper(WorkbasketHistoryEventMapper.class)) { - this.taskHistoryEventMapper = - this.taskanaHistoryEngine.getSqlSession().getMapper(TaskHistoryEventMapper.class); - this.workbasketHistoryEventMapper = - this.taskanaHistoryEngine.getSqlSession().getMapper(WorkbasketHistoryEventMapper.class); - this.classificationHistoryEventMapper = - this.taskanaHistoryEngine.getSqlSession().getMapper(ClassificationHistoryEventMapper.class); - this.userMapper = taskanaHistoryEngine.getSqlSession().getMapper(UserMapper.class); + sqlSession.getConfiguration().addMapper(WorkbasketHistoryEventMapper.class); + } + if (!sqlSession + .getConfiguration() + .getMapperRegistry() + .hasMapper(ClassificationHistoryEventMapper.class)) { + + sqlSession.getConfiguration().addMapper(ClassificationHistoryEventMapper.class); + } + + if (!sqlSession + .getConfiguration() + .getMapperRegistry() + .hasMapper(ClassificationHistoryQueryMapper.class)) { + + sqlSession.getConfiguration().addMapper(ClassificationHistoryQueryMapper.class); + } + + if (!sqlSession + .getConfiguration() + .getMapperRegistry() + .hasMapper(TaskHistoryQueryMapper.class)) { + + sqlSession.getConfiguration().addMapper(TaskHistoryQueryMapper.class); + } + + if (!sqlSession + .getConfiguration() + .getMapperRegistry() + .hasMapper(WorkbasketHistoryQueryMapper.class)) { + + sqlSession.getConfiguration().addMapper(WorkbasketHistoryQueryMapper.class); + } + + this.taskHistoryEventMapper = sqlSession.getMapper(TaskHistoryEventMapper.class); + this.workbasketHistoryEventMapper = sqlSession.getMapper(WorkbasketHistoryEventMapper.class); + this.classificationHistoryEventMapper = + sqlSession.getMapper(ClassificationHistoryEventMapper.class); + this.userMapper = sqlSession.getMapper(UserMapper.class); + } catch (IllegalAccessException e) { + throw new SystemException( + "TASKANA engine of Session Manager could not be retrieved. Aborting Startup"); + } } @Override public void create(TaskHistoryEvent event) { - try { - taskanaHistoryEngine.openConnection(); - if (event.getCreated() == null) { - Instant now = Instant.now(); - event.setCreated(now); - } - taskHistoryEventMapper.insert(event); - } catch (SQLException e) { - LOGGER.error("Error while inserting task history event into database", e); - } finally { - taskanaHistoryEngine.returnConnection(); + + if (event.getCreated() == null) { + Instant now = Instant.now(); + event.setCreated(now); } + taskHistoryEventMapper.insert(event); } @Override public void create(WorkbasketHistoryEvent event) { - try { - taskanaHistoryEngine.openConnection(); - if (event.getCreated() == null) { - Instant now = Instant.now(); - event.setCreated(now); - } - workbasketHistoryEventMapper.insert(event); - } catch (SQLException e) { - LOGGER.error("Error while inserting workbasket history event into database", e); - } finally { - taskanaHistoryEngine.returnConnection(); + + if (event.getCreated() == null) { + Instant now = Instant.now(); + event.setCreated(now); } + workbasketHistoryEventMapper.insert(event); } @Override public void create(ClassificationHistoryEvent event) { - try { - taskanaHistoryEngine.openConnection(); - if (event.getCreated() == null) { - Instant now = Instant.now(); - event.setCreated(now); - } - classificationHistoryEventMapper.insert(event); - } catch (SQLException e) { - LOGGER.error("Error while inserting classification history event into database", e); - } finally { - taskanaHistoryEngine.returnConnection(); + + if (event.getCreated() == null) { + Instant now = Instant.now(); + event.setCreated(now); } + classificationHistoryEventMapper.insert(event); } @Override public void deleteHistoryEventsByTaskIds(List taskIds) throws InvalidArgumentException, NotAuthorizedException { - taskanaHistoryEngine.checkRoleMembership(TaskanaRole.ADMIN); + + internalTaskanaEngine.openConnection(); + internalTaskanaEngine.getEngine().checkRoleMembership(TaskanaRole.ADMIN); if (taskIds == null) { throw new InvalidArgumentException("List of taskIds must not be null."); } - try { - taskanaHistoryEngine.openConnection(); - taskHistoryEventMapper.deleteMultipleByTaskIds(taskIds); - } catch (SQLException e) { - LOGGER.error("Caught exception while trying to delete history events", e); - } finally { - taskanaHistoryEngine.returnConnection(); - } + taskHistoryEventMapper.deleteMultipleByTaskIds(taskIds); + + internalTaskanaEngine.returnConnection(); } public TaskHistoryEvent getTaskHistoryEvent(String historyEventId) throws TaskanaHistoryEventNotFoundException { TaskHistoryEvent resultEvent = null; try { - taskanaHistoryEngine.openConnection(); + internalTaskanaEngine.openConnection(); resultEvent = taskHistoryEventMapper.findById(historyEventId); if (resultEvent == null) { throw new TaskanaHistoryEventNotFoundException(historyEventId); } - if (taskanaHistoryEngine.getConfiguration().isAddAdditionalUserInfo()) { + if (internalTaskanaEngine.getEngine().getConfiguration().isAddAdditionalUserInfo()) { User user = userMapper.findById(resultEvent.getUserId()); if (user != null) { resultEvent.setUserLongName(user.getLongName()); @@ -138,30 +184,20 @@ public class SimpleHistoryServiceImpl implements TaskanaHistory { } return resultEvent; - } catch (SQLException e) { - LOGGER.error("Caught exception while trying to retrieve a history event", e); - return resultEvent; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } public TaskHistoryQuery createTaskHistoryQuery() { - return new TaskHistoryQueryImpl(taskanaHistoryEngine); + return new TaskHistoryQueryImpl(internalTaskanaEngine); } public WorkbasketHistoryQuery createWorkbasketHistoryQuery() { - return new WorkbasketHistoryQueryImpl(taskanaHistoryEngine); + return new WorkbasketHistoryQueryImpl(internalTaskanaEngine); } public ClassificationHistoryQuery createClassificationHistoryQuery() { - return new ClassificationHistoryQueryImpl(taskanaHistoryEngine); - } - - /* - * ATTENTION: This method exists for testing purposes. - */ - TaskanaHistoryEngineImpl getTaskanaEngine(TaskanaEngine taskanaEngine) { - return TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngine); + return new ClassificationHistoryQueryImpl(internalTaskanaEngine); } } diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskHistoryQueryImpl.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskHistoryQueryImpl.java index d41d00ec6..92a85357f 100644 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskHistoryQueryImpl.java +++ b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskHistoryQueryImpl.java @@ -2,7 +2,6 @@ package pro.taskana.simplehistory.impl; import static pro.taskana.common.api.BaseQuery.toLowerCopy; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.apache.ibatis.session.RowBounds; @@ -10,6 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pro.taskana.common.api.TimeInterval; import pro.taskana.common.api.exceptions.SystemException; +import pro.taskana.common.internal.InternalTaskanaEngine; import pro.taskana.simplehistory.impl.task.TaskHistoryQuery; import pro.taskana.simplehistory.impl.task.TaskHistoryQueryColumnName; import pro.taskana.spi.history.api.events.task.TaskHistoryCustomField; @@ -30,7 +30,7 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { private static final String SQL_EXCEPTION_MESSAGE = "Method openConnection() could not open a connection to the database."; - private final TaskanaHistoryEngineImpl taskanaHistoryEngine; + private final InternalTaskanaEngine internalTaskanaEngine; private final List orderBy; private final List orderColumns; private boolean joinWithUserInfo; @@ -83,11 +83,12 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { private String[] custom3Like; private String[] custom4Like; - public TaskHistoryQueryImpl(TaskanaHistoryEngineImpl taskanaHistoryEngine) { - this.taskanaHistoryEngine = taskanaHistoryEngine; + public TaskHistoryQueryImpl(InternalTaskanaEngine internalTaskanaEngine) { + this.internalTaskanaEngine = internalTaskanaEngine; this.orderBy = new ArrayList<>(); this.orderColumns = new ArrayList<>(); - this.joinWithUserInfo = taskanaHistoryEngine.getConfiguration().isAddAdditionalUserInfo(); + this.joinWithUserInfo = + internalTaskanaEngine.getEngine().getConfiguration().isAddAdditionalUserInfo(); } public String[] getIdIn() { @@ -631,14 +632,11 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { public List list() { List result = new ArrayList<>(); try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_MAPPER, this); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -646,15 +644,12 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { public List list(int offset, int limit) { List result = new ArrayList<>(); try { - taskanaHistoryEngine.openConnection(); + internalTaskanaEngine.openConnection(); RowBounds rowBounds = new RowBounds(offset, limit); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_MAPPER, this, rowBounds); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_MAPPER, this, rowBounds); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -672,15 +667,12 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { } try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_VALUE_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_VALUE_MAPPER, this); return result; } finally { this.orderColumns.remove(orderColumns.size() - 1); - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -688,16 +680,13 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { public TaskHistoryEvent single() { TaskHistoryEvent result = null; try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectOne(LINK_TO_MAPPER, this); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectOne(LINK_TO_MAPPER, this); return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); - return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -705,14 +694,11 @@ public class TaskHistoryQueryImpl implements TaskHistoryQuery { public long count() { Long rowCount; try { - taskanaHistoryEngine.openConnection(); - rowCount = taskanaHistoryEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); + internalTaskanaEngine.openConnection(); + rowCount = internalTaskanaEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); return (rowCount == null) ? 0L : rowCount; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); - return -1; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskanaHistoryEngineImpl.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskanaHistoryEngineImpl.java deleted file mode 100644 index 4165fb543..000000000 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/TaskanaHistoryEngineImpl.java +++ /dev/null @@ -1,255 +0,0 @@ -package pro.taskana.simplehistory.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; -import java.util.HashSet; -import java.util.Set; -import org.apache.ibatis.mapping.Environment; -import org.apache.ibatis.session.Configuration; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; -import org.apache.ibatis.session.SqlSessionFactoryBuilder; -import org.apache.ibatis.session.SqlSessionManager; -import org.apache.ibatis.transaction.TransactionFactory; -import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; -import org.apache.ibatis.transaction.managed.ManagedTransactionFactory; -import org.apache.ibatis.type.JdbcType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import pro.taskana.TaskanaConfiguration; -import pro.taskana.common.api.TaskanaEngine; -import pro.taskana.common.api.TaskanaRole; -import pro.taskana.common.api.exceptions.NotAuthorizedException; -import pro.taskana.common.api.exceptions.SystemException; -import pro.taskana.common.internal.OracleSqlSessionFactory; -import pro.taskana.common.internal.configuration.DB; -import pro.taskana.common.internal.persistence.InstantTypeHandler; -import pro.taskana.common.internal.persistence.MapTypeHandler; -import pro.taskana.common.internal.persistence.StringTypeHandler; -import pro.taskana.simplehistory.TaskanaHistoryEngine; -import pro.taskana.simplehistory.impl.classification.ClassificationHistoryEventMapper; -import pro.taskana.simplehistory.impl.classification.ClassificationHistoryQueryMapper; -import pro.taskana.simplehistory.impl.task.TaskHistoryEventMapper; -import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper; -import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryEventMapper; -import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryQueryMapper; -import pro.taskana.spi.history.api.TaskanaHistory; -import pro.taskana.user.internal.UserMapper; - -/** This is the implementation of TaskanaHistoryEngine. */ -public class TaskanaHistoryEngineImpl implements TaskanaHistoryEngine { - - protected static final ThreadLocal> SESSION_STACK = new ThreadLocal<>(); - private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaHistoryEngineImpl.class); - private static final String DEFAULT = "default"; - private final SqlSessionManager sessionManager; - private final TaskanaConfiguration taskanaConfiguration; - private final TaskanaEngine taskanaEngine; - private TransactionFactory transactionFactory; - private TaskanaHistory taskanaHistoryService; - - protected TaskanaHistoryEngineImpl(TaskanaEngine taskanaEngine) { - this.taskanaConfiguration = taskanaEngine.getConfiguration(); - this.taskanaEngine = taskanaEngine; - - createTransactionFactory(taskanaConfiguration.isUseManagedTransactions()); - sessionManager = createSqlSessionManager(); - } - - public static TaskanaHistoryEngineImpl createTaskanaEngine(TaskanaEngine taskanaEngine) { - return new TaskanaHistoryEngineImpl(taskanaEngine); - } - - @Override - public TaskanaHistory getTaskanaHistoryService() { - if (taskanaHistoryService == null) { - SimpleHistoryServiceImpl historyService = new SimpleHistoryServiceImpl(); - historyService.initialize(taskanaEngine); - taskanaHistoryService = historyService; - } - return taskanaHistoryService; - } - - public boolean isUserInRole(TaskanaRole... roles) { - if (!getConfiguration().isSecurityEnabled()) { - return true; - } - - Set rolesMembers = - Arrays.stream(roles) - .map(role -> getConfiguration().getRoleMap().get(role)) - .collect(HashSet::new, Set::addAll, Set::addAll); - - return taskanaEngine.getCurrentUserContext().getAccessIds().stream() - .anyMatch(rolesMembers::contains); - } - - public void checkRoleMembership(TaskanaRole... roles) throws NotAuthorizedException { - if (!isUserInRole(roles)) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug( - "Throwing NotAuthorizedException because accessIds {} are not member of roles {}", - taskanaEngine.getCurrentUserContext().getAccessIds(), - Arrays.toString(roles)); - } - throw new NotAuthorizedException(taskanaEngine.getCurrentUserContext().getUserid(), roles); - } - } - - public TaskanaConfiguration getConfiguration() { - return this.taskanaConfiguration; - } - - protected SqlSessionManager createSqlSessionManager() { - Environment environment = - new Environment(DEFAULT, this.transactionFactory, taskanaConfiguration.getDataSource()); - Configuration configuration = new Configuration(environment); - - // set databaseId - DB db; - try (Connection con = taskanaConfiguration.getDataSource().getConnection()) { - db = DB.getDB(con); - configuration.setDatabaseId(db.dbProductId); - } catch (SQLException e) { - throw new SystemException("Could not open a connection to set the databaseId", e); - } - - // register type handlers - if (DB.ORACLE == db) { - // Use NULL instead of OTHER when jdbcType is not specified for null values, - // otherwise oracle driver will chunck on null values - configuration.setJdbcTypeForNull(JdbcType.NULL); - configuration.getTypeHandlerRegistry().register(String.class, new StringTypeHandler()); - } - configuration.getTypeHandlerRegistry().register(new MapTypeHandler()); - configuration.getTypeHandlerRegistry().register(Instant.class, new InstantTypeHandler()); - configuration.getTypeHandlerRegistry().register(JdbcType.TIMESTAMP, new InstantTypeHandler()); - - // add mappers - configuration.addMapper(TaskHistoryEventMapper.class); - configuration.addMapper(TaskHistoryQueryMapper.class); - configuration.addMapper(WorkbasketHistoryEventMapper.class); - configuration.addMapper(WorkbasketHistoryQueryMapper.class); - configuration.addMapper(ClassificationHistoryEventMapper.class); - configuration.addMapper(ClassificationHistoryQueryMapper.class); - configuration.addMapper(UserMapper.class); - - SqlSessionFactory localSessionFactory; - if (DB.ORACLE == db) { - localSessionFactory = - new SqlSessionFactoryBuilder() { - @Override - public SqlSessionFactory build(Configuration config) { - return new OracleSqlSessionFactory(config); - } - }.build(configuration); - } else { - localSessionFactory = new SqlSessionFactoryBuilder().build(configuration); - } - return SqlSessionManager.newInstance(localSessionFactory); - } - - protected static void pushSessionToStack(SqlSessionManager session) { - getSessionStack().push(session); - } - - protected static void popSessionFromStack() { - Deque stack = getSessionStack(); - if (!stack.isEmpty()) { - stack.pop(); - } - } - - /** - * With sessionStack, we maintain a Stack of SqlSessionManager objects on a per thread basis. - * SqlSessionManager is the MyBatis object that wraps database connections. The purpose of this - * stack is to keep track of nested calls. Each external API call is wrapped into - * taskanaEngineImpl.openConnection(); ..... taskanaEngineImpl.returnConnection(); calls. In order - * to avoid duplicate opening / closing of connections, we use the sessionStack in the following - * way: Each time, an openConnection call is received, we push the current sessionManager onto the - * stack. On the first call to openConnection, we call sessionManager.startManagedSession() to - * open a database connection. On each call to returnConnection() we pop one instance of - * sessionManager from the stack. When the stack becomes empty, we close the database connection - * by calling sessionManager.close() - * - * @return Stack of SqlSessionManager - */ - protected static Deque getSessionStack() { - Deque stack = SESSION_STACK.get(); - if (stack == null) { - stack = new ArrayDeque<>(); - SESSION_STACK.set(stack); - } - return stack; - } - - protected static SqlSessionManager getSessionFromStack() { - Deque stack = getSessionStack(); - if (stack.isEmpty()) { - return null; - } - return stack.peek(); - } - - /** - * Open the connection to the database. to be called at the begin of each Api call that accesses - * the database - * - * @throws SQLException thrown if the connection could not be opened. - */ - void openConnection() throws SQLException { - initSqlSession(); - this.sessionManager.getConnection().setSchema(taskanaConfiguration.getSchemaName()); - } - - /** - * Returns the database connection into the pool. In the case of nested calls, simply pops the - * latest session from the session stack. Closes the connection if the session stack is empty. In - * mode AUTOCOMMIT commits before the connection is closed. To be called at the end of each Api - * call that accesses the database - */ - void returnConnection() { - popSessionFromStack(); - if (getSessionStack().isEmpty() - && this.sessionManager != null - && this.sessionManager.isManagedSessionStarted()) { - try { - this.sessionManager.commit(); - } catch (Exception e) { - // ignore - } - this.sessionManager.close(); - } - } - - /** Initializes the SqlSessionManager. */ - void initSqlSession() { - this.sessionManager.startManagedSession(); - } - - /** - * retrieve the SqlSession used by taskana. - * - * @return the myBatis SqlSession object used by taskana - */ - SqlSession getSqlSession() { - return this.sessionManager; - } - - /** - * creates the MyBatis transaction factory. - * - * @param useManagedTransactions true if TASKANA should use a ManagedTransactionFactory. - */ - private void createTransactionFactory(boolean useManagedTransactions) { - if (useManagedTransactions) { - this.transactionFactory = new ManagedTransactionFactory(); - } else { - this.transactionFactory = new JdbcTransactionFactory(); - } - } -} diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImpl.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImpl.java index 1ef2ab8d3..6b3fbc78d 100644 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImpl.java +++ b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImpl.java @@ -2,7 +2,6 @@ package pro.taskana.simplehistory.impl; import static pro.taskana.common.api.BaseQuery.toLowerCopy; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.apache.ibatis.session.RowBounds; @@ -11,6 +10,7 @@ import org.slf4j.LoggerFactory; import pro.taskana.common.api.TimeInterval; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.SystemException; +import pro.taskana.common.internal.InternalTaskanaEngine; import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryQuery; import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryQueryColumnName; import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEvent; @@ -30,7 +30,7 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { private static final String SQL_EXCEPTION_MESSAGE = "Method openConnection() could not open a connection to the database."; - private final TaskanaHistoryEngineImpl taskanaHistoryEngine; + private final InternalTaskanaEngine internalTaskanaEngine; private final List orderColumns; @SuppressWarnings("unused") @@ -71,8 +71,8 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { private String[] orgLevel3Like; private String[] orgLevel4Like; - public WorkbasketHistoryQueryImpl(TaskanaHistoryEngineImpl internalTaskanaHistoryEngine) { - this.taskanaHistoryEngine = internalTaskanaHistoryEngine; + public WorkbasketHistoryQueryImpl(InternalTaskanaEngine internalTaskanaEngine) { + this.internalTaskanaEngine = internalTaskanaEngine; this.orderBy = new ArrayList<>(); this.orderColumns = new ArrayList<>(); } @@ -475,14 +475,11 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { public List list() { List result = new ArrayList<>(); try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_MAPPER, this); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -490,15 +487,12 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { public List list(int offset, int limit) { List result = new ArrayList<>(); try { - taskanaHistoryEngine.openConnection(); + internalTaskanaEngine.openConnection(); RowBounds rowBounds = new RowBounds(offset, limit); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_MAPPER, this, rowBounds); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_MAPPER, this, rowBounds); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -512,17 +506,14 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { this.addOrderCriteria(columnName.toString(), sortDirection); try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectList(LINK_TO_VALUE_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectList(LINK_TO_VALUE_MAPPER, this); return result; } finally { this.orderBy = cacheOrderBy; this.columnName = null; this.orderColumns.remove(orderColumns.size() - 1); - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -530,15 +521,12 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { public WorkbasketHistoryEvent single() { WorkbasketHistoryEvent result = null; try { - taskanaHistoryEngine.openConnection(); - result = taskanaHistoryEngine.getSqlSession().selectOne(LINK_TO_MAPPER, this); + internalTaskanaEngine.openConnection(); + result = internalTaskanaEngine.getSqlSession().selectOne(LINK_TO_MAPPER, this); - return result; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); return result; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } @@ -546,14 +534,11 @@ public class WorkbasketHistoryQueryImpl implements WorkbasketHistoryQuery { public long count() { Long rowCount; try { - taskanaHistoryEngine.openConnection(); - rowCount = taskanaHistoryEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); + internalTaskanaEngine.openConnection(); + rowCount = internalTaskanaEngine.getSqlSession().selectOne(LINK_TO_COUNTER, this); return (rowCount == null) ? 0L : rowCount; - } catch (SQLException e) { - LOGGER.error(SQL_EXCEPTION_MESSAGE, e.getCause()); - return -1; } finally { - taskanaHistoryEngine.returnConnection(); + internalTaskanaEngine.returnConnection(); } } diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java index 75e9ec7d7..a426cc758 100644 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java +++ b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java @@ -25,32 +25,31 @@ import pro.taskana.common.internal.jobs.AbstractTaskanaJob; import pro.taskana.common.internal.transaction.TaskanaTransactionProvider; import pro.taskana.common.internal.util.CollectionUtil; import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl; -import pro.taskana.simplehistory.impl.TaskanaHistoryEngineImpl; import pro.taskana.spi.history.api.events.task.TaskHistoryEvent; import pro.taskana.spi.history.api.events.task.TaskHistoryEventType; public class HistoryCleanupJob extends AbstractTaskanaJob { private static final Logger LOGGER = LoggerFactory.getLogger(HistoryCleanupJob.class); - - private final TaskanaHistoryEngineImpl taskanaHistoryEngine = - TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngineImpl); - private final boolean allCompletedSameParentBusiness = taskanaEngineImpl .getConfiguration() .isSimpleHistoryCleanupJobAllCompletedSameParentBusiness(); - private final Duration minimumAge = taskanaEngineImpl.getConfiguration().getSimpleHistoryCleanupJobMinimumAge(); private final int batchSize = taskanaEngineImpl.getConfiguration().getSimpleHistoryCleanupJobBatchSize(); + private SimpleHistoryServiceImpl simpleHistoryService = null; public HistoryCleanupJob( TaskanaEngine taskanaEngine, TaskanaTransactionProvider txProvider, ScheduledJob scheduledJob) { super(taskanaEngine, txProvider, scheduledJob, true); + if (simpleHistoryService == null) { + simpleHistoryService = new SimpleHistoryServiceImpl(); + simpleHistoryService.initialize(taskanaEngine); + } } public static Duration getLockExpirationPeriod(TaskanaConfiguration taskanaConfiguration) { @@ -62,9 +61,6 @@ public class HistoryCleanupJob extends AbstractTaskanaJob { Instant createdBefore = Instant.now().minus(minimumAge); LOGGER.info("Running job to delete all history events created before ({})", createdBefore); try { - SimpleHistoryServiceImpl simpleHistoryService = - (SimpleHistoryServiceImpl) taskanaHistoryEngine.getTaskanaHistoryService(); - List historyEventCandidatesToClean = simpleHistoryService .createTaskHistoryQuery() @@ -181,9 +177,6 @@ public class HistoryCleanupJob extends AbstractTaskanaJob { private int deleteEvents(List taskIdsToDeleteHistoryEventsFor) throws InvalidArgumentException, NotAuthorizedException { - SimpleHistoryServiceImpl simpleHistoryService = - (SimpleHistoryServiceImpl) taskanaHistoryEngine.getTaskanaHistoryService(); - int deletedTasksCount = (int) simpleHistoryService diff --git a/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java b/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java index d9de26692..2c776c215 100644 --- a/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java @@ -19,7 +19,6 @@ import pro.taskana.common.internal.util.IdGenerator; import pro.taskana.common.test.config.DataSourceGenerator; import pro.taskana.sampledata.SampleDataGenerator; import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl; -import pro.taskana.simplehistory.impl.TaskanaHistoryEngineImpl; import pro.taskana.simplehistory.impl.classification.ClassificationHistoryEventMapper; import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper; import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryEventMapper; @@ -33,7 +32,6 @@ import pro.taskana.task.internal.models.ObjectReferenceImpl; public abstract class AbstractAccTest { protected static TaskanaConfiguration taskanaConfiguration; - protected static TaskanaHistoryEngineImpl taskanaHistoryEngine; protected static TaskanaEngine taskanaEngine; protected static SimpleHistoryServiceImpl historyService; @@ -116,7 +114,6 @@ public abstract class AbstractAccTest { taskanaConfiguration = configuration; taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaConfiguration, ConnectionManagementMode.AUTOCOMMIT); - taskanaHistoryEngine = TaskanaHistoryEngineImpl.createTaskanaEngine(taskanaEngine); taskService = taskanaEngine.getTaskService(); historyService = new SimpleHistoryServiceImpl(); historyService.initialize(taskanaEngine); @@ -129,10 +126,10 @@ public abstract class AbstractAccTest { protected TaskHistoryQueryMapper getHistoryQueryMapper() throws NoSuchFieldException, IllegalAccessException { - Field sessionManagerField = TaskanaHistoryEngineImpl.class.getDeclaredField("sessionManager"); + Field sessionManagerField = TaskanaEngineImpl.class.getDeclaredField("sessionManager"); sessionManagerField.setAccessible(true); SqlSessionManager sqlSessionManager = - (SqlSessionManager) sessionManagerField.get(taskanaHistoryEngine); + (SqlSessionManager) sessionManagerField.get(taskanaEngine); return sqlSessionManager.getMapper(TaskHistoryQueryMapper.class); } @@ -160,32 +157,32 @@ public abstract class AbstractAccTest { protected static WorkbasketHistoryEventMapper getWorkbasketHistoryEventMapper() { try { - Field sessionManager = TaskanaHistoryEngineImpl.class.getDeclaredField("sessionManager"); + Field sessionManager = TaskanaEngineImpl.class.getDeclaredField("sessionManager"); sessionManager.setAccessible(true); - SqlSessionManager manager = (SqlSessionManager) sessionManager.get(taskanaHistoryEngine); + SqlSessionManager manager = (SqlSessionManager) sessionManager.get(taskanaEngine); return manager.getMapper(WorkbasketHistoryEventMapper.class); } catch (Exception e) { throw new JUnitException( String.format( "Could not extract %s from %s", - WorkbasketHistoryEventMapper.class, TaskanaHistoryEngineImpl.class)); + WorkbasketHistoryEventMapper.class, TaskanaEngineImpl.class)); } } protected static ClassificationHistoryEventMapper getClassificationHistoryEventMapper() { try { - Field sessionManager = TaskanaHistoryEngineImpl.class.getDeclaredField("sessionManager"); + Field sessionManager = TaskanaEngineImpl.class.getDeclaredField("sessionManager"); sessionManager.setAccessible(true); - SqlSessionManager manager = (SqlSessionManager) sessionManager.get(taskanaHistoryEngine); + SqlSessionManager manager = (SqlSessionManager) sessionManager.get(taskanaEngine); return manager.getMapper(ClassificationHistoryEventMapper.class); } catch (Exception e) { throw new JUnitException( String.format( "Could not extract %s from %s", - ClassificationHistoryEventMapper.class, TaskanaHistoryEngineImpl.class)); + ClassificationHistoryEventMapper.class, TaskanaEngineImpl.class)); } } diff --git a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/classification/CreateHistoryEventOnClassificationDeletionAccTest.java b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/classification/CreateHistoryEventOnClassificationDeletionAccTest.java index 1bc95daf1..d30c1438e 100644 --- a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/classification/CreateHistoryEventOnClassificationDeletionAccTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/classification/CreateHistoryEventOnClassificationDeletionAccTest.java @@ -30,6 +30,9 @@ class CreateHistoryEventOnClassificationDeletionAccTest extends AbstractAccTest final String classificationId = "CLI:200000000000000000000000000000000015"; + taskService.createTaskQuery().list(); + historyService.deleteHistoryEventsByTaskIds(List.of("test12")); + List events = historyService .createClassificationHistoryQuery() diff --git a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java index 8c70d3022..47f00fcee 100644 --- a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java @@ -26,10 +26,10 @@ import pro.taskana.testapi.builder.TaskBuilder; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.models.WorkbasketSummary; +@TaskanaIntegrationTest @WithServiceProvider( serviceProviderInterface = TaskanaHistory.class, serviceProviders = SimpleHistoryServiceImpl.class) -@TaskanaIntegrationTest @ExtendWith(JaasExtension.class) class CreateHistoryEventOnTaskDeletionAccTest { @TaskanaInject TaskanaEngine taskanaEngine; @@ -47,8 +47,6 @@ class CreateHistoryEventOnTaskDeletionAccTest { @WithAccessId(user = "admin") @BeforeAll void setUp() throws Exception { - historyService = new SimpleHistoryServiceImpl(); - historyService.initialize(taskanaEngine); defaultClassificationSummary = DefaultTestEntities.defaultTestClassification() @@ -60,11 +58,15 @@ class CreateHistoryEventOnTaskDeletionAccTest { task2 = createTask().state(TaskState.COMPLETED).buildAndStore(taskService); task3 = createTask().state(TaskState.COMPLETED).buildAndStore(taskService); task4 = createTask().state(TaskState.COMPLETED).buildAndStore(taskService); + + historyService = new SimpleHistoryServiceImpl(); + historyService.initialize(taskanaEngine); } @WithAccessId(user = "admin") @Test void should_CreateDeleteHistoryEvent_When_TaskIsDeleted() throws Exception { + historyService.deleteHistoryEventsByTaskIds(List.of(task4.getId())); taskService.deleteTask(task4.getId()); diff --git a/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImplTest.java b/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImplTest.java index 1656d4659..b2e01f2c4 100644 --- a/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImplTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/ClassificationHistoryQueryImplTest.java @@ -14,6 +14,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import pro.taskana.common.internal.InternalTaskanaEngine; import pro.taskana.common.internal.util.IdGenerator; import pro.taskana.spi.history.api.events.classification.ClassificationHistoryEvent; import pro.taskana.spi.history.api.events.classification.ClassificationHistoryEventType; @@ -24,13 +25,13 @@ class ClassificationHistoryQueryImplTest { private ClassificationHistoryQueryImpl historyQueryImpl; - @Mock private TaskanaHistoryEngineImpl taskanaHistoryEngineMock; + @Mock private InternalTaskanaEngine internalTaskanaEngineMock; @Mock private SqlSession sqlSessionMock; @BeforeEach void setup() { - historyQueryImpl = new ClassificationHistoryQueryImpl(taskanaHistoryEngineMock); + historyQueryImpl = new ClassificationHistoryQueryImpl(internalTaskanaEngineMock); } @Test @@ -40,9 +41,9 @@ class ClassificationHistoryQueryImplTest { createHistoryEvent( ClassificationHistoryEventType.CREATED.getName(), "admin", "someDetails")); - doNothing().when(taskanaHistoryEngineMock).openConnection(); - doNothing().when(taskanaHistoryEngineMock).returnConnection(); - when(taskanaHistoryEngineMock.getSqlSession()).thenReturn(sqlSessionMock); + doNothing().when(internalTaskanaEngineMock).openConnection(); + doNothing().when(internalTaskanaEngineMock).returnConnection(); + when(internalTaskanaEngineMock.getSqlSession()).thenReturn(sqlSessionMock); when(sqlSessionMock.selectList(any(), any())).thenReturn(new ArrayList<>(returnList)); List result = diff --git a/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImplTest.java b/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImplTest.java index d73434585..828946621 100644 --- a/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImplTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/SimpleHistoryServiceImplTest.java @@ -19,6 +19,7 @@ import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.internal.InternalTaskanaEngine; import pro.taskana.simplehistory.impl.task.TaskHistoryEventMapper; import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper; import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryEventMapper; @@ -40,13 +41,12 @@ class SimpleHistoryServiceImplTest { @Mock private WorkbasketHistoryEventMapper workbasketHistoryEventMapperMock; @Mock private WorkbasketHistoryQueryMapper workbasketHistoryQueryMapperMock; - - @Mock private TaskanaHistoryEngineImpl taskanaHistoryEngineMock; - @Mock private TaskanaConfiguration taskanaConfiguration; @Mock private TaskanaEngine taskanaEngine; + @Mock private InternalTaskanaEngine internalTaskanaEngine; + @Mock private SqlSessionManager sqlSessionManagerMock; @Mock private SqlSession sqlSessionMock; @@ -58,9 +58,7 @@ class SimpleHistoryServiceImplTest { "wbKey1", "taskId1", "type1", "wbKey2", "someUserId", "someDetails"); cutSpy.create(expectedWb); - verify(taskanaHistoryEngineMock, times(1)).openConnection(); verify(taskHistoryEventMapperMock, times(1)).insert(expectedWb); - verify(taskanaHistoryEngineMock, times(1)).returnConnection(); assertThat(expectedWb.getCreated()).isNotNull(); } @@ -71,9 +69,7 @@ class SimpleHistoryServiceImplTest { "wbKey1", WorkbasketHistoryEventType.CREATED.getName(), "someUserId", "someDetails"); cutSpy.create(expectedEvent); - verify(taskanaHistoryEngineMock, times(1)).openConnection(); verify(workbasketHistoryEventMapperMock, times(1)).insert(expectedEvent); - verify(taskanaHistoryEngineMock, times(1)).returnConnection(); assertThat(expectedEvent.getCreated()).isNotNull(); } @@ -84,20 +80,21 @@ class SimpleHistoryServiceImplTest { AbstractAccTest.createTaskHistoryEvent( "wbKey1", "taskId1", "type1", "wbKey2", "someUserId", "someDetails")); - when(taskanaHistoryEngineMock.getConfiguration()).thenReturn(taskanaConfiguration); when(taskanaConfiguration.isAddAdditionalUserInfo()).thenReturn(false); - when(taskanaHistoryEngineMock.getSqlSession()).thenReturn(sqlSessionMock); + when(internalTaskanaEngine.getSqlSession()).thenReturn(sqlSessionMock); when(sqlSessionMock.selectList(any(), any())).thenReturn(new ArrayList<>(returnList)); + when(internalTaskanaEngine.getEngine()).thenReturn(taskanaEngine); + when(taskanaEngine.getConfiguration()).thenReturn(taskanaConfiguration); final List result = cutSpy.createTaskHistoryQuery().taskIdIn("taskId1").list(); - verify(taskanaHistoryEngineMock, times(1)).openConnection(); - verify(taskanaHistoryEngineMock, times(1)).getSqlSession(); + verify(internalTaskanaEngine, times(1)).openConnection(); + verify(internalTaskanaEngine, times(1)).getSqlSession(); verify(sqlSessionMock, times(1)).selectList(any(), any()); - verify(taskanaHistoryEngineMock, times(1)).returnConnection(); + verify(internalTaskanaEngine, times(1)).returnConnection(); assertThat(result).hasSize(returnList.size()); assertThat(result.get(0).getWorkbasketKey()).isEqualTo(returnList.get(0).getWorkbasketKey()); } @@ -108,16 +105,15 @@ class SimpleHistoryServiceImplTest { returnList.add( AbstractAccTest.createWorkbasketHistoryEvent( "wbKey1", WorkbasketHistoryEventType.CREATED.getName(), "someUserId", "someDetails")); - when(taskanaHistoryEngineMock.getSqlSession()).thenReturn(sqlSessionMock); when(sqlSessionMock.selectList(any(), any())).thenReturn(new ArrayList<>(returnList)); - + when(internalTaskanaEngine.getSqlSession()).thenReturn(sqlSessionMock); final List result = cutSpy.createWorkbasketHistoryQuery().keyIn("wbKey1").list(); - verify(taskanaHistoryEngineMock, times(1)).openConnection(); - verify(taskanaHistoryEngineMock, times(1)).getSqlSession(); + verify(internalTaskanaEngine, times(1)).openConnection(); + verify(internalTaskanaEngine, times(1)).getSqlSession(); verify(sqlSessionMock, times(1)).selectList(any(), any()); - verify(taskanaHistoryEngineMock, times(1)).returnConnection(); + verify(internalTaskanaEngine, times(1)).returnConnection(); assertThat(result).hasSize(returnList.size()); assertThat(result.get(0).getKey()).isEqualTo(returnList.get(0).getKey()); } diff --git a/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImplTest.java b/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImplTest.java index b8fc404e5..5c02b3c8b 100644 --- a/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImplTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/pro/taskana/simplehistory/impl/WorkbasketHistoryQueryImplTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import pro.taskana.common.api.TimeInterval; +import pro.taskana.common.internal.InternalTaskanaEngine; import pro.taskana.common.internal.util.IdGenerator; import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEvent; import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEventType; @@ -24,7 +25,7 @@ import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEventType; @ExtendWith(MockitoExtension.class) class WorkbasketHistoryQueryImplTest { - @Mock private TaskanaHistoryEngineImpl taskanaHistoryEngineMock; + @Mock private InternalTaskanaEngine internalTaskanaEngineMock; private WorkbasketHistoryQueryImpl historyQueryImpl; @@ -32,7 +33,7 @@ class WorkbasketHistoryQueryImplTest { @BeforeEach void setup() { - historyQueryImpl = new WorkbasketHistoryQueryImpl(taskanaHistoryEngineMock); + historyQueryImpl = new WorkbasketHistoryQueryImpl(internalTaskanaEngineMock); } @Test @@ -47,9 +48,9 @@ class WorkbasketHistoryQueryImplTest { null)); TimeInterval interval = new TimeInterval(Instant.now().minusNanos(1000), Instant.now()); - doNothing().when(taskanaHistoryEngineMock).openConnection(); - doNothing().when(taskanaHistoryEngineMock).returnConnection(); - when(taskanaHistoryEngineMock.getSqlSession()).thenReturn(sqlSessionMock); + doNothing().when(internalTaskanaEngineMock).openConnection(); + doNothing().when(internalTaskanaEngineMock).returnConnection(); + when(internalTaskanaEngineMock.getSqlSession()).thenReturn(sqlSessionMock); when(sqlSessionMock.selectList(any(), any())).thenReturn(new ArrayList<>(returnList)); List result = diff --git a/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java b/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java index 79d3f7bda..f0b8c5899 100644 --- a/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java +++ b/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java @@ -2,7 +2,6 @@ package pro.taskana.simplehistory.rest; import jakarta.servlet.http.HttpServletRequest; import java.beans.ConstructorProperties; -import java.sql.SQLException; import java.util.List; import java.util.function.BiConsumer; import org.springframework.beans.factory.annotation.Autowired; @@ -14,7 +13,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.BaseQuery.SortDirection; import pro.taskana.common.api.TaskanaEngine; import pro.taskana.common.api.exceptions.InvalidArgumentException; @@ -35,19 +33,17 @@ import pro.taskana.spi.history.api.exceptions.TaskanaHistoryEventNotFoundExcepti @RestController @EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL) public class TaskHistoryEventController { - private final SimpleHistoryServiceImpl simpleHistoryService; private final TaskHistoryEventRepresentationModelAssembler assembler; @Autowired public TaskHistoryEventController( - TaskanaConfiguration taskanaConfiguration, + TaskanaEngine taskanaEngine, SimpleHistoryServiceImpl simpleHistoryServiceImpl, - TaskHistoryEventRepresentationModelAssembler assembler) - throws SQLException { + TaskHistoryEventRepresentationModelAssembler assembler) { this.simpleHistoryService = simpleHistoryServiceImpl; - this.simpleHistoryService.initialize(TaskanaEngine.buildTaskanaEngine(taskanaConfiguration)); + this.simpleHistoryService.initialize(taskanaEngine); this.assembler = assembler; } diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java b/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java index d67b0e62b..111c02efe 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java @@ -2,6 +2,7 @@ package pro.taskana.common.api; import java.sql.SQLException; import java.util.function.Supplier; +import org.apache.ibatis.transaction.TransactionFactory; import pro.taskana.TaskanaConfiguration; import pro.taskana.classification.api.ClassificationService; import pro.taskana.common.api.exceptions.NotAuthorizedException; @@ -93,7 +94,7 @@ public interface TaskanaEngine { */ @SuppressWarnings("checkstyle:JavadocMethod") static TaskanaEngine buildTaskanaEngine(TaskanaConfiguration configuration) throws SQLException { - return buildTaskanaEngine(configuration, ConnectionManagementMode.PARTICIPATE); + return buildTaskanaEngine(configuration, ConnectionManagementMode.PARTICIPATE, null); } /** @@ -108,7 +109,26 @@ public interface TaskanaEngine { static TaskanaEngine buildTaskanaEngine( TaskanaConfiguration configuration, ConnectionManagementMode connectionManagementMode) throws SQLException { - return TaskanaEngineImpl.createTaskanaEngine(configuration, connectionManagementMode); + return buildTaskanaEngine(configuration, connectionManagementMode, null); + } + + /** + * Builds an {@linkplain TaskanaEngine} based on {@linkplain TaskanaConfiguration}, + * SqlConnectionMode and TransactionFactory. + * + * @param configuration complete taskanaConfig to build the engine + * @param connectionManagementMode connectionMode for the SqlSession + * @param transactionFactory the TransactionFactory + * @return a {@linkplain TaskanaEngineImpl} + * @throws SQLException when the db schema could not be initialized + */ + static TaskanaEngine buildTaskanaEngine( + TaskanaConfiguration configuration, + ConnectionManagementMode connectionManagementMode, + TransactionFactory transactionFactory) + throws SQLException { + return TaskanaEngineImpl.createTaskanaEngine( + configuration, connectionManagementMode, transactionFactory); } /** diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java index 73d5da160..7ebd4971e 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java @@ -112,7 +112,9 @@ public class TaskanaEngineImpl implements TaskanaEngine { protected Connection connection; protected TaskanaEngineImpl( - TaskanaConfiguration taskanaConfiguration, ConnectionManagementMode connectionManagementMode) + TaskanaConfiguration taskanaConfiguration, + ConnectionManagementMode connectionManagementMode, + TransactionFactory transactionFactory) throws SQLException { LOGGER.info( "initializing TASKANA with this configuration: {} and this mode: {}", @@ -146,7 +148,11 @@ public class TaskanaEngineImpl implements TaskanaEngine { currentUserContext = new CurrentUserContextImpl(TaskanaConfiguration.shouldUseLowerCaseForAccessIds()); - createTransactionFactory(taskanaConfiguration.isUseManagedTransactions()); + if (transactionFactory == null) { + createTransactionFactory(taskanaConfiguration.isUseManagedTransactions()); + } else { + this.transactionFactory = transactionFactory; + } sessionManager = createSqlSessionManager(); initializeDbSchema(taskanaConfiguration); @@ -156,7 +162,8 @@ public class TaskanaEngineImpl implements TaskanaEngine { new TaskanaConfiguration.Builder(this.taskanaConfiguration) .jobSchedulerEnabled(false) .build(); - TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(configuration, EXPLICIT); + TaskanaEngine taskanaEngine = + TaskanaEngine.buildTaskanaEngine(configuration, EXPLICIT, transactionFactory); RealClock clock = new RealClock( this.taskanaConfiguration.getJobSchedulerInitialStartDelay(), @@ -186,9 +193,12 @@ public class TaskanaEngineImpl implements TaskanaEngine { } public static TaskanaEngine createTaskanaEngine( - TaskanaConfiguration taskanaConfiguration, ConnectionManagementMode connectionManagementMode) + TaskanaConfiguration taskanaConfiguration, + ConnectionManagementMode connectionManagementMode, + TransactionFactory transactionFactory) throws SQLException { - return new TaskanaEngineImpl(taskanaConfiguration, connectionManagementMode); + return new TaskanaEngineImpl( + taskanaConfiguration, connectionManagementMode, transactionFactory); } @Override @@ -246,7 +256,11 @@ public class TaskanaEngineImpl implements TaskanaEngine { connection.setAutoCommit(false); connection.setSchema(taskanaConfiguration.getSchemaName()); mode = EXPLICIT; - sessionManager.startManagedSession(connection); + if (transactionFactory.getClass().getSimpleName().equals("SpringManagedTransactionFactory")) { + sessionManager.startManagedSession(); + } else { + sessionManager.startManagedSession(connection); + } } else if (this.connection != null) { closeConnection(); } diff --git a/lib/taskana-spring/src/main/java/pro/taskana/common/internal/SpringTaskanaEngineImpl.java b/lib/taskana-spring/src/main/java/pro/taskana/common/internal/SpringTaskanaEngineImpl.java index 3f291238b..84422ddcb 100644 --- a/lib/taskana-spring/src/main/java/pro/taskana/common/internal/SpringTaskanaEngineImpl.java +++ b/lib/taskana-spring/src/main/java/pro/taskana/common/internal/SpringTaskanaEngineImpl.java @@ -10,9 +10,7 @@ public class SpringTaskanaEngineImpl extends TaskanaEngineImpl implements Spring public SpringTaskanaEngineImpl( TaskanaConfiguration taskanaConfiguration, ConnectionManagementMode mode) throws SQLException { - super(taskanaConfiguration, mode); - this.transactionFactory = new SpringManagedTransactionFactory(); - this.sessionManager = createSqlSessionManager(); + super(taskanaConfiguration, mode, new SpringManagedTransactionFactory()); } public static SpringTaskanaEngine createTaskanaEngine( diff --git a/rest/taskana-rest-spring-example-boot/src/main/java/pro/taskana/example/boot/ExampleRestConfiguration.java b/rest/taskana-rest-spring-example-boot/src/main/java/pro/taskana/example/boot/ExampleRestConfiguration.java index 4828aded1..2f308edf5 100644 --- a/rest/taskana-rest-spring-example-boot/src/main/java/pro/taskana/example/boot/ExampleRestConfiguration.java +++ b/rest/taskana-rest-spring-example-boot/src/main/java/pro/taskana/example/boot/ExampleRestConfiguration.java @@ -11,6 +11,7 @@ import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.internal.SpringTaskanaEngine; import pro.taskana.common.internal.configuration.DbSchemaCreator; import pro.taskana.sampledata.SampleDataGenerator; @@ -44,7 +45,7 @@ public class ExampleRestConfiguration { @DependsOn("generateSampleData") public TaskanaEngine getTaskanaEngine(TaskanaConfiguration taskanaConfiguration) throws SQLException { - return TaskanaEngine.buildTaskanaEngine(taskanaConfiguration); + return SpringTaskanaEngine.buildTaskanaEngine(taskanaConfiguration); } // only required to let the adapter example connect to the same database