diff --git a/lib/taskana-cdi-example/src/main/java/pro/taskana/ExampleBootstrap.java b/lib/taskana-cdi-example/src/main/java/pro/taskana/ExampleBootstrap.java
index 9b5aa026e..0b34f7826 100644
--- a/lib/taskana-cdi-example/src/main/java/pro/taskana/ExampleBootstrap.java
+++ b/lib/taskana-cdi-example/src/main/java/pro/taskana/ExampleBootstrap.java
@@ -10,7 +10,6 @@ import pro.taskana.exceptions.ClassificationNotFoundException;
import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.InvalidOwnerException;
import pro.taskana.exceptions.InvalidStateException;
-import pro.taskana.exceptions.InvalidWorkbasketException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.TaskAlreadyExistException;
import pro.taskana.exceptions.TaskNotFoundException;
@@ -25,8 +24,8 @@ public class ExampleBootstrap {
@PostConstruct
public void init(@Observes @Initialized(ApplicationScoped.class) Object init)
throws TaskNotFoundException, NotAuthorizedException, WorkbasketNotFoundException,
- ClassificationNotFoundException, InvalidStateException, InvalidOwnerException, InvalidWorkbasketException,
- TaskAlreadyExistException, InvalidArgumentException {
+ ClassificationNotFoundException, InvalidStateException, InvalidOwnerException, TaskAlreadyExistException,
+ InvalidArgumentException {
System.out.println("---------------------------> Start App");
Task task = taskanaEjb.getTaskService().newTask(null);
ObjectReference objRef = new ObjectReference();
diff --git a/lib/taskana-cdi/src/main/java/pro/taskana/TaskanaProducers.java b/lib/taskana-cdi/src/main/java/pro/taskana/TaskanaProducers.java
index b4881a130..02aa5240f 100644
--- a/lib/taskana-cdi/src/main/java/pro/taskana/TaskanaProducers.java
+++ b/lib/taskana-cdi/src/main/java/pro/taskana/TaskanaProducers.java
@@ -1,8 +1,9 @@
package pro.taskana;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import pro.taskana.configuration.TaskanaEngineConfiguration;
+import java.io.IOException;
+import java.io.InputStream;
+import java.sql.SQLException;
+import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
@@ -12,64 +13,65 @@ import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
-import java.io.IOException;
-import java.io.InputStream;
-import java.sql.SQLException;
-import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pro.taskana.configuration.TaskanaEngineConfiguration;
@ApplicationScoped
public class TaskanaProducers {
- private static final Logger logger = LoggerFactory.getLogger(TaskanaProducers.class);
+ private static final Logger logger = LoggerFactory.getLogger(TaskanaProducers.class);
- private static final String TASKANA_PROPERTIES = "taskana.properties";
+ private static final String TASKANA_PROPERTIES = "taskana.properties";
- @Inject
- private TaskanaEngine taskanaEngine;
+ @Inject
+ private TaskanaEngine taskanaEngine;
- private TaskanaEngineConfiguration taskanaEngineConfiguration;
+ private TaskanaEngineConfiguration taskanaEngineConfiguration;
- @PostConstruct
- public void init() {
- // Load Properties and get Datasource via Context
- // Load DataSource via Container
- Context ctx;
- DataSource dataSource;
- ClassLoader classloader = Thread.currentThread().getContextClassLoader();
- try (InputStream propertyStream = classloader.getResourceAsStream(TASKANA_PROPERTIES)) {
- Properties properties = new Properties();
- ctx = new InitialContext();
- properties.load(propertyStream);
- dataSource = (DataSource) ctx.lookup(properties.getProperty("datasource.jndi"));
- logger.debug("---------------> " + dataSource.getConnection().getMetaData());
- this.taskanaEngineConfiguration = new TaskanaEngineConfiguration(dataSource, true, false);
- } catch (NamingException | SQLException | IOException e) {
- logger.error("Could not start Taskana: ", e);
- }
- }
+ @PostConstruct
+ public void init() {
+ // Load Properties and get Datasource via Context
+ // Load DataSource via Container
+ Context ctx;
+ DataSource dataSource;
+ ClassLoader classloader = Thread.currentThread().getContextClassLoader();
+ try (InputStream propertyStream = classloader.getResourceAsStream(TASKANA_PROPERTIES)) {
+ Properties properties = new Properties();
+ ctx = new InitialContext();
+ properties.load(propertyStream);
+ dataSource = (DataSource) ctx.lookup(properties.getProperty("datasource.jndi"));
+ logger.debug("---------------> " + dataSource.getConnection().getMetaData());
+ this.taskanaEngineConfiguration = new TaskanaEngineConfiguration(dataSource, true, false);
+ } catch (NamingException | SQLException | IOException e) {
+ logger.error("Could not start Taskana: ", e);
+ }
+ }
- @ApplicationScoped
- @Produces
- public TaskanaEngine generateTaskEngine() throws SQLException {
- return taskanaEngineConfiguration.buildTaskanaEngine();
- }
+ @ApplicationScoped
+ @Produces
+ public TaskanaEngine generateTaskEngine() {
+ return taskanaEngineConfiguration.buildTaskanaEngine();
+ }
- @ApplicationScoped
- @Produces
- public TaskService generateTaskService() {
- return taskanaEngine.getTaskService();
- }
+ @ApplicationScoped
+ @Produces
+ public TaskService generateTaskService() {
+ return taskanaEngine.getTaskService();
+ }
- @ApplicationScoped
- @Produces
- public ClassificationService generateClassificationService() {
- return taskanaEngine.getClassificationService();
- }
+ @ApplicationScoped
+ @Produces
+ public ClassificationService generateClassificationService() {
+ return taskanaEngine.getClassificationService();
+ }
- @ApplicationScoped
- @Produces
- public WorkbasketService generateWorkbasketService() {
- return taskanaEngine.getWorkbasketService();
- }
+ @ApplicationScoped
+ @Produces
+ public WorkbasketService generateWorkbasketService() {
+ return taskanaEngine.getWorkbasketService();
+ }
}
diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java
index d27ab2cb9..5afb3e1fe 100644
--- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java
+++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java
@@ -5,7 +5,6 @@ import javax.inject.Inject;
import pro.taskana.exceptions.ClassificationNotFoundException;
import pro.taskana.exceptions.InvalidArgumentException;
-import pro.taskana.exceptions.InvalidWorkbasketException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.TaskAlreadyExistException;
import pro.taskana.exceptions.WorkbasketNotFoundException;
@@ -35,8 +34,7 @@ public class TaskanaEjb {
}
public void triggerRollback() throws NotAuthorizedException, WorkbasketNotFoundException,
- ClassificationNotFoundException, TaskAlreadyExistException, InvalidWorkbasketException,
- InvalidArgumentException {
+ ClassificationNotFoundException, TaskAlreadyExistException, InvalidArgumentException {
Task task = taskService.newTask(null);
ObjectReference objRef = new ObjectReference();
objRef.setCompany("aCompany");
diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaProducersTest.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaProducersTest.java
index df53ebdf4..45ee8be15 100644
--- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaProducersTest.java
+++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaProducersTest.java
@@ -5,7 +5,6 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
-import javax.naming.NamingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
@@ -14,7 +13,6 @@ import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.swarm.Swarm;
@@ -45,12 +43,8 @@ public class TaskanaProducersTest {
return swarm;
}
- @Before
- public void init() throws SQLException, ClassNotFoundException {
- }
-
@Test
- public void testCommit() throws SQLException, ClassNotFoundException, NamingException {
+ public void testCommit() throws SQLException, ClassNotFoundException {
Client client = ClientBuilder.newClient();
client.target("http://127.0.0.1:8090/rest/test").request().get();
@@ -70,7 +64,7 @@ public class TaskanaProducersTest {
}
@Test
- public void testRollback() throws SQLException, ClassNotFoundException, NamingException {
+ public void testRollback() throws SQLException, ClassNotFoundException {
Client client = ClientBuilder.newClient();
client.target("http://127.0.0.1:8090/rest/test").request().post(null);
diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaRestTest.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaRestTest.java
index 186d44131..fe5cd5232 100644
--- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaRestTest.java
+++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaRestTest.java
@@ -66,7 +66,7 @@ public class TaskanaRestTest {
@POST
public Response rollbackTask()
throws NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException,
- InvalidWorkbasketException, TaskAlreadyExistException, InvalidArgumentException {
+ TaskAlreadyExistException, InvalidArgumentException {
taskanaEjb.triggerRollback();
return Response.status(204).build();
}
@@ -74,8 +74,7 @@ public class TaskanaRestTest {
@DELETE
@Path("{id}")
public void completeTask(@PathParam("id") String id)
- throws TaskNotFoundException, InvalidOwnerException, InvalidStateException, ClassificationNotFoundException,
- NotAuthorizedException {
+ throws TaskNotFoundException, InvalidOwnerException, InvalidStateException, NotAuthorizedException {
logger.info(id);
taskanaEjb.getTaskService().forceCompleteTask(id);
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/configuration/TaskanaEngineConfiguration.java b/lib/taskana-core/src/main/java/pro/taskana/configuration/TaskanaEngineConfiguration.java
index d58d9592a..0e8086bd4 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/configuration/TaskanaEngineConfiguration.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/configuration/TaskanaEngineConfiguration.java
@@ -1,343 +1,342 @@
-package pro.taskana.configuration;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.sql.SQLException;
-import java.time.LocalDate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.stream.Collectors;
-
-import javax.sql.DataSource;
-
-import org.apache.ibatis.datasource.pooled.PooledDataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import pro.taskana.TaskanaEngine;
-import pro.taskana.TaskanaRole;
-import pro.taskana.exceptions.SystemException;
-import pro.taskana.impl.TaskanaEngineImpl;
-import pro.taskana.impl.util.LoggerUtils;
-
-/**
- * This central class creates the TaskanaEngine and holds all the information about DB and Security.
- * Security is enabled by default.
- */
-public class TaskanaEngineConfiguration {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineConfiguration.class);
-
- private static final String USER_NAME = "sa";
- private static final String USER_PASSWORD = "sa";
- private static final String JDBC_H2_MEM_TASKANA = "jdbc:h2:mem:taskana;IGNORECASE=TRUE;LOCK_MODE=0;INIT=CREATE SCHEMA IF NOT EXISTS TASKANA";
- private static final String H2_DRIVER = "org.h2.Driver";
- private static final String TASKANA_PROPERTIES = "/taskana.properties";
- private static final String TASKANA_ROLES_SEPARATOR = "|";
- private static final String TASKANA_DOMAINS_PROPERTY = "taskana.domains";
- private static final String TASKANA_CLASSIFICATION_TYPES_PROPERTY = "taskana.classification.types";
- private static final String TASKANA_CLASSIFICATION_CATEGORIES_PROPERTY = "taskana.classification.categories";
-
- // Taskana properties file
- protected String propertiesFileName = TASKANA_PROPERTIES;
-
- // Taskana datasource configuration
- protected DataSource dataSource;
- protected DbSchemaCreator dbScriptRunner;
-
- // Taskana role configuration
- protected String rolesSeparator = TASKANA_ROLES_SEPARATOR;
- protected Map> roleMap = new HashMap<>();
-
- // global switch to enable JAAS based authentication and Taskana
- // authorizations
- protected boolean securityEnabled = true;
- protected boolean useManagedTransactions;
-
- // Properties for the monitor
- private boolean germanPublicHolidaysEnabled;
- private List customHolidays;
-
- // List of configured domain names
- protected List domains = new ArrayList();
-
- // List of configured classification types
- protected List classificationTypes = new ArrayList();
-
- // List of configured classification categories
- protected List classificationCategories = new ArrayList();
-
- public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions)
- throws SQLException {
- this(dataSource, useManagedTransactions, true);
- }
-
- public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions,
- boolean securityEnabled) throws SQLException {
- this(dataSource, useManagedTransactions, securityEnabled, null, null);
- }
-
- public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions,
- boolean securityEnabled, String propertiesFileName, String rolesSeparator) throws SQLException {
- this.useManagedTransactions = useManagedTransactions;
- this.securityEnabled = securityEnabled;
-
- if (propertiesFileName != null) {
- this.propertiesFileName = propertiesFileName;
- }
-
- if (rolesSeparator != null) {
- this.rolesSeparator = rolesSeparator;
- }
-
- initTaskanaProperties(this.propertiesFileName, this.rolesSeparator);
-
- if (dataSource != null) {
- this.dataSource = dataSource;
- } else {
- // use default In Memory datasource
- this.dataSource = createDefaultDataSource();
- }
- dbScriptRunner = new DbSchemaCreator(this.dataSource);
- dbScriptRunner.run();
-
- }
-
- public void initTaskanaProperties(String propertiesFile, String rolesSeparator) {
- LOGGER.debug("Reading taskana configuration from {} with role separator {}", propertiesFile, rolesSeparator);
- Properties props = readPropertiesFromFile(propertiesFile);
- initTaskanaRoles(props, rolesSeparator);
- initDomains(props);
- initClassificationTypes(props);
- initClassificationCategories(props);
- }
-
- private void initDomains(Properties props) {
- String domainNames = props.getProperty(TASKANA_DOMAINS_PROPERTY);
- if (domainNames != null && !domainNames.isEmpty()) {
- StringTokenizer st = new StringTokenizer(domainNames, ",");
- while (st.hasMoreTokens()) {
- domains.add(st.nextToken().trim().toUpperCase());
- }
- }
- LOGGER.debug("Configured domains: {}", domains);
- }
-
- private void initClassificationTypes(Properties props) {
- String classificationTypesNames = props.getProperty(TASKANA_CLASSIFICATION_TYPES_PROPERTY);
- if (classificationTypesNames != null && !classificationTypesNames.isEmpty()) {
- StringTokenizer st = new StringTokenizer(classificationTypesNames, ",");
- while (st.hasMoreTokens()) {
- classificationTypes.add(st.nextToken().trim().toUpperCase());
- }
- }
- LOGGER.debug("Configured domains: {}", domains);
- }
-
- private void initClassificationCategories(Properties props) {
- String classificationCategoryNames = props.getProperty(TASKANA_CLASSIFICATION_CATEGORIES_PROPERTY);
- if (classificationCategoryNames != null && !classificationCategoryNames.isEmpty()) {
- StringTokenizer st = new StringTokenizer(classificationCategoryNames, ",");
- while (st.hasMoreTokens()) {
- classificationCategories.add(st.nextToken().trim().toUpperCase());
- }
- }
- LOGGER.debug("Configured domains: {}", domains);
- }
-
- private void initTaskanaRoles(Properties props, String rolesSeparator) {
- List validPropertyNames = Arrays.stream(TaskanaRole.values())
- .map(TaskanaRole::getPropertyName)
- .collect(Collectors.toList());
- for (Object obj : props.keySet()) {
- String propertyName = ((String) obj);
- if (validPropertyNames.contains(propertyName.toLowerCase().trim())) {
- String propertyValue = props.getProperty(propertyName);
- Set roleMemberSet = new HashSet<>();
- StringTokenizer st = new StringTokenizer(propertyValue, rolesSeparator);
- while (st.hasMoreTokens()) {
- String token = st.nextToken().toLowerCase().trim();
- roleMemberSet.add(token);
- }
- TaskanaRole key = TaskanaRole.fromPropertyName(propertyName);
- if (key != null) {
- roleMap.put(key, roleMemberSet);
- } else {
- LOGGER.error("Internal System error when processing role property {}.", propertyName);
- throw new SystemException(
- "Internal System error when processing role property " + propertyName);
- }
- }
- }
- ensureRoleMapIsFullyInitialized();
-
- roleMap.forEach(
- (k, v) -> LOGGER.debug("Found Taskana RoleConfig {} : {} ", k, LoggerUtils.setToString(v)));
- }
-
- private Properties readPropertiesFromFile(String propertiesFile) {
- Properties props = new Properties();
- boolean loadFromClasspath = loadFromClasspath(propertiesFile);
- try {
- if (loadFromClasspath) {
- InputStream inputStream = this.getClass().getResourceAsStream(propertiesFile);
- if (inputStream == null) {
- LOGGER.error("taskana properties file {} was not found on classpath.",
- propertiesFile);
- } else {
- props.load(new InputStreamReader(inputStream));
- LOGGER.debug("Role properties were loaded from file {} from classpath.", propertiesFile);
- }
- } else {
- props.load(new FileInputStream(propertiesFile));
- LOGGER.debug("Role properties were loaded from file {}.", propertiesFile);
- }
- } catch (IOException e) {
- LOGGER.error("caught IOException when processing properties file {}.", propertiesFile);
- throw new SystemException("internal System error when processing properties file " + propertiesFile);
- }
- return props;
- }
-
- private boolean loadFromClasspath(String propertiesFile) {
- boolean loadFromClasspath = true;
- File f = new File(propertiesFile);
- if (f.exists() && !f.isDirectory()) {
- loadFromClasspath = false;
- }
- return loadFromClasspath;
- }
-
- private void ensureRoleMapIsFullyInitialized() {
- // make sure that roleMap does not return null for any role
- Arrays.stream(TaskanaRole.values())
- .forEach(role -> roleMap.putIfAbsent(role, new HashSet<>()));
- }
-
- public static DataSource createDefaultDataSource() {
- LOGGER.info("No datasource is provided. A inmemory db is used: "
- + "'org.h2.Driver', 'jdbc:h2:mem:taskana;IGNORECASE=TRUE;LOCK_MODE=0;INIT=CREATE SCHEMA IF NOT EXISTS TASKANA', 'sa', 'sa'");
- return createDatasource(H2_DRIVER, JDBC_H2_MEM_TASKANA, USER_NAME, USER_PASSWORD);
- }
-
- /**
- * This method creates the TaskanaEngine without an sqlSessionFactory.
- *
- * @return the TaskanaEngine
- */
- public TaskanaEngine buildTaskanaEngine() {
- return TaskanaEngineImpl.createTaskanaEngine(this);
- }
-
- /**
- * This method creates a PooledDataSource, if the needed properties are provided.
- *
- * @param driver
- * the name of the jdbc driver
- * @param jdbcUrl
- * the url to which the jdbc driver connects
- * @param username
- * the user name for database access
- * @param password
- * the password for database access
- * @return DataSource
- */
- public static DataSource createDatasource(String driver, String jdbcUrl, String username, String password) {
- return new PooledDataSource(driver, jdbcUrl, username, password);
- }
-
- public boolean isSecurityEnabled() {
- return this.securityEnabled;
- }
-
- public DataSource getDatasource() {
- return this.dataSource;
- }
-
- public boolean getUseManagedTransactions() {
- return this.useManagedTransactions;
- }
-
- public String getPropertiesFileName() {
- return this.propertiesFileName;
- }
-
- public void setPropertiesFileName(String propertiesFileName) {
- this.propertiesFileName = propertiesFileName;
- }
-
- public String getPropertiesSeparator() {
- return this.rolesSeparator;
- }
-
- public void setPropertiesSeparator(String propertiesSeparator) {
- this.rolesSeparator = propertiesSeparator;
- }
-
- public boolean isGermanPublicHolidaysEnabled() {
- return this.germanPublicHolidaysEnabled;
- }
-
- public void setGermanPublicHolidaysEnabled(boolean germanPublicHolidaysEnabled) {
- this.germanPublicHolidaysEnabled = germanPublicHolidaysEnabled;
- }
-
- public List getCustomHolidays() {
- return customHolidays;
- }
-
- public void setCustomHolidays(List customHolidays) {
- this.customHolidays = customHolidays;
- }
-
- public Map> getRoleMap() {
- return roleMap;
- }
-
- public void setRoleMap(Map> roleMap) {
- this.roleMap = roleMap;
- }
-
- public List getDomains() {
- return domains;
- }
-
- public void setDomains(List domains) {
- this.domains = domains;
- }
-
- public List getClassificationTypes() {
- return classificationTypes;
- }
-
- public void setClassificationTypes(List classificationTypes) {
- this.classificationTypes = classificationTypes;
- }
-
- public List getClassificationCategories() {
- return classificationCategories;
- }
-
- public void setClassificationCategories(List classificationCategories) {
- this.classificationCategories = classificationCategories;
- }
-
- /**
- * Helper method to determine whether all access ids (user Id and group ids) should be used in lower case.
- *
- * @return true if all access ids should be used in lower case, false otherwise
- */
- public static boolean shouldUseLowerCaseForAccessIds() {
- return true;
- }
-}
+package pro.taskana.configuration;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.stream.Collectors;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.datasource.pooled.PooledDataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pro.taskana.TaskanaEngine;
+import pro.taskana.TaskanaRole;
+import pro.taskana.exceptions.SystemException;
+import pro.taskana.impl.TaskanaEngineImpl;
+import pro.taskana.impl.util.LoggerUtils;
+
+/**
+ * This central class creates the TaskanaEngine and holds all the information about DB and Security.
+ * Security is enabled by default.
+ */
+public class TaskanaEngineConfiguration {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineConfiguration.class);
+
+ private static final String USER_NAME = "sa";
+ private static final String USER_PASSWORD = "sa";
+ private static final String JDBC_H2_MEM_TASKANA = "jdbc:h2:mem:taskana;IGNORECASE=TRUE;LOCK_MODE=0;INIT=CREATE SCHEMA IF NOT EXISTS TASKANA";
+ private static final String H2_DRIVER = "org.h2.Driver";
+ private static final String TASKANA_PROPERTIES = "/taskana.properties";
+ private static final String TASKANA_ROLES_SEPARATOR = "|";
+ private static final String TASKANA_DOMAINS_PROPERTY = "taskana.domains";
+ private static final String TASKANA_CLASSIFICATION_TYPES_PROPERTY = "taskana.classification.types";
+ private static final String TASKANA_CLASSIFICATION_CATEGORIES_PROPERTY = "taskana.classification.categories";
+
+ // Taskana properties file
+ protected String propertiesFileName = TASKANA_PROPERTIES;
+
+ // Taskana datasource configuration
+ protected DataSource dataSource;
+ protected DbSchemaCreator dbScriptRunner;
+
+ // Taskana role configuration
+ protected String rolesSeparator = TASKANA_ROLES_SEPARATOR;
+ protected Map> roleMap = new HashMap<>();
+
+ // global switch to enable JAAS based authentication and Taskana
+ // authorizations
+ protected boolean securityEnabled = true;
+ protected boolean useManagedTransactions;
+
+ // Properties for the monitor
+ private boolean germanPublicHolidaysEnabled;
+ private List customHolidays;
+
+ // List of configured domain names
+ protected List domains = new ArrayList();
+
+ // List of configured classification types
+ protected List classificationTypes = new ArrayList();
+
+ // List of configured classification categories
+ protected List classificationCategories = new ArrayList();
+
+ public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions)
+ throws SQLException {
+ this(dataSource, useManagedTransactions, true);
+ }
+
+ public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions,
+ boolean securityEnabled) throws SQLException {
+ this(dataSource, useManagedTransactions, securityEnabled, null, null);
+ }
+
+ public TaskanaEngineConfiguration(DataSource dataSource, boolean useManagedTransactions,
+ boolean securityEnabled, String propertiesFileName, String rolesSeparator) throws SQLException {
+ this.useManagedTransactions = useManagedTransactions;
+ this.securityEnabled = securityEnabled;
+
+ if (propertiesFileName != null) {
+ this.propertiesFileName = propertiesFileName;
+ }
+
+ if (rolesSeparator != null) {
+ this.rolesSeparator = rolesSeparator;
+ }
+
+ initTaskanaProperties(this.propertiesFileName, this.rolesSeparator);
+
+ if (dataSource != null) {
+ this.dataSource = dataSource;
+ } else {
+ // use default In Memory datasource
+ this.dataSource = createDefaultDataSource();
+ }
+ dbScriptRunner = new DbSchemaCreator(this.dataSource);
+ dbScriptRunner.run();
+
+ }
+
+ public void initTaskanaProperties(String propertiesFile, String rolesSeparator) {
+ LOGGER.debug("Reading taskana configuration from {} with role separator {}", propertiesFile, rolesSeparator);
+ Properties props = readPropertiesFromFile(propertiesFile);
+ initTaskanaRoles(props, rolesSeparator);
+ initDomains(props);
+ initClassificationTypes(props);
+ initClassificationCategories(props);
+ }
+
+ private void initDomains(Properties props) {
+ String domainNames = props.getProperty(TASKANA_DOMAINS_PROPERTY);
+ if (domainNames != null && !domainNames.isEmpty()) {
+ StringTokenizer st = new StringTokenizer(domainNames, ",");
+ while (st.hasMoreTokens()) {
+ domains.add(st.nextToken().trim().toUpperCase());
+ }
+ }
+ LOGGER.debug("Configured domains: {}", domains);
+ }
+
+ private void initClassificationTypes(Properties props) {
+ String classificationTypesNames = props.getProperty(TASKANA_CLASSIFICATION_TYPES_PROPERTY);
+ if (classificationTypesNames != null && !classificationTypesNames.isEmpty()) {
+ StringTokenizer st = new StringTokenizer(classificationTypesNames, ",");
+ while (st.hasMoreTokens()) {
+ classificationTypes.add(st.nextToken().trim().toUpperCase());
+ }
+ }
+ LOGGER.debug("Configured domains: {}", domains);
+ }
+
+ private void initClassificationCategories(Properties props) {
+ String classificationCategoryNames = props.getProperty(TASKANA_CLASSIFICATION_CATEGORIES_PROPERTY);
+ if (classificationCategoryNames != null && !classificationCategoryNames.isEmpty()) {
+ StringTokenizer st = new StringTokenizer(classificationCategoryNames, ",");
+ while (st.hasMoreTokens()) {
+ classificationCategories.add(st.nextToken().trim().toUpperCase());
+ }
+ }
+ LOGGER.debug("Configured domains: {}", domains);
+ }
+
+ private void initTaskanaRoles(Properties props, String rolesSeparator) {
+ List validPropertyNames = Arrays.stream(TaskanaRole.values())
+ .map(TaskanaRole::getPropertyName)
+ .collect(Collectors.toList());
+ for (Object obj : props.keySet()) {
+ String propertyName = ((String) obj);
+ if (validPropertyNames.contains(propertyName.toLowerCase().trim())) {
+ String propertyValue = props.getProperty(propertyName);
+ Set roleMemberSet = new HashSet<>();
+ StringTokenizer st = new StringTokenizer(propertyValue, rolesSeparator);
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken().toLowerCase().trim();
+ roleMemberSet.add(token);
+ }
+ TaskanaRole key = TaskanaRole.fromPropertyName(propertyName);
+ if (key != null) {
+ roleMap.put(key, roleMemberSet);
+ } else {
+ throw new SystemException(
+ "Internal System error when processing role property " + propertyName);
+ }
+ }
+ }
+ ensureRoleMapIsFullyInitialized();
+
+ roleMap.forEach(
+ (k, v) -> LOGGER.debug("Found Taskana RoleConfig {} : {} ", k, LoggerUtils.setToString(v)));
+ }
+
+ private Properties readPropertiesFromFile(String propertiesFile) {
+ Properties props = new Properties();
+ boolean loadFromClasspath = loadFromClasspath(propertiesFile);
+ try {
+ if (loadFromClasspath) {
+ InputStream inputStream = this.getClass().getResourceAsStream(propertiesFile);
+ if (inputStream == null) {
+ LOGGER.error("taskana properties file {} was not found on classpath.",
+ propertiesFile);
+ } else {
+ props.load(new InputStreamReader(inputStream));
+ LOGGER.debug("Role properties were loaded from file {} from classpath.", propertiesFile);
+ }
+ } else {
+ props.load(new FileInputStream(propertiesFile));
+ LOGGER.debug("Role properties were loaded from file {}.", propertiesFile);
+ }
+ } catch (IOException e) {
+ throw new SystemException("internal System error when processing properties file " + propertiesFile,
+ e.getCause());
+ }
+ return props;
+ }
+
+ private boolean loadFromClasspath(String propertiesFile) {
+ boolean loadFromClasspath = true;
+ File f = new File(propertiesFile);
+ if (f.exists() && !f.isDirectory()) {
+ loadFromClasspath = false;
+ }
+ return loadFromClasspath;
+ }
+
+ private void ensureRoleMapIsFullyInitialized() {
+ // make sure that roleMap does not return null for any role
+ Arrays.stream(TaskanaRole.values())
+ .forEach(role -> roleMap.putIfAbsent(role, new HashSet<>()));
+ }
+
+ public static DataSource createDefaultDataSource() {
+ LOGGER.info("No datasource is provided. A inmemory db is used: "
+ + "'org.h2.Driver', 'jdbc:h2:mem:taskana;IGNORECASE=TRUE;LOCK_MODE=0;INIT=CREATE SCHEMA IF NOT EXISTS TASKANA', 'sa', 'sa'");
+ return createDatasource(H2_DRIVER, JDBC_H2_MEM_TASKANA, USER_NAME, USER_PASSWORD);
+ }
+
+ /**
+ * This method creates the TaskanaEngine without an sqlSessionFactory.
+ *
+ * @return the TaskanaEngine
+ */
+ public TaskanaEngine buildTaskanaEngine() {
+ return TaskanaEngineImpl.createTaskanaEngine(this);
+ }
+
+ /**
+ * This method creates a PooledDataSource, if the needed properties are provided.
+ *
+ * @param driver
+ * the name of the jdbc driver
+ * @param jdbcUrl
+ * the url to which the jdbc driver connects
+ * @param username
+ * the user name for database access
+ * @param password
+ * the password for database access
+ * @return DataSource
+ */
+ public static DataSource createDatasource(String driver, String jdbcUrl, String username, String password) {
+ return new PooledDataSource(driver, jdbcUrl, username, password);
+ }
+
+ public boolean isSecurityEnabled() {
+ return this.securityEnabled;
+ }
+
+ public DataSource getDatasource() {
+ return this.dataSource;
+ }
+
+ public boolean getUseManagedTransactions() {
+ return this.useManagedTransactions;
+ }
+
+ public String getPropertiesFileName() {
+ return this.propertiesFileName;
+ }
+
+ public void setPropertiesFileName(String propertiesFileName) {
+ this.propertiesFileName = propertiesFileName;
+ }
+
+ public String getPropertiesSeparator() {
+ return this.rolesSeparator;
+ }
+
+ public void setPropertiesSeparator(String propertiesSeparator) {
+ this.rolesSeparator = propertiesSeparator;
+ }
+
+ public boolean isGermanPublicHolidaysEnabled() {
+ return this.germanPublicHolidaysEnabled;
+ }
+
+ public void setGermanPublicHolidaysEnabled(boolean germanPublicHolidaysEnabled) {
+ this.germanPublicHolidaysEnabled = germanPublicHolidaysEnabled;
+ }
+
+ public List getCustomHolidays() {
+ return customHolidays;
+ }
+
+ public void setCustomHolidays(List customHolidays) {
+ this.customHolidays = customHolidays;
+ }
+
+ public Map> getRoleMap() {
+ return roleMap;
+ }
+
+ public void setRoleMap(Map> roleMap) {
+ this.roleMap = roleMap;
+ }
+
+ public List getDomains() {
+ return domains;
+ }
+
+ public void setDomains(List domains) {
+ this.domains = domains;
+ }
+
+ public List getClassificationTypes() {
+ return classificationTypes;
+ }
+
+ public void setClassificationTypes(List classificationTypes) {
+ this.classificationTypes = classificationTypes;
+ }
+
+ public List getClassificationCategories() {
+ return classificationCategories;
+ }
+
+ public void setClassificationCategories(List classificationCategories) {
+ this.classificationCategories = classificationCategories;
+ }
+
+ /**
+ * Helper method to determine whether all access ids (user Id and group ids) should be used in lower case.
+ *
+ * @return true if all access ids should be used in lower case, false otherwise
+ */
+ public static boolean shouldUseLowerCaseForAccessIds() {
+ return true;
+ }
+}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/exceptions/AttachmentPersistenceException.java b/lib/taskana-core/src/main/java/pro/taskana/exceptions/AttachmentPersistenceException.java
index 4ee9cb81f..9ed1483a1 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/exceptions/AttachmentPersistenceException.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/exceptions/AttachmentPersistenceException.java
@@ -9,7 +9,7 @@ public class AttachmentPersistenceException extends TaskanaException {
private static final long serialVersionUID = 123L;
- public AttachmentPersistenceException(String attachmentId) {
- super("AttachmentId=" + attachmentId);
+ public AttachmentPersistenceException(String msg, Throwable cause) {
+ super(msg, cause);
}
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java b/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java
index c7052f1b7..28f4acf71 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java
@@ -9,5 +9,9 @@ public class ClassificationInUseException extends TaskanaException {
super(msg);
}
+ public ClassificationInUseException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
private static final long serialVersionUID = 1L;
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/exceptions/InvalidArgumentException.java b/lib/taskana-core/src/main/java/pro/taskana/exceptions/InvalidArgumentException.java
index cabd8ba68..5f26aa857 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/exceptions/InvalidArgumentException.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/exceptions/InvalidArgumentException.java
@@ -11,5 +11,9 @@ public class InvalidArgumentException extends TaskanaException {
super(msg);
}
+ public InvalidArgumentException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
private static final long serialVersionUID = 1L;
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/exceptions/NotAuthorizedToQueryWorkbasketException.java b/lib/taskana-core/src/main/java/pro/taskana/exceptions/NotAuthorizedToQueryWorkbasketException.java
index a6c2411a5..5eb4df3db 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/exceptions/NotAuthorizedToQueryWorkbasketException.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/exceptions/NotAuthorizedToQueryWorkbasketException.java
@@ -9,6 +9,10 @@ public class NotAuthorizedToQueryWorkbasketException extends TaskanaRuntimeExcep
super(msg);
}
+ public NotAuthorizedToQueryWorkbasketException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
private static final long serialVersionUID = 1L;
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/exceptions/SystemException.java b/lib/taskana-core/src/main/java/pro/taskana/exceptions/SystemException.java
index bb003cb0f..f067d75de 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/exceptions/SystemException.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/exceptions/SystemException.java
@@ -9,5 +9,9 @@ public class SystemException extends TaskanaRuntimeException {
super(msg);
}
+ public SystemException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
private static final long serialVersionUID = 1L;
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java
index 51f07b3c4..5b881876f 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java
@@ -237,7 +237,8 @@ public class ClassificationServiceImpl implements ClassificationService {
try {
Duration.parse(classification.getServiceLevel());
} catch (Exception e) {
- throw new InvalidArgumentException("Invalid service level. Please use the format defined by ISO 8601");
+ throw new InvalidArgumentException("Invalid service level. Please use the format defined by ISO 8601",
+ e.getCause());
}
}
@@ -278,7 +279,6 @@ public class ClassificationServiceImpl implements ClassificationService {
taskanaEngine.openConnection();
result = classificationMapper.findById(id);
if (result == null) {
- LOGGER.error("Classification for id {} was not found. Throwing ClassificationNotFoundException", id);
throw new ClassificationNotFoundException(id, "Classification for id " + id + " was not found");
}
return result;
@@ -303,9 +303,6 @@ public class ClassificationServiceImpl implements ClassificationService {
if (result == null) {
result = classificationMapper.findByKeyAndDomain(key, "");
if (result == null) {
- LOGGER.error(
- "Classification for key {} and domain {} was not found. Throwing ClassificationNotFoundException",
- key, domain);
throw new ClassificationNotFoundException(key, domain,
"Classification for key " + key + " was not found");
}
@@ -400,7 +397,8 @@ public class ClassificationServiceImpl implements ClassificationService {
} catch (PersistenceException e) {
if (isReferentialIntegrityConstraintViolation(e)) {
throw new ClassificationInUseException("The classification " + classificationId
- + " is in use and cannot be deleted. There are either tasks or attachments associated with the classification.");
+ + " is in use and cannot be deleted. There are either tasks or attachments associated with the classification.",
+ e.getCause());
}
}
} finally {
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java
index 937473dbd..2892d53e3 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java
@@ -332,7 +332,8 @@ public class TaskImpl implements Task {
num = Integer.parseInt(number);
} catch (NumberFormatException e) {
throw new InvalidArgumentException(
- "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16");
+ "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16",
+ e.getCause());
}
switch (num) {
@@ -382,7 +383,8 @@ public class TaskImpl implements Task {
num = Integer.parseInt(number);
} catch (NumberFormatException e) {
throw new InvalidArgumentException(
- "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16");
+ "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16",
+ e.getCause());
}
switch (num) {
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java
index 7c77f0d68..3b04ab68f 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java
@@ -400,7 +400,8 @@ public class TaskQueryImpl implements TaskQuery {
num = Integer.parseInt(number);
} catch (NumberFormatException e) {
throw new InvalidArgumentException(
- "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16");
+ "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16",
+ e.getCause());
}
switch (num) {
@@ -467,7 +468,8 @@ public class TaskQueryImpl implements TaskQuery {
num = Integer.parseInt(number);
} catch (NumberFormatException e) {
throw new InvalidArgumentException(
- "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16");
+ "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16",
+ e.getCause());
}
switch (num) {
@@ -851,7 +853,7 @@ public class TaskQueryImpl implements TaskQuery {
}
}
} catch (NotAuthorizedException e) {
- throw new NotAuthorizedToQueryWorkbasketException(e.getMessage());
+ throw new NotAuthorizedToQueryWorkbasketException(e.getMessage(), e.getCause());
}
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java
index dd071a5a7..f82f45561 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java
@@ -38,7 +38,6 @@ import pro.taskana.exceptions.ConcurrencyException;
import pro.taskana.exceptions.InvalidArgumentException;
import pro.taskana.exceptions.InvalidOwnerException;
import pro.taskana.exceptions.InvalidStateException;
-import pro.taskana.exceptions.InvalidWorkbasketException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.SystemException;
import pro.taskana.exceptions.TaskAlreadyExistException;
@@ -78,8 +77,7 @@ public class TaskServiceImpl implements TaskService {
this.converter = DaysToWorkingDaysConverter
.initialize(Collections.singletonList(new TimeIntervalColumnHeader(0)), Instant.now());
} catch (InvalidArgumentException e) {
- LOGGER.error("could not initialize DaysToWorkingDaysConverter. Caught exception " + e);
- throw new SystemException("Internal error. Cannot initialize DaysToWorkingDaysConverter");
+ throw new SystemException("Internal error. Cannot initialize DaysToWorkingDaysConverter", e.getCause());
}
this.taskanaEngine = (TaskanaEngineImpl) taskanaEngine;
this.taskMapper = taskMapper;
@@ -363,8 +361,6 @@ public class TaskServiceImpl implements TaskService {
.list();
if (workbaskets.isEmpty()) {
String currentUser = CurrentUserContext.getUserid();
- LOGGER.error("The current user {} has no read permission for workbasket {}.", currentUser,
- workbasketId);
throw new NotAuthorizedException(
"The current user " + currentUser + " has no read permission for workbasket " + workbasketId);
} else {
@@ -388,7 +384,6 @@ public class TaskServiceImpl implements TaskService {
.findFirst()
.orElse(null);
if (classification == null) {
- LOGGER.error("Could not find a Classification for task {} ", resultTask);
throw new SystemException(
"Could not find a Classification for task " + resultTask.getId());
}
@@ -396,7 +391,6 @@ public class TaskServiceImpl implements TaskService {
resultTask.setClassificationSummary(classification);
return resultTask;
} else {
- LOGGER.warn("Method getTaskById() didn't find task with id {}. Throwing TaskNotFoundException", id);
throw new TaskNotFoundException(id, "Task with id " + id + " was not found");
}
} finally {
@@ -407,8 +401,7 @@ public class TaskServiceImpl implements TaskService {
@Override
public Task transfer(String taskId, String destinationWorkbasketId)
- throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedException, InvalidWorkbasketException,
- InvalidStateException {
+ throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedException, InvalidStateException {
LOGGER.debug("entry to transfer(taskId = {}, destinationWorkbasketId = {})", taskId, destinationWorkbasketId);
TaskImpl task = null;
try {
@@ -447,8 +440,7 @@ public class TaskServiceImpl implements TaskService {
@Override
public Task transfer(String taskId, String destinationWorkbasketKey, String domain)
- throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedException, InvalidWorkbasketException,
- InvalidStateException {
+ throws TaskNotFoundException, WorkbasketNotFoundException, NotAuthorizedException, InvalidStateException {
LOGGER.debug("entry to transfer(taskId = {}, destinationWorkbasketKey = {}, domain = {})", taskId,
destinationWorkbasketKey, domain);
TaskImpl task = null;
@@ -652,8 +644,7 @@ public class TaskServiceImpl implements TaskService {
@Override
public Task updateTask(Task task)
throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException, WorkbasketNotFoundException,
- ClassificationNotFoundException, InvalidWorkbasketException, NotAuthorizedException,
- AttachmentPersistenceException {
+ ClassificationNotFoundException, NotAuthorizedException, AttachmentPersistenceException {
String userId = CurrentUserContext.getUserid();
LOGGER.debug("entry to updateTask(task = {}, userId = {})", task, userId);
TaskImpl newTaskImpl = (TaskImpl) task;
@@ -778,11 +769,9 @@ public class TaskServiceImpl implements TaskService {
.findFirst()
.orElse(null);
if (aClassification == null) {
- LOGGER.error("Didnt find a Classification for task ");
throw new SystemException(
"Did not find a Classification for task (Id=" + task.getTaskId() + ",classification="
- + task.getClassificationSummary().getId()
- + ")");
+ + task.getClassificationSummary().getId() + ")");
}
// set the classification on the task object
task.setClassificationSummary(aClassification);
@@ -908,7 +897,6 @@ public class TaskServiceImpl implements TaskService {
.findFirst()
.orElse(null);
if (aClassification == null) {
- LOGGER.error("Could not find a Classification for attachment {}.", att);
throw new SystemException("Could not find a Classification for attachment " + att);
}
att.setClassificationSummary(aClassification);
@@ -930,7 +918,6 @@ public class TaskServiceImpl implements TaskService {
.orElse(null);
if (aClassification == null) {
- LOGGER.error("Could not find a Classification for attachment {}.", att);
throw new SystemException("Could not find a Classification for attachment " + att);
}
att.setClassificationSummary(aClassification);
@@ -1052,8 +1039,6 @@ public class TaskServiceImpl implements TaskService {
}
if (customFieldsToUpdate == null || customFieldsToUpdate.isEmpty()) {
- LOGGER.warn(
- "The customFieldsToUpdate argument to updateTasks must not be empty. Throwing InvalidArgumentException.");
throw new InvalidArgumentException("The customFieldsToUpdate argument to updateTasks must not be empty.");
}
validateObjectReference(selectionCriteria, "ObjectReference", "updateTasks call");
@@ -1070,7 +1055,6 @@ public class TaskServiceImpl implements TaskService {
for (Map.Entry entry : customFieldsToUpdate.entrySet()) {
String key = entry.getKey();
if (!allowedKeys.contains(key)) {
- LOGGER.warn("The customFieldsToUpdate argument to updateTasks contains invalid key {}.", key);
throw new InvalidArgumentException(
"The customFieldsToUpdate argument to updateTasks contains invalid key " + key);
} else {
@@ -1165,8 +1149,7 @@ public class TaskServiceImpl implements TaskService {
private void standardUpdateActions(TaskImpl oldTaskImpl, TaskImpl newTaskImpl,
PrioDurationHolder prioDurationFromAttachments)
- throws InvalidArgumentException, ConcurrencyException, WorkbasketNotFoundException,
- ClassificationNotFoundException {
+ throws InvalidArgumentException, ConcurrencyException, ClassificationNotFoundException {
validateObjectReference(newTaskImpl.getPrimaryObjRef(), "primary ObjectReference", "Task");
if (oldTaskImpl.getModified() != null && !oldTaskImpl.getModified().equals(newTaskImpl.getModified())
|| oldTaskImpl.getClaimed() != null && !oldTaskImpl.getClaimed().equals(newTaskImpl.getClaimed())
@@ -1312,10 +1295,10 @@ public class TaskServiceImpl implements TaskService {
newTaskImpl.getId(),
attachmentImpl);
} catch (PersistenceException e) {
- LOGGER.error(
- "TaskService.updateTask() for TaskId={} can NOT INSERT the current Attachment, because it was added fored multiple times and wasn´t persisted before. ID={}",
- newTaskImpl.getId(), attachmentImpl.getId());
- throw new AttachmentPersistenceException(attachmentImpl.getId());
+ throw new AttachmentPersistenceException(
+ "Cannot insert the Attachement " + attachmentImpl.getId() + " for Task "
+ + newTaskImpl.getId() + " because it already exists.",
+ e.getCause());
}
}
@@ -1412,7 +1395,7 @@ public class TaskServiceImpl implements TaskService {
}
BulkOperationResults classificationChanged(String taskId, String classificationId)
- throws TaskNotFoundException, ClassificationNotFoundException {
+ throws ClassificationNotFoundException {
LOGGER.debug("entry to classificationChanged(taskId = {} , classificationId = {} )", taskId, classificationId);
TaskImpl task = null;
BulkOperationResults bulkLog = new BulkOperationResults<>();
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java
index fd78eba40..bda1e5ad5 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java
@@ -372,7 +372,8 @@ public class TaskSummaryImpl implements TaskSummary {
num = Integer.parseInt(number);
} catch (NumberFormatException e) {
throw new InvalidArgumentException(
- "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16");
+ "Argument '" + number + "' to getCustomAttribute cannot be converted to a number between 1 and 16",
+ e.getCause());
}
switch (num) {
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 51201bc79..5a19aaf37 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
@@ -1,400 +1,394 @@
-package pro.taskana.impl;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.ArrayDeque;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.List;
-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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import pro.taskana.ClassificationService;
-import pro.taskana.TaskMonitorService;
-import pro.taskana.TaskService;
-import pro.taskana.TaskanaEngine;
-import pro.taskana.TaskanaRole;
-import pro.taskana.WorkbasketService;
-import pro.taskana.configuration.TaskanaEngineConfiguration;
-import pro.taskana.exceptions.AutocommitFailedException;
-import pro.taskana.exceptions.ConnectionNotSetException;
-import pro.taskana.exceptions.NotAuthorizedException;
-import pro.taskana.exceptions.SystemException;
-import pro.taskana.exceptions.UnsupportedDatabaseException;
-import pro.taskana.impl.persistence.MapTypeHandler;
-import pro.taskana.impl.util.LoggerUtils;
-import pro.taskana.mappings.AttachmentMapper;
-import pro.taskana.mappings.ClassificationMapper;
-import pro.taskana.mappings.DistributionTargetMapper;
-import pro.taskana.mappings.JobMapper;
-import pro.taskana.mappings.ObjectReferenceMapper;
-import pro.taskana.mappings.QueryMapper;
-import pro.taskana.mappings.TaskMapper;
-import pro.taskana.mappings.TaskMonitorMapper;
-import pro.taskana.mappings.WorkbasketAccessMapper;
-import pro.taskana.mappings.WorkbasketMapper;
-import pro.taskana.security.CurrentUserContext;
-
-/**
- * This is the implementation of TaskanaEngine.
- */
-public class TaskanaEngineImpl implements TaskanaEngine {
-
- private static final String DEFAULT = "default";
- private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
- protected static ThreadLocal> sessionStack = new ThreadLocal<>();
- protected TaskanaEngineConfiguration taskanaEngineConfiguration;
- protected TransactionFactory transactionFactory;
- protected SqlSessionManager sessionManager;
- protected SqlSessionFactory sessionFactory;
- protected ConnectionManagementMode mode = ConnectionManagementMode.PARTICIPATE;
- protected java.sql.Connection connection = null;
-
- protected TaskanaEngineImpl(TaskanaEngineConfiguration taskanaEngineConfiguration) {
- this.taskanaEngineConfiguration = taskanaEngineConfiguration;
- createTransactionFactory(taskanaEngineConfiguration.getUseManagedTransactions());
- this.sessionManager = createSqlSessionManager();
- }
-
- public static TaskanaEngine createTaskanaEngine(TaskanaEngineConfiguration taskanaEngineConfiguration) {
- return new TaskanaEngineImpl(taskanaEngineConfiguration);
- }
-
- /**
- * 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 = sessionStack.get();
- if (stack == null) {
- stack = new ArrayDeque<>();
- sessionStack.set(stack);
- }
- return stack;
- }
-
- protected static SqlSessionManager getSessionFromStack() {
- Deque stack = getSessionStack();
- if (stack.isEmpty()) {
- return null;
- }
- return stack.peek();
- }
-
- protected static void pushSessionToStack(SqlSessionManager session) {
- getSessionStack().push(session);
- }
-
- protected static void popSessionFromStack() {
- Deque stack = getSessionStack();
- if (!stack.isEmpty()) {
- stack.pop();
- }
- }
-
- public static boolean isDb2(String dbProductName) {
- return dbProductName.contains("DB2");
- }
-
- public static boolean isH2(String databaseProductName) {
- return databaseProductName.contains("H2");
- }
-
- public static boolean isPostgreSQL(String databaseProductName) {
- return databaseProductName.equals("PostgreSQL");
- }
-
- @Override
- public TaskService getTaskService() {
- SqlSession session = this.sessionManager;
- return new TaskServiceImpl(this, session.getMapper(TaskMapper.class),
- session.getMapper(AttachmentMapper.class));
- }
-
- @Override
- public TaskMonitorService getTaskMonitorService() {
- SqlSession session = this.sessionManager;
- return new TaskMonitorServiceImpl(this,
- session.getMapper(TaskMonitorMapper.class));
- }
-
- @Override
- public WorkbasketService getWorkbasketService() {
- SqlSession session = this.sessionManager;
- return new WorkbasketServiceImpl(this,
- session.getMapper(WorkbasketMapper.class),
- session.getMapper(DistributionTargetMapper.class),
- session.getMapper(WorkbasketAccessMapper.class));
- }
-
- @Override
- public ClassificationService getClassificationService() {
- SqlSession session = this.sessionManager;
- return new ClassificationServiceImpl(this, session.getMapper(ClassificationMapper.class),
- session.getMapper(TaskMapper.class));
- }
-
- @Override
- public TaskanaEngineConfiguration getConfiguration() {
- return this.taskanaEngineConfiguration;
- }
-
- /**
- * sets the connection management mode.
- *
- * @param mode
- * - the connection management mode Valid values are:
- *
- * - PARTICIPATE - taskana participates in global transaction. This is the default mode.
- * - AUTOCOMMIT - taskana commits each API call separately
- * - EXPLICIT - commit processing is managed explicitly by the client
- *
- */
- @Override
- public void setConnectionManagementMode(ConnectionManagementMode mode) {
- if (this.mode == ConnectionManagementMode.EXPLICIT && connection != null
- && mode != ConnectionManagementMode.EXPLICIT) {
- if (sessionManager.isManagedSessionStarted()) {
- sessionManager.close();
- }
- connection = null;
- }
- this.mode = mode;
- }
-
- /**
- * Set the database connection to be used by taskana. If this Api is called, taskana uses the connection passed by
- * the client for database access in all subsequent API calls until the client resets this connection. Control over
- * commit and rollback is the responsibility of the client. In order to close the connection, the client can call
- * TaskanaEngine.closeConnection() or TaskanaEngine.setConnection(null). Both calls have the same effect.
- *
- * @param connection
- * The connection that passed into TaskanaEngine
- */
- @Override
- public void setConnection(java.sql.Connection connection) throws SQLException {
- if (connection != null) {
- this.connection = connection;
- // disabling auto commit for passed connection in order to gain full control over the connection management
- connection.setAutoCommit(false);
- mode = ConnectionManagementMode.EXPLICIT;
- sessionManager.startManagedSession(connection);
- } else if (this.connection != null) {
- closeConnection();
- }
- }
-
- /**
- * closes the connection to the database in mode EXPLICIT. In mode EXPLICIT, closes the client's connection, sets it
- * to null and switches to mode PARTICIPATE Has the same effect as setConnection(null)
- */
- @Override
- public void closeConnection() {
- if (this.mode == ConnectionManagementMode.EXPLICIT) {
- this.connection = null;
- if (sessionManager.isManagedSessionStarted()) {
- sessionManager.close();
- }
- mode = ConnectionManagementMode.PARTICIPATE;
- }
- }
-
- /**
- * Open the connection to the database. to be called at the begin of each Api call that accesses the database
- */
- void openConnection() {
- initSqlSession();
- if (mode != ConnectionManagementMode.EXPLICIT) {
- pushSessionToStack(this.sessionManager);
- }
- }
-
- /**
- * Initializes the SqlSessionManager.
- */
- void initSqlSession() {
- if (mode == ConnectionManagementMode.EXPLICIT && this.connection == null) {
- throw new ConnectionNotSetException();
- } else if (mode != ConnectionManagementMode.EXPLICIT && !this.sessionManager.isManagedSessionStarted()) {
- this.sessionManager.startManagedSession();
- }
- }
-
- /**
- * 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() {
- if (this.mode != ConnectionManagementMode.EXPLICIT) {
- popSessionFromStack();
- if (getSessionStack().isEmpty()
- && this.sessionManager != null && this.sessionManager.isManagedSessionStarted()) {
- if (this.mode == ConnectionManagementMode.AUTOCOMMIT) {
- try {
- this.sessionManager.commit();
- } catch (Exception e) {
- LOGGER.error("closeSession(): Tried to Autocommit and caught exception" + e);
- throw new AutocommitFailedException(e);
- }
- }
- this.sessionManager.close();
- }
- }
- }
-
- /**
- * retrieve the SqlSession used by taskana.
- *
- * @return the myBatis SqlSession object used by taskana
- */
- SqlSession getSqlSession() {
- return this.sessionManager;
- }
-
- /**
- * 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
- */
- @Override
- public void checkRoleMembership(TaskanaRole... roles) throws NotAuthorizedException {
- if (isUserInRole(roles)) {
- return;
- } else {
- if (LOGGER.isErrorEnabled()) {
- String accessIds = LoggerUtils.listToString(CurrentUserContext.getAccessIds());
- String rolesAsString = Arrays.toString(roles);
- LOGGER.error("Throwing NotAuthorizedException because accessIds {} are not member of roles {}",
- accessIds,
- rolesAsString);
- }
- throw new NotAuthorizedException("current user is not member of role(s) " + Arrays.toString(roles));
- }
- }
-
- /**
- * 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
- */
- @Override
- public boolean isUserInRole(TaskanaRole... roles) {
- if (!getConfiguration().isSecurityEnabled()) {
- return true;
- } else {
- List accessIds = CurrentUserContext.getAccessIds();
- Set rolesMembers = new HashSet<>();
- for (TaskanaRole role : roles) {
- rolesMembers.addAll(getConfiguration().getRoleMap().get(role));
- }
- for (String accessId : accessIds) {
- if (rolesMembers.contains(accessId)) {
- return true;
- }
- }
- return false;
- }
- }
-
- /**
- * This method creates the sqlSessionManager of myBatis. It integrates all the SQL mappers and sets the databaseId
- * attribute.
- *
- * @return a {@link SqlSessionFactory}
- */
- protected SqlSessionManager createSqlSessionManager() {
- Environment environment = new Environment(DEFAULT, this.transactionFactory,
- taskanaEngineConfiguration.getDatasource());
- Configuration configuration = new Configuration(environment);
-
- // set databaseId
- String databaseProductName;
- try (Connection con = taskanaEngineConfiguration.getDatasource().getConnection()) {
- databaseProductName = con.getMetaData().getDatabaseProductName();
- if (isDb2(databaseProductName)) {
- configuration.setDatabaseId("db2");
- } else if (isH2(databaseProductName)) {
- configuration.setDatabaseId("h2");
- } else if (isPostgreSQL(databaseProductName)) {
- configuration.setDatabaseId("postgres");
- } else {
- LOGGER.error(
- "Method createSqlSessionManager() didn't find database with name {}. Throwing UnsupportedDatabaseException",
- databaseProductName);
- throw new UnsupportedDatabaseException(databaseProductName);
- }
-
- } catch (SQLException e) {
- LOGGER.error(
- "Method createSqlSessionManager() could not open a connection to the database. No databaseId has been set.",
- e);
- throw new SystemException(
- "Method createSqlSessionManager() could not open a connection to the database. No databaseId has been set.");
- }
-
- // add mappers
- configuration.addMapper(TaskMapper.class);
- configuration.addMapper(TaskMonitorMapper.class);
- configuration.addMapper(WorkbasketMapper.class);
- configuration.addMapper(DistributionTargetMapper.class);
- configuration.addMapper(ClassificationMapper.class);
- configuration.addMapper(WorkbasketAccessMapper.class);
- configuration.addMapper(ObjectReferenceMapper.class);
- 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);
- }
-
- /**
- * creates the MyBatis transaction factory.
- *
- * @param useManagedTransactions
- */
- private void createTransactionFactory(boolean useManagedTransactions) {
- if (useManagedTransactions) {
- this.transactionFactory = new ManagedTransactionFactory();
- } else {
- this.transactionFactory = new JdbcTransactionFactory();
- }
- }
-
- /**
- * Returns true if the given domain does exist in the configuration.
- *
- * @param domain
- * the domain specified in the configuration
- * @return true if the domain exists
- */
- public boolean domainExists(String domain) {
- return getConfiguration().getDomains().contains(domain);
- }
-}
+package pro.taskana.impl;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.List;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pro.taskana.ClassificationService;
+import pro.taskana.TaskMonitorService;
+import pro.taskana.TaskService;
+import pro.taskana.TaskanaEngine;
+import pro.taskana.TaskanaRole;
+import pro.taskana.WorkbasketService;
+import pro.taskana.configuration.TaskanaEngineConfiguration;
+import pro.taskana.exceptions.AutocommitFailedException;
+import pro.taskana.exceptions.ConnectionNotSetException;
+import pro.taskana.exceptions.NotAuthorizedException;
+import pro.taskana.exceptions.SystemException;
+import pro.taskana.exceptions.UnsupportedDatabaseException;
+import pro.taskana.impl.persistence.MapTypeHandler;
+import pro.taskana.impl.util.LoggerUtils;
+import pro.taskana.mappings.AttachmentMapper;
+import pro.taskana.mappings.ClassificationMapper;
+import pro.taskana.mappings.DistributionTargetMapper;
+import pro.taskana.mappings.JobMapper;
+import pro.taskana.mappings.ObjectReferenceMapper;
+import pro.taskana.mappings.QueryMapper;
+import pro.taskana.mappings.TaskMapper;
+import pro.taskana.mappings.TaskMonitorMapper;
+import pro.taskana.mappings.WorkbasketAccessMapper;
+import pro.taskana.mappings.WorkbasketMapper;
+import pro.taskana.security.CurrentUserContext;
+
+/**
+ * This is the implementation of TaskanaEngine.
+ */
+public class TaskanaEngineImpl implements TaskanaEngine {
+
+ private static final String DEFAULT = "default";
+ private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
+ protected static ThreadLocal> sessionStack = new ThreadLocal<>();
+ protected TaskanaEngineConfiguration taskanaEngineConfiguration;
+ protected TransactionFactory transactionFactory;
+ protected SqlSessionManager sessionManager;
+ protected SqlSessionFactory sessionFactory;
+ protected ConnectionManagementMode mode = ConnectionManagementMode.PARTICIPATE;
+ protected java.sql.Connection connection = null;
+
+ protected TaskanaEngineImpl(TaskanaEngineConfiguration taskanaEngineConfiguration) {
+ this.taskanaEngineConfiguration = taskanaEngineConfiguration;
+ createTransactionFactory(taskanaEngineConfiguration.getUseManagedTransactions());
+ this.sessionManager = createSqlSessionManager();
+ }
+
+ public static TaskanaEngine createTaskanaEngine(TaskanaEngineConfiguration taskanaEngineConfiguration) {
+ return new TaskanaEngineImpl(taskanaEngineConfiguration);
+ }
+
+ /**
+ * 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 = sessionStack.get();
+ if (stack == null) {
+ stack = new ArrayDeque<>();
+ sessionStack.set(stack);
+ }
+ return stack;
+ }
+
+ protected static SqlSessionManager getSessionFromStack() {
+ Deque stack = getSessionStack();
+ if (stack.isEmpty()) {
+ return null;
+ }
+ return stack.peek();
+ }
+
+ protected static void pushSessionToStack(SqlSessionManager session) {
+ getSessionStack().push(session);
+ }
+
+ protected static void popSessionFromStack() {
+ Deque stack = getSessionStack();
+ if (!stack.isEmpty()) {
+ stack.pop();
+ }
+ }
+
+ public static boolean isDb2(String dbProductName) {
+ return dbProductName.contains("DB2");
+ }
+
+ public static boolean isH2(String databaseProductName) {
+ return databaseProductName.contains("H2");
+ }
+
+ public static boolean isPostgreSQL(String databaseProductName) {
+ return databaseProductName.equals("PostgreSQL");
+ }
+
+ @Override
+ public TaskService getTaskService() {
+ SqlSession session = this.sessionManager;
+ return new TaskServiceImpl(this, session.getMapper(TaskMapper.class),
+ session.getMapper(AttachmentMapper.class));
+ }
+
+ @Override
+ public TaskMonitorService getTaskMonitorService() {
+ SqlSession session = this.sessionManager;
+ return new TaskMonitorServiceImpl(this,
+ session.getMapper(TaskMonitorMapper.class));
+ }
+
+ @Override
+ public WorkbasketService getWorkbasketService() {
+ SqlSession session = this.sessionManager;
+ return new WorkbasketServiceImpl(this,
+ session.getMapper(WorkbasketMapper.class),
+ session.getMapper(DistributionTargetMapper.class),
+ session.getMapper(WorkbasketAccessMapper.class));
+ }
+
+ @Override
+ public ClassificationService getClassificationService() {
+ SqlSession session = this.sessionManager;
+ return new ClassificationServiceImpl(this, session.getMapper(ClassificationMapper.class),
+ session.getMapper(TaskMapper.class));
+ }
+
+ @Override
+ public TaskanaEngineConfiguration getConfiguration() {
+ return this.taskanaEngineConfiguration;
+ }
+
+ /**
+ * sets the connection management mode.
+ *
+ * @param mode
+ * - the connection management mode Valid values are:
+ *
+ * - PARTICIPATE - taskana participates in global transaction. This is the default mode.
+ * - AUTOCOMMIT - taskana commits each API call separately
+ * - EXPLICIT - commit processing is managed explicitly by the client
+ *
+ */
+ @Override
+ public void setConnectionManagementMode(ConnectionManagementMode mode) {
+ if (this.mode == ConnectionManagementMode.EXPLICIT && connection != null
+ && mode != ConnectionManagementMode.EXPLICIT) {
+ if (sessionManager.isManagedSessionStarted()) {
+ sessionManager.close();
+ }
+ connection = null;
+ }
+ this.mode = mode;
+ }
+
+ /**
+ * Set the database connection to be used by taskana. If this Api is called, taskana uses the connection passed by
+ * the client for database access in all subsequent API calls until the client resets this connection. Control over
+ * commit and rollback is the responsibility of the client. In order to close the connection, the client can call
+ * TaskanaEngine.closeConnection() or TaskanaEngine.setConnection(null). Both calls have the same effect.
+ *
+ * @param connection
+ * The connection that passed into TaskanaEngine
+ */
+ @Override
+ public void setConnection(java.sql.Connection connection) throws SQLException {
+ if (connection != null) {
+ this.connection = connection;
+ // disabling auto commit for passed connection in order to gain full control over the connection management
+ connection.setAutoCommit(false);
+ mode = ConnectionManagementMode.EXPLICIT;
+ sessionManager.startManagedSession(connection);
+ } else if (this.connection != null) {
+ closeConnection();
+ }
+ }
+
+ /**
+ * closes the connection to the database in mode EXPLICIT. In mode EXPLICIT, closes the client's connection, sets it
+ * to null and switches to mode PARTICIPATE Has the same effect as setConnection(null)
+ */
+ @Override
+ public void closeConnection() {
+ if (this.mode == ConnectionManagementMode.EXPLICIT) {
+ this.connection = null;
+ if (sessionManager.isManagedSessionStarted()) {
+ sessionManager.close();
+ }
+ mode = ConnectionManagementMode.PARTICIPATE;
+ }
+ }
+
+ /**
+ * Open the connection to the database. to be called at the begin of each Api call that accesses the database
+ */
+ void openConnection() {
+ initSqlSession();
+ if (mode != ConnectionManagementMode.EXPLICIT) {
+ pushSessionToStack(this.sessionManager);
+ }
+ }
+
+ /**
+ * Initializes the SqlSessionManager.
+ */
+ void initSqlSession() {
+ if (mode == ConnectionManagementMode.EXPLICIT && this.connection == null) {
+ throw new ConnectionNotSetException();
+ } else if (mode != ConnectionManagementMode.EXPLICIT && !this.sessionManager.isManagedSessionStarted()) {
+ this.sessionManager.startManagedSession();
+ }
+ }
+
+ /**
+ * 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() {
+ if (this.mode != ConnectionManagementMode.EXPLICIT) {
+ popSessionFromStack();
+ if (getSessionStack().isEmpty()
+ && this.sessionManager != null && this.sessionManager.isManagedSessionStarted()) {
+ if (this.mode == ConnectionManagementMode.AUTOCOMMIT) {
+ try {
+ this.sessionManager.commit();
+ } catch (Exception e) {
+ throw new AutocommitFailedException(e.getCause());
+ }
+ }
+ this.sessionManager.close();
+ }
+ }
+ }
+
+ /**
+ * retrieve the SqlSession used by taskana.
+ *
+ * @return the myBatis SqlSession object used by taskana
+ */
+ SqlSession getSqlSession() {
+ return this.sessionManager;
+ }
+
+ /**
+ * 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
+ */
+ @Override
+ public void checkRoleMembership(TaskanaRole... roles) throws NotAuthorizedException {
+ if (isUserInRole(roles)) {
+ return;
+ } else {
+ if (LOGGER.isErrorEnabled()) {
+ String accessIds = LoggerUtils.listToString(CurrentUserContext.getAccessIds());
+ String rolesAsString = Arrays.toString(roles);
+ LOGGER.error("Throwing NotAuthorizedException because accessIds {} are not member of roles {}",
+ accessIds,
+ rolesAsString);
+ }
+ throw new NotAuthorizedException("current user is not member of role(s) " + Arrays.toString(roles));
+ }
+ }
+
+ /**
+ * 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
+ */
+ @Override
+ public boolean isUserInRole(TaskanaRole... roles) {
+ if (!getConfiguration().isSecurityEnabled()) {
+ return true;
+ } else {
+ List accessIds = CurrentUserContext.getAccessIds();
+ Set rolesMembers = new HashSet<>();
+ for (TaskanaRole role : roles) {
+ rolesMembers.addAll(getConfiguration().getRoleMap().get(role));
+ }
+ for (String accessId : accessIds) {
+ if (rolesMembers.contains(accessId)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * This method creates the sqlSessionManager of myBatis. It integrates all the SQL mappers and sets the databaseId
+ * attribute.
+ *
+ * @return a {@link SqlSessionFactory}
+ */
+ protected SqlSessionManager createSqlSessionManager() {
+ Environment environment = new Environment(DEFAULT, this.transactionFactory,
+ taskanaEngineConfiguration.getDatasource());
+ Configuration configuration = new Configuration(environment);
+
+ // set databaseId
+ String databaseProductName;
+ try (Connection con = taskanaEngineConfiguration.getDatasource().getConnection()) {
+ databaseProductName = con.getMetaData().getDatabaseProductName();
+ if (isDb2(databaseProductName)) {
+ configuration.setDatabaseId("db2");
+ } else if (isH2(databaseProductName)) {
+ configuration.setDatabaseId("h2");
+ } else if (isPostgreSQL(databaseProductName)) {
+ configuration.setDatabaseId("postgres");
+ } else {
+ throw new UnsupportedDatabaseException(databaseProductName);
+ }
+
+ } catch (SQLException e) {
+ throw new SystemException(
+ "Method createSqlSessionManager() could not open a connection to the database. No databaseId has been set.",
+ e.getCause());
+ }
+
+ // add mappers
+ configuration.addMapper(TaskMapper.class);
+ configuration.addMapper(TaskMonitorMapper.class);
+ configuration.addMapper(WorkbasketMapper.class);
+ configuration.addMapper(DistributionTargetMapper.class);
+ configuration.addMapper(ClassificationMapper.class);
+ configuration.addMapper(WorkbasketAccessMapper.class);
+ configuration.addMapper(ObjectReferenceMapper.class);
+ 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);
+ }
+
+ /**
+ * creates the MyBatis transaction factory.
+ *
+ * @param useManagedTransactions
+ */
+ private void createTransactionFactory(boolean useManagedTransactions) {
+ if (useManagedTransactions) {
+ this.transactionFactory = new ManagedTransactionFactory();
+ } else {
+ this.transactionFactory = new JdbcTransactionFactory();
+ }
+ }
+
+ /**
+ * Returns true if the given domain does exist in the configuration.
+ *
+ * @param domain
+ * the domain specified in the configuration
+ * @return true if the domain exists
+ */
+ public boolean domainExists(String domain) {
+ return getConfiguration().getDomains().contains(domain);
+ }
+}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketServiceImpl.java
index f54b2813d..81395dbfc 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketServiceImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketServiceImpl.java
@@ -67,9 +67,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
taskanaEngine.openConnection();
result = workbasketMapper.findById(workbasketId);
if (result == null) {
- LOGGER.error(
- "Method getWorkbasket() didn't find workbasket with ID {}. Throwing WorkbasketNotFoundException",
- workbasketId);
throw new WorkbasketNotFoundException(workbasketId,
"Workbasket with id " + workbasketId + " was not found.");
}
@@ -92,9 +89,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
taskanaEngine.openConnection();
result = workbasketMapper.findByKeyAndDomain(workbasketKey, domain);
if (result == null) {
- LOGGER.error(
- "Method getWorkbasketByKey() didn't find workbasket with key {}. Throwing WorkbasketNotFoundException",
- workbasketKey);
throw new WorkbasketNotFoundException(workbasketKey, domain,
"Workbasket with key " + workbasketKey + " and domain " + domain + " was not found.");
}
@@ -150,9 +144,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
Workbasket existingWorkbasket = workbasketMapper.findByKeyAndDomain(newWorkbasket.getKey(),
newWorkbasket.getDomain());
if (existingWorkbasket != null) {
- LOGGER.error(
- "createWorkbasket failed because Workbasket with key {} and domain {} already exists. Throwing WorkbasketAlreadyExistsException.",
- newWorkbasket.getKey(), newWorkbasket.getDomain());
throw new WorkbasketAlreadyExistException(existingWorkbasket);
}
@@ -172,7 +163,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
@Override
public Workbasket updateWorkbasket(Workbasket workbasketToUpdate)
- throws NotAuthorizedException, WorkbasketNotFoundException, InvalidWorkbasketException {
+ throws NotAuthorizedException {
LOGGER.debug("entry to updateWorkbasket(workbasket)", workbasketToUpdate);
taskanaEngine.checkRoleMembership(TaskanaRole.BUSINESS_ADMIN, TaskanaRole.ADMIN);
@@ -208,8 +199,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
accessItem.setId(IdGenerator.generateWithPrefix(ID_PREFIX_WORKBASKET_AUTHORIZATION));
if (workbasketAccessItem.getId() == null || workbasketAccessItem.getAccessId() == null
|| workbasketAccessItem.getWorkbasketId() == null) {
- LOGGER.error(
- "createWorkbasketAccessItem failed because id, accessId or workbasketId is null. Throwing InvalidArgumentException.");
throw new InvalidArgumentException(
"Checking the preconditions of the current WorkbasketAccessItem failed. WorkbasketAccessItem="
+ workbasketAccessItem.toString());
@@ -243,16 +232,10 @@ public class WorkbasketServiceImpl implements WorkbasketService {
for (WorkbasketAccessItem workbasketAccessItem : wbAccessItems) {
WorkbasketAccessItemImpl wbAccessItemImpl = (WorkbasketAccessItemImpl) workbasketAccessItem;
if (wbAccessItemImpl.getWorkbasketId() == null) {
- LOGGER.error(
- "setWorkbasketAccessItem failed because WorkbasketAccessItem {} has a null workbasketId. Throwing InvalidArgumentException.",
- workbasketAccessItem);
throw new InvalidArgumentException(
"Checking the preconditions of the current WorkbasketAccessItem failed - WBID is NULL. WorkbasketAccessItem="
+ workbasketAccessItem.toString());
} else if (!wbAccessItemImpl.getWorkbasketId().equals(workbasketId)) {
- LOGGER.error(
- "setWorkbasketAccessItem failed because WorkbasketAccessItem {} does not refer to workbasket {}. Throwing InvalidArgumentException.",
- workbasketAccessItem, workbasketId);
throw new InvalidArgumentException(
"Checking the preconditions of the current WorkbasketAccessItem failed - the WBID does not match. Target-WBID='"
+ workbasketId + "' WorkbasketAccessItem="
@@ -311,8 +294,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
taskanaEngine.openConnection();
if (workbasketMapper.findById(workbasketId) == null) {
- LOGGER.error("Throwing WorkbasketNotFoundException because workbasket with id {} does not exist",
- workbasketId);
throw new WorkbasketNotFoundException(workbasketId,
"Workbasket with id " + workbasketId + " was not found.");
}
@@ -326,9 +307,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
WorkbasketAccessItem wbAcc = workbasketAccessMapper.findByWorkbasketAndAccessId(workbasketId,
accessIds);
if (wbAcc == null) {
- LOGGER.error(
- "AccessIds {} do not have permission {} on workbasket with id {}. Throwing NotAuthorizedException.",
- LoggerUtils.listToString(accessIds), Arrays.toString(requestedPermissions), workbasketId);
throw new NotAuthorizedException(
"Not authorized. Permission '" + Arrays.toString(requestedPermissions) + "' on workbasket '"
+ workbasketId
@@ -340,9 +318,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
for (WorkbasketPermission perm : requestedPermissions) {
if (!grantedPermissions.contains(perm)) {
isAuthorized = false;
- LOGGER.error(
- "AccessIds {} do not have permission {} on workbasket with id {}. Throwing NotAuthorizedException.",
- LoggerUtils.listToString(accessIds), perm.name(), workbasketId);
throw new NotAuthorizedException(
"Not authorized. Permission '" + perm.name() + "' on workbasket '" + workbasketId
+ "' is needed.");
@@ -363,9 +338,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
taskanaEngine.openConnection();
if (workbasketMapper.findByKeyAndDomain(workbasketKey, domain) == null) {
- LOGGER.error(
- "Throwing WorkbasketNotFoundException because workbasket with key {} and domain {} does not exist",
- workbasketKey, domain);
throw new WorkbasketNotFoundException(workbasketKey, domain,
"Workbasket with key " + workbasketKey + " and domain " + domain + " was not found");
}
@@ -377,9 +349,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
WorkbasketAccessItem wbAcc = workbasketAccessMapper.findByWorkbasketKeyDomainAndAccessId(
workbasketKey, domain, accessIds);
if (wbAcc == null) {
- LOGGER.error(
- "AccessIds {} do not have permission {} on workbasket with key {} and domain {}. Throwing NotAuthorizedException.",
- LoggerUtils.listToString(accessIds), Arrays.toString(requestedPermissions), workbasketKey, domain);
throw new NotAuthorizedException(
"Not authorized. Permission '" + Arrays.toString(requestedPermissions)
+ "' on workbasket with key '"
@@ -391,9 +360,6 @@ public class WorkbasketServiceImpl implements WorkbasketService {
for (WorkbasketPermission perm : requestedPermissions) {
if (!grantedPermissions.contains(perm)) {
isAuthorized = false;
- LOGGER.error(
- "AccessIds {} do not have permission {} on workbasket with key {} and domain {}. Throwing NotAuthorizedException.",
- LoggerUtils.listToString(accessIds), perm.name(), workbasketKey, domain);
throw new NotAuthorizedException(
"Not authorized. Permission '" + perm.name() + "' on workbasket with key '" + workbasketKey
+ "' and domain '" + domain + "' is needed.");
@@ -746,7 +712,7 @@ public class WorkbasketServiceImpl implements WorkbasketService {
@Override
public void removeDistributionTarget(String sourceWorkbasketId, String targetWorkbasketId)
- throws NotAuthorizedException, WorkbasketNotFoundException {
+ throws NotAuthorizedException {
LOGGER.debug("entry to removeDistributionTarget(sourceWorkbasketId = {}, targetWorkbasketId = {})",
sourceWorkbasketId, targetWorkbasketId);
taskanaEngine.checkRoleMembership(TaskanaRole.BUSINESS_ADMIN, TaskanaRole.ADMIN);
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java b/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java
index 0a8f46dc8..c4ee3f71b 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java
@@ -62,7 +62,7 @@ public class MapTypeHandler extends BaseTypeHandler