TSK-2004: JavaDoc 4 TaskanaConfiguration.Builder#initTaskanaProperties

And refactoring of some components around the TaskanaConfiguration
This commit is contained in:
Mustapha Zorgati 2023-02-16 16:49:22 +01:00
parent ff643fdff6
commit 4697fbe5be
15 changed files with 345 additions and 166 deletions

View File

@ -8,7 +8,7 @@ public final class CustomHoliday {
private final Integer month;
public CustomHoliday(Integer day, Integer month) {
super();
// TODO: validate this is a valid date
this.day = day;
this.month = month;
}

View File

@ -64,7 +64,9 @@ public class TaskanaConfigurationInitializer {
PropertyParser<?> propertyParser =
Optional.ofNullable(PROPERTY_INITIALIZER_BY_CLASS.get(type))
.orElseThrow(
() -> new SystemException("Unknown configuration type " + type));
() ->
new SystemException(
String.format("Unknown configuration type '%s'", type)));
propertyParser
.initialize(props, separator, field, taskanaProperty)
.ifPresent(value -> setFieldValue(instance, field, value));
@ -139,18 +141,16 @@ public class TaskanaConfigurationInitializer {
private static <T> Optional<T> parseProperty(
Map<String, String> props, String key, CheckedFunction<String, T, Exception> function) {
String property = props.getOrDefault(key, "");
if (!property.isEmpty()) {
try {
return Optional.ofNullable(function.apply(property));
} catch (Throwable t) {
LOGGER.warn(
"Could not parse property {} ({}). Using default. Exception: {}",
key,
property,
t.getMessage());
}
if (property.isEmpty()) {
return Optional.empty();
}
try {
return Optional.ofNullable(function.apply(property));
} catch (Exception t) {
throw new SystemException(
String.format("Could not parse property '%s' ('%s').", key, property), t);
}
return Optional.empty();
}
interface PropertyParser<T> {

View File

@ -18,12 +18,8 @@ public class FileLoaderUtil {
}
public static boolean fileExistsOnSystem(String fileToLoad) {
boolean loadFromClasspath = false;
File f = new File(fileToLoad);
if (f.exists() && !f.isDirectory()) {
loadFromClasspath = true;
}
return loadFromClasspath;
return f.exists() && !f.isDirectory();
}
public static InputStream openFileFromClasspathOrSystem(String fileToLoad, Class<?> clazz) {

View File

@ -45,8 +45,7 @@ public class HistoryCleanupJob extends AbstractTaskanaJob {
private final boolean allCompletedSameParentBusiness;
private Duration minimumAge = taskanaEngineImpl.getConfiguration().getCleanupJobMinimumAge();
private int batchSize =
taskanaEngineImpl.getConfiguration().getMaxNumberOfUpdatesPerTransaction();
private int batchSize = taskanaEngineImpl.getConfiguration().getJobBatchSize();
public HistoryCleanupJob(
TaskanaEngine taskanaEngine,

View File

@ -1,18 +1,29 @@
package acceptance;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import java.lang.reflect.Field;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.ThrowingConsumer;
import pro.taskana.TaskanaConfiguration;
import pro.taskana.TaskanaConfiguration.Builder;
import pro.taskana.common.api.CustomHoliday;
import pro.taskana.common.api.TaskanaRole;
import pro.taskana.common.internal.util.ReflectionUtil;
import pro.taskana.testapi.extensions.TestContainerExtension;
import pro.taskana.workbasket.api.WorkbasketPermission;
class TaskanaConfigurationTest {
@ -69,4 +80,117 @@ class TaskanaConfigurationTest {
return DynamicTest.stream(fields, Field::getName, testCase);
}
@Test
void should_PopulateEveryTaskanaConfiguration_When_EveryBuilderFunctionIsCalled() {
// given
List<String> expectedDomains = List.of("A", "B");
Map<TaskanaRole, Set<String>> expectedRoleMap = Map.of(TaskanaRole.ADMIN, Set.of("admin"));
List<String> expectedClassificationTypes = List.of("typeA", "typeB");
Map<String, List<String>> expectedClassificationCategories =
Map.of("typeA", List.of("categoryA"), "typeB", List.of("categoryB"));
List<CustomHoliday> expectedCustomHolidays = List.of(CustomHoliday.of(10, 10));
int expectedJobBatchSize = 50;
int expectedNumberOfJobRetries = 500;
Instant expectedCleanupJobFirstJun = Instant.MIN;
Duration expectedCleanupJobRunEvery = Duration.ofDays(2);
Duration expectedCleanupJobMinimumAge = Duration.ZERO;
int expectedPriorityJobBatchSize = 49;
Instant expectedPriorityJobFirstRun = Instant.MIN.plus(1, ChronoUnit.DAYS);
Instant expectedUserRefreshJobFirstRun = Instant.MIN.plus(2, ChronoUnit.DAYS);
Duration expectedUserRefreshJobRunEvery = Duration.ofDays(5);
List<WorkbasketPermission> expectedMinimalPermissionsToAssignDomains =
List.of(WorkbasketPermission.CUSTOM_2);
// when
TaskanaConfiguration configuration =
new Builder(TestContainerExtension.createDataSourceForH2(), false, "TASKANA")
.domains(expectedDomains)
.roleMap(expectedRoleMap)
.classificationTypes(expectedClassificationTypes)
.classificationCategoriesByTypeMap(expectedClassificationCategories)
.allowTimestampServiceLevelMismatch(true)
.customHolidays(expectedCustomHolidays)
.germanPublicHolidaysEnabled(true)
.corpusChristiEnabled(true)
.deleteHistoryOnTaskDeletionEnabled(true)
.jobBatchSize(expectedJobBatchSize)
.maxNumberOfJobRetries(expectedNumberOfJobRetries)
.cleanupJobFirstRun(expectedCleanupJobFirstJun)
.cleanupJobRunEvery(expectedCleanupJobRunEvery)
.cleanupJobMinimumAge(expectedCleanupJobMinimumAge)
.taskCleanupJobAllCompletedSameParentBusiness(false)
.priorityJobBatchSize(expectedPriorityJobBatchSize)
.priorityJobFirstRun(expectedPriorityJobFirstRun)
.priorityJobActive(true)
.userRefreshJobFirstRun(expectedUserRefreshJobFirstRun)
.userRefreshJobRunEvery(expectedUserRefreshJobRunEvery)
.addAdditionalUserInfo(true)
.minimalPermissionsToAssignDomains(expectedMinimalPermissionsToAssignDomains)
.build();
// then
assertThat(configuration).hasNoNullFieldsOrProperties();
assertThat(configuration.getDomains()).isEqualTo(expectedDomains);
assertThat(configuration.getRoleMap()).isEqualTo(expectedRoleMap);
assertThat(configuration.getClassificationTypes()).isEqualTo(expectedClassificationTypes);
assertThat(configuration.getClassificationCategoriesByType())
.isEqualTo(expectedClassificationCategories);
assertThat(configuration.isAllowTimestampServiceLevelMismatch()).isTrue();
assertThat(configuration.getCustomHolidays()).isEqualTo(expectedCustomHolidays);
assertThat(configuration.isGermanPublicHolidaysEnabled()).isTrue();
assertThat(configuration.isCorpusChristiEnabled()).isTrue();
assertThat(configuration.isDeleteHistoryOnTaskDeletionEnabled()).isTrue();
assertThat(configuration.getJobBatchSize()).isEqualTo(expectedJobBatchSize);
assertThat(configuration.getMaxNumberOfJobRetries()).isEqualTo(expectedNumberOfJobRetries);
assertThat(configuration.getCleanupJobFirstRun()).isEqualTo(expectedCleanupJobFirstJun);
assertThat(configuration.getCleanupJobRunEvery()).isEqualTo(expectedCleanupJobRunEvery);
assertThat(configuration.getCleanupJobMinimumAge()).isEqualTo(expectedCleanupJobMinimumAge);
assertThat(configuration.isTaskCleanupJobAllCompletedSameParentBusiness()).isFalse();
assertThat(configuration.getPriorityJobBatchSize()).isEqualTo(expectedPriorityJobBatchSize);
assertThat(configuration.getPriorityJobFirstRun()).isEqualTo(expectedPriorityJobFirstRun);
assertThat(configuration.isPriorityJobActive()).isTrue();
assertThat(configuration.getUserRefreshJobFirstRun()).isEqualTo(expectedUserRefreshJobFirstRun);
assertThat(configuration.getUserRefreshJobRunEvery()).isEqualTo(expectedUserRefreshJobRunEvery);
assertThat(configuration.isAddAdditionalUserInfo()).isTrue();
assertThat(configuration.getMinimalPermissionsToAssignDomains())
.isEqualTo(expectedMinimalPermissionsToAssignDomains);
}
@Test
void should_PopulateEveryConfigurationProperty_When_UsingCopyConstructor() {
TaskanaConfiguration configuration =
new Builder(TestContainerExtension.createDataSourceForH2(), false, "TASKANA")
.domains(List.of("A", "B"))
.roleMap(Map.of(TaskanaRole.ADMIN, Set.of("admin")))
.classificationTypes(List.of("typeA", "typeB"))
.classificationCategoriesByTypeMap(
Map.of("typeA", List.of("categoryA"), "typeB", List.of("categoryB")))
.allowTimestampServiceLevelMismatch(true)
.customHolidays(List.of(CustomHoliday.of(10, 10)))
.germanPublicHolidaysEnabled(true)
.corpusChristiEnabled(true)
.deleteHistoryOnTaskDeletionEnabled(true)
.jobBatchSize(50)
.maxNumberOfJobRetries(500)
.cleanupJobFirstRun(Instant.MIN)
.cleanupJobRunEvery(Duration.ofDays(2))
.cleanupJobMinimumAge(Duration.ZERO)
.taskCleanupJobAllCompletedSameParentBusiness(false)
.priorityJobBatchSize(49)
.priorityJobFirstRun(Instant.MIN.plus(1, ChronoUnit.DAYS))
.priorityJobActive(true)
.userRefreshJobFirstRun(Instant.MIN.plus(2, ChronoUnit.DAYS))
.userRefreshJobRunEvery(Duration.ofDays(5))
.addAdditionalUserInfo(true)
.minimalPermissionsToAssignDomains(List.of(WorkbasketPermission.CUSTOM_2))
.build();
TaskanaConfiguration copyConfiguration = new Builder(configuration).build();
assertThat(copyConfiguration)
.hasNoNullFieldsOrProperties()
.usingRecursiveComparison()
.isEqualTo(configuration);
}
}

View File

@ -18,6 +18,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
@ -43,83 +44,105 @@ public class TaskanaConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaConfiguration.class);
// region general configuration
private final DataSource dataSource;
private final boolean securityEnabled;
private final boolean useManagedTransactions;
private final String schemaName;
@TaskanaProperty("taskana.german.holidays.enabled")
private final boolean germanPublicHolidaysEnabled;
// endregion
@TaskanaProperty("taskana.german.holidays.corpus-christi.enabled")
private final boolean corpusChristiEnabled;
// endregion
// region history configuration
@TaskanaProperty("taskana.history.deletion.on.task.deletion.enabled")
private final boolean deleteHistoryOnTaskDeletionEnabled;
// region custom configuration
private final Map<String, String> properties;
// Taskana role configuration
private final Map<TaskanaRole, Set<String>> roleMap;
@TaskanaProperty("taskana.domains")
private List<String> domains = new ArrayList<>();
// endregion
// region authentication configuration
private Map<TaskanaRole, Set<String>> roleMap = new EnumMap<>(TaskanaRole.class);
// region classification configuration
@TaskanaProperty("taskana.classification.types")
private List<String> classificationTypes = new ArrayList<>();
// TODO: make this a Set
private Map<String, List<String>> classificationCategoriesByType = new HashMap<>();
// endregion
@TaskanaProperty("taskana.validation.allowTimestampServiceLevelMismatch")
private boolean allowTimestampServiceLevelMismatch = false;
// endregion
// region holiday configuration
@TaskanaProperty("taskana.custom.holidays")
private List<CustomHoliday> customHolidays = new ArrayList<>();
// region job configuration
// TODO validate this is positive
@TaskanaProperty("taskana.jobs.batchSize")
private int jobBatchSize = 100;
// TODO validate this is positive
@TaskanaProperty("taskana.jobs.maxRetries")
private int maxNumberOfJobRetries = 3;
private final boolean securityEnabled;
@TaskanaProperty("taskana.jobs.cleanup.firstRunAt")
private Instant cleanupJobFirstRun = Instant.parse("2018-01-01T00:00:00Z");
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.cleanup.runEvery")
private Duration cleanupJobRunEvery = Duration.ofDays(1);
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.cleanup.minimumAge")
private Duration cleanupJobMinimumAge = Duration.ofDays(14);
private final boolean useManagedTransactions;
@TaskanaProperty("taskana.jobs.cleanup.allCompletedSameParentBusiness")
private boolean taskCleanupJobAllCompletedSameParentBusiness = true;
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.priority.batchSize")
private int priorityJobBatchSize = 100;
private final List<String> domains;
private final List<String> classificationTypes;
@TaskanaProperty("taskana.jobs.priority.firstRunAt")
private Instant priorityJobFirstRun = Instant.parse("2018-01-01T00:00:00Z");
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.priority.runEvery")
private Duration priorityJobRunEvery = Duration.ofDays(1);
private final Map<String, List<String>> classificationCategoriesByTypeMap;
private final List<CustomHoliday> customHolidays;
// Properties for the monitor
private final boolean deleteHistoryOnTaskDeletionEnabled;
private final boolean germanPublicHolidaysEnabled;
private final boolean corpusChristiEnabled;
private final int jobBatchSize;
private final int maxNumberOfJobRetries;
private final Instant cleanupJobFirstRun;
private final Duration cleanupJobRunEvery;
private final Duration cleanupJobMinimumAge;
private final boolean taskCleanupJobAllCompletedSameParentBusiness;
private final boolean validationAllowTimestampServiceLevelMismatch;
private final boolean addAdditionalUserInfo;
private final int priorityJobBatchSize;
private final Instant priorityJobFirstRun;
private final Duration priorityJobRunEvery;
private final boolean priorityJobActive;
private final Duration userRefreshJobRunEvery;
private final Instant userRefreshJobFirstRun;
private final List<WorkbasketPermission> minimalPermissionsToAssignDomains;
@TaskanaProperty("taskana.jobs.priority.active")
private boolean priorityJobActive = false;
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.user.refresh.runEvery")
private Duration userRefreshJobRunEvery = Duration.ofDays(1);
// endregion
@TaskanaProperty("taskana.jobs.user.refresh.firstRunAt")
private Instant userRefreshJobFirstRun = Instant.parse("2018-01-01T23:00:00Z");
// region user configuration
@TaskanaProperty("taskana.addAdditionalUserInfo")
private boolean addAdditionalUserInfo = false;
// endregion
// TODO: make Set
@TaskanaProperty("taskana.user.minimalPermissionsToAssignDomains")
private List<WorkbasketPermission> minimalPermissionsToAssignDomains = new ArrayList<>();
// endregion
protected TaskanaConfiguration(Builder builder) {
this.dataSource = builder.dataSource;
this.schemaName = builder.schemaName;
this.properties = Collections.unmodifiableMap(builder.properties);
this.properties = Map.copyOf(builder.properties);
this.roleMap =
builder.roleMap.entrySet().stream()
.collect(
Collectors.toUnmodifiableMap(
Entry::getKey, e -> Collections.unmodifiableSet(e.getValue())));
this.securityEnabled = builder.securityEnabled;
this.useManagedTransactions = builder.useManagedTransactions;
this.domains = Collections.unmodifiableList(builder.domains);
this.classificationTypes = Collections.unmodifiableList(builder.classificationTypes);
this.classificationCategoriesByTypeMap =
builder.classificationCategoriesByTypeMap.entrySet().stream()
this.classificationCategoriesByType =
builder.classificationCategoriesByType.entrySet().stream()
.collect(
Collectors.toUnmodifiableMap(
Entry::getKey, e -> Collections.unmodifiableList(e.getValue())));
this.customHolidays = Collections.unmodifiableList(builder.customHolidays);
this.deleteHistoryOnTaskDeletionEnabled = builder.deleteHistoryOnTaskDeletionEnabled;
this.germanPublicHolidaysEnabled = builder.germanPublicHolidaysEnabled;
@ -131,8 +154,7 @@ public class TaskanaConfiguration {
this.cleanupJobMinimumAge = builder.cleanupJobMinimumAge;
this.taskCleanupJobAllCompletedSameParentBusiness =
builder.taskCleanupJobAllCompletedSameParentBusiness;
this.validationAllowTimestampServiceLevelMismatch =
builder.validationAllowTimestampServiceLevelMismatch;
this.allowTimestampServiceLevelMismatch = builder.allowTimestampServiceLevelMismatch;
this.addAdditionalUserInfo = builder.addAdditionalUserInfo;
this.priorityJobBatchSize = builder.priorityJobBatchSize;
this.priorityJobFirstRun = builder.priorityJobFirstRun;
@ -188,7 +210,7 @@ public class TaskanaConfiguration {
return this.useManagedTransactions;
}
public int getMaxNumberOfUpdatesPerTransaction() {
public int getJobBatchSize() {
return jobBatchSize;
}
@ -204,8 +226,8 @@ public class TaskanaConfiguration {
return this.germanPublicHolidaysEnabled;
}
public boolean isValidationAllowTimestampServiceLevelMismatch() {
return validationAllowTimestampServiceLevelMismatch;
public boolean isAllowTimestampServiceLevelMismatch() {
return allowTimestampServiceLevelMismatch;
}
public boolean isDeleteHistoryOnTaskDeletionEnabled() {
@ -234,19 +256,19 @@ public class TaskanaConfiguration {
public List<String> getAllClassificationCategories() {
List<String> classificationCategories = new ArrayList<>();
for (Map.Entry<String, List<String>> type : this.classificationCategoriesByTypeMap.entrySet()) {
for (Map.Entry<String, List<String>> type : this.classificationCategoriesByType.entrySet()) {
classificationCategories.addAll(type.getValue());
}
return classificationCategories;
}
public Map<String, List<String>> getClassificationCategoriesByTypeMap() {
return this.classificationCategoriesByTypeMap.entrySet().stream()
public Map<String, List<String>> getClassificationCategoriesByType() {
return this.classificationCategoriesByType.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, e -> new ArrayList<>(e.getValue())));
}
public List<String> getClassificationCategoriesByType(String type) {
return classificationCategoriesByTypeMap.getOrDefault(type, Collections.emptyList());
return classificationCategoriesByType.getOrDefault(type, Collections.emptyList());
}
public Instant getCleanupJobFirstRun() {
@ -310,86 +332,105 @@ public class TaskanaConfiguration {
public static class Builder {
private static final Logger LOGGER = LoggerFactory.getLogger(Builder.class);
private static final String TASKANA_PROPERTIES = "/taskana.properties";
private static final String TASKANA_PROPERTY_SEPARATOR = "|";
// region general configuration
private final DataSource dataSource;
private final boolean securityEnabled;
private final boolean useManagedTransactions;
private String schemaName;
private Map<String, String> properties;
private Map<TaskanaRole, Set<String>> roleMap = new EnumMap<>(TaskanaRole.class);
// List of configured domain names
@TaskanaProperty("taskana.domains")
private List<String> domains = new ArrayList<>();
// endregion
// region authentication configuration
private Map<TaskanaRole, Set<String>> roleMap = new EnumMap<>(TaskanaRole.class);
// endregion
// region classification configuration
@TaskanaProperty("taskana.classification.types")
private List<String> classificationTypes = new ArrayList<>();
private Map<String, List<String>> classificationCategoriesByTypeMap = new HashMap<>();
// TODO: make this a Set
private Map<String, List<String>> classificationCategoriesByType = new HashMap<>();
@TaskanaProperty("taskana.validation.allowTimestampServiceLevelMismatch")
private boolean allowTimestampServiceLevelMismatch = false;
// endregion
// region holiday configuration
@TaskanaProperty("taskana.custom.holidays")
private List<CustomHoliday> customHolidays = new ArrayList<>();
// Properties for the monitor
@TaskanaProperty("taskana.history.deletion.on.task.deletion.enabled")
private boolean deleteHistoryOnTaskDeletionEnabled;
@TaskanaProperty("taskana.german.holidays.enabled")
private boolean germanPublicHolidaysEnabled;
@TaskanaProperty("taskana.german.holidays.corpus-christi.enabled")
private boolean corpusChristiEnabled;
// endregion
// Properties for general job execution
// region history configuration
@TaskanaProperty("taskana.history.deletion.on.task.deletion.enabled")
private boolean deleteHistoryOnTaskDeletionEnabled;
// endregion
// region job configuration
// TODO validate this is positive
@TaskanaProperty("taskana.jobs.batchSize")
private int jobBatchSize = 100;
// TODO validate this is positive
@TaskanaProperty("taskana.jobs.maxRetries")
private int maxNumberOfJobRetries = 3;
// Properties for the cleanup job
@TaskanaProperty("taskana.jobs.cleanup.firstRunAt")
private Instant cleanupJobFirstRun = Instant.parse("2018-01-01T00:00:00Z");
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.cleanup.runEvery")
private Duration cleanupJobRunEvery = Duration.parse("P1D");
private Duration cleanupJobRunEvery = Duration.ofDays(1);
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.cleanup.minimumAge")
private Duration cleanupJobMinimumAge = Duration.parse("P14D");
// TASKANA behavior
private Duration cleanupJobMinimumAge = Duration.ofDays(14);
@TaskanaProperty("taskana.jobs.cleanup.allCompletedSameParentBusiness")
private boolean taskCleanupJobAllCompletedSameParentBusiness = true;
@TaskanaProperty("taskana.validation.allowTimestampServiceLevelMismatch")
private boolean validationAllowTimestampServiceLevelMismatch = false;
// Property to enable/disable the addition of user full/long name through joins
@TaskanaProperty("taskana.addAdditionalUserInfo")
private boolean addAdditionalUserInfo = false;
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.priority.batchSize")
private int priorityJobBatchSize = 100;
@TaskanaProperty("taskana.jobs.priority.firstRunAt")
private Instant priorityJobFirstRun = Instant.parse("2018-01-01T00:00:00Z");
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.priority.runEvery")
private Duration priorityJobRunEvery = Duration.parse("P1D");
private Duration priorityJobRunEvery = Duration.ofDays(1);
@TaskanaProperty("taskana.jobs.priority.active")
private boolean priorityJobActive = false;
// TODO: validate this is positive
@TaskanaProperty("taskana.jobs.user.refresh.runEvery")
private Duration userRefreshJobRunEvery = Duration.parse("P1D");
private Duration userRefreshJobRunEvery = Duration.ofDays(1);
@TaskanaProperty("taskana.jobs.user.refresh.firstRunAt")
private Instant userRefreshJobFirstRun = Instant.parse("2018-01-01T23:00:00Z");
// endregion
// region user configuration
@TaskanaProperty("taskana.addAdditionalUserInfo")
private boolean addAdditionalUserInfo = false;
// TODO: make Set
@TaskanaProperty("taskana.user.minimalPermissionsToAssignDomains")
private List<WorkbasketPermission> minimalPermissionsToAssignDomains = new ArrayList<>();
// endregion
// region custom configuration
private Map<String, String> properties = Collections.emptyMap();
// endregion
public Builder(TaskanaConfiguration tec) {
this.dataSource = tec.getDatasource();
@ -400,20 +441,19 @@ public class TaskanaConfiguration {
this.useManagedTransactions = tec.isUseManagedTransactions();
this.domains = tec.getDomains();
this.classificationTypes = tec.getClassificationTypes();
this.classificationCategoriesByTypeMap = tec.getClassificationCategoriesByTypeMap();
this.classificationCategoriesByType = tec.getClassificationCategoriesByType();
this.customHolidays = tec.getCustomHolidays();
this.deleteHistoryOnTaskDeletionEnabled = tec.isDeleteHistoryOnTaskDeletionEnabled();
this.germanPublicHolidaysEnabled = tec.isGermanPublicHolidaysEnabled();
this.corpusChristiEnabled = tec.isCorpusChristiEnabled();
this.jobBatchSize = tec.getMaxNumberOfUpdatesPerTransaction();
this.jobBatchSize = tec.getJobBatchSize();
this.maxNumberOfJobRetries = tec.getMaxNumberOfJobRetries();
this.cleanupJobFirstRun = tec.getCleanupJobFirstRun();
this.cleanupJobRunEvery = tec.getCleanupJobRunEvery();
this.cleanupJobMinimumAge = tec.getCleanupJobMinimumAge();
this.taskCleanupJobAllCompletedSameParentBusiness =
tec.isTaskCleanupJobAllCompletedSameParentBusiness();
this.validationAllowTimestampServiceLevelMismatch =
tec.isValidationAllowTimestampServiceLevelMismatch();
this.allowTimestampServiceLevelMismatch = tec.isAllowTimestampServiceLevelMismatch();
this.addAdditionalUserInfo = tec.isAddAdditionalUserInfo();
this.priorityJobBatchSize = tec.getPriorityJobBatchSize();
this.priorityJobFirstRun = tec.getPriorityJobFirstRun();
@ -435,17 +475,14 @@ public class TaskanaConfiguration {
boolean securityEnabled) {
this.useManagedTransactions = useManagedTransactions;
this.securityEnabled = securityEnabled;
if (dataSource != null) {
this.dataSource = dataSource;
} else {
throw new SystemException("DataSource can't be null");
}
this.dataSource = Objects.requireNonNull(dataSource);
this.schemaName = initSchemaName(schemaName);
}
// region builder methods
@SuppressWarnings("unused")
// TODO: why do we need this method?
public Builder schemaName(String schemaName) {
this.schemaName = initSchemaName(schemaName);
return this;
@ -472,7 +509,7 @@ public class TaskanaConfiguration {
@SuppressWarnings("unused")
public Builder classificationCategoriesByTypeMap(
Map<String, List<String>> classificationCategoriesByTypeMap) {
this.classificationCategoriesByTypeMap = classificationCategoriesByTypeMap;
this.classificationCategoriesByType = classificationCategoriesByTypeMap;
return this;
}
@ -539,10 +576,9 @@ public class TaskanaConfiguration {
}
@SuppressWarnings("unused")
public Builder validationAllowTimestampServiceLevelMismatch(
public Builder allowTimestampServiceLevelMismatch(
boolean validationAllowTimestampServiceLevelMismatch) {
this.validationAllowTimestampServiceLevelMismatch =
validationAllowTimestampServiceLevelMismatch;
this.allowTimestampServiceLevelMismatch = validationAllowTimestampServiceLevelMismatch;
return this;
}
@ -599,55 +635,83 @@ public class TaskanaConfiguration {
return new TaskanaConfiguration(this);
}
@SuppressWarnings("unused")
// endregion
/**
* Configure the {@linkplain TaskanaConfiguration} with the default {@linkplain
* #TASKANA_PROPERTIES property file location} and {@linkplain #TASKANA_PROPERTY_SEPARATOR
* property separator}.
*
* @see #initTaskanaProperties(String, String)
*/
@SuppressWarnings({"unused", "checkstyle:JavadocMethod"})
public Builder initTaskanaProperties() {
return this.initTaskanaProperties(TASKANA_PROPERTIES, TASKANA_PROPERTY_SEPARATOR);
}
@SuppressWarnings("unused")
/**
* Configure the {@linkplain TaskanaConfiguration} with the default {@linkplain
* #TASKANA_PROPERTY_SEPARATOR property separator}.
*
* @see #initTaskanaProperties(String, String)
*/
@SuppressWarnings({"unused", "checkstyle:JavadocMethod"})
public Builder initTaskanaProperties(String propertiesFile) {
return this.initTaskanaProperties(propertiesFile, TASKANA_PROPERTY_SEPARATOR);
}
/**
* Configure the {@linkplain TaskanaConfiguration} using a property file from the classpath of
* {@linkplain TaskanaConfiguration TaskanaConfigurations} or the system.
*
* <p>Please check this builders instance fields for the {@linkplain TaskanaProperty} for
* property naming.
*
* @param propertiesFile path to the properties file.
* @param separator if a property is a collection type, this separator determines which sequence
* delimits each individual value.
* @return the builder
* @throws SystemException if propertiesFile or separator is null or empty
*/
public Builder initTaskanaProperties(String propertiesFile, String separator) {
if (propertiesFile == null || propertiesFile.isEmpty() || propertiesFile.isBlank()) {
throw new SystemException("property file can't be null or empty");
}
if (separator == null || separator.isEmpty() || separator.isBlank()) {
throw new SystemException("separator file can't be null or empty");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(
"Reading taskana configuration from {} with separator {}", propertiesFile, separator);
}
loadProperties(propertiesFile);
properties = loadProperties(propertiesFile);
configureAnnotatedFields(this, separator, properties);
roleMap = configureRoles(separator, properties, shouldUseLowerCaseForAccessIds());
classificationCategoriesByTypeMap =
classificationCategoriesByType =
configureClassificationCategoriesForType(properties, classificationTypes);
return this;
}
private String initSchemaName(String schemaName) {
String schemaNameTmp;
if (schemaName != null && !schemaName.isEmpty()) {
schemaNameTmp = schemaName;
} else {
throw new SystemException("SchemaName can't be null or empty");
if (schemaName == null || schemaName.isEmpty() || schemaName.isBlank()) {
throw new SystemException("schema name can't be null or empty");
}
try (Connection connection = dataSource.getConnection()) {
String databaseProductId = DB.getDatabaseProductId(connection);
if (DB.isPostgres(databaseProductId)) {
schemaNameTmp = schemaNameTmp.toLowerCase();
return schemaName.toLowerCase();
} else {
schemaNameTmp = schemaNameTmp.toUpperCase();
return schemaName.toUpperCase();
}
} catch (SQLException ex) {
LOGGER.error("Caught exception when attempting to initialize the schema name", ex);
throw new SystemException(
"Caught exception when attempting to initialize the schema name", ex);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Using schema name {}", schemaNameTmp);
}
return schemaNameTmp;
}
private void loadProperties(String propertiesFile) {
private Map<String, String> loadProperties(String propertiesFile) {
Properties props = new Properties();
try (InputStream stream =
FileLoaderUtil.openFileFromClasspathOrSystem(
@ -655,13 +719,12 @@ public class TaskanaConfiguration {
props.load(stream);
} catch (IOException e) {
throw new SystemException(
"internal System error when processing properties file " + propertiesFile, e);
String.format("Could not process properties file '%s'", propertiesFile), e);
}
this.properties =
props.entrySet().stream()
.collect(
Collectors.toUnmodifiableMap(
e -> e.getKey().toString(), e -> e.getValue().toString()));
return props.entrySet().stream()
.collect(
Collectors.toUnmodifiableMap(
e -> e.getKey().toString(), e -> e.getValue().toString()));
}
}
}

View File

@ -63,7 +63,7 @@ public class ClassificationChangedJob extends AbstractTaskanaJob {
}
private void scheduleTaskRefreshJobs(List<String> affectedTaskIds) {
int batchSize = taskanaEngineImpl.getConfiguration().getMaxNumberOfUpdatesPerTransaction();
int batchSize = taskanaEngineImpl.getConfiguration().getJobBatchSize();
Collection<List<String>> affectedTaskBatches =
CollectionUtil.partitionBasedOnSize(affectedTaskIds, batchSize);
if (LOGGER.isDebugEnabled()) {

View File

@ -84,6 +84,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
private static final String MINIMAL_TASKANA_SCHEMA_VERSION = "5.2.0";
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
private static final SessionStack SESSION_STACK = new SessionStack();
protected final TaskanaConfiguration taskanaEngineConfiguration;
private final TaskRoutingManager taskRoutingManager;
private final CreateTaskPreprocessorManager createTaskPreprocessorManager;
private final PriorityServiceManager priorityServiceManager;
@ -92,21 +93,23 @@ public class TaskanaEngineImpl implements TaskanaEngine {
private final AfterRequestReviewManager afterRequestReviewManager;
private final BeforeRequestChangesManager beforeRequestChangesManager;
private final AfterRequestChangesManager afterRequestChangesManager;
private final InternalTaskanaEngineImpl internalTaskanaEngineImpl;
private final WorkingDaysToDaysConverter workingDaysToDaysConverter;
private final HistoryEventManager historyEventManager;
private final CurrentUserContext currentUserContext;
protected TaskanaConfiguration taskanaEngineConfiguration;
protected ConnectionManagementMode mode;
protected TransactionFactory transactionFactory;
protected SqlSessionManager sessionManager;
protected ConnectionManagementMode mode;
protected Connection connection;
protected TaskanaEngineImpl(
TaskanaConfiguration taskanaEngineConfiguration,
ConnectionManagementMode connectionManagementMode)
throws SQLException {
LOGGER.info(
"initializing TASKANA with this configuration: {} and this mode: {}",
taskanaEngineConfiguration,
connectionManagementMode);
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
this.mode = connectionManagementMode;
internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
@ -345,7 +348,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
// register type handlers
if (DB.isOracleDb(databaseProductName)) {
// Use NULL instead of OTHER when jdbcType is not specified for null values,
// otherwise oracle driver will chunck on null values
// otherwise oracle driver will chunk on null values
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.getTypeHandlerRegistry().register(String.class, new StringTypeHandler());
}

View File

@ -252,10 +252,7 @@ class ServiceLevelHandler {
private TaskImpl updatePlannedDueOnTaskUpdate(
TaskImpl newTaskImpl, TaskImpl oldTaskImpl, DurationPrioHolder durationPrioHolder)
throws InvalidArgumentException {
if (taskanaEngine
.getEngine()
.getConfiguration()
.isValidationAllowTimestampServiceLevelMismatch()
if (taskanaEngine.getEngine().getConfiguration().isAllowTimestampServiceLevelMismatch()
&& newTaskImpl.getDue() != null
&& newTaskImpl.getPlanned() != null) {
@ -343,10 +340,7 @@ class ServiceLevelHandler {
private TaskImpl updatePlannedDueOnCreationOfNewTask(
TaskImpl newTask, DurationPrioHolder durationPrioHolder) throws InvalidArgumentException {
if (taskanaEngine
.getEngine()
.getConfiguration()
.isValidationAllowTimestampServiceLevelMismatch()
if (taskanaEngine.getEngine().getConfiguration().isAllowTimestampServiceLevelMismatch()
&& newTask.getDue() != null
&& newTask.getPlanned() != null) {
return newTask;

View File

@ -43,7 +43,7 @@ public class TaskCleanupJob extends AbstractTaskanaJob {
ScheduledJob scheduledJob) {
super(taskanaEngine, txProvider, scheduledJob, true);
minimumAge = taskanaEngine.getConfiguration().getCleanupJobMinimumAge();
batchSize = taskanaEngine.getConfiguration().getMaxNumberOfUpdatesPerTransaction();
batchSize = taskanaEngine.getConfiguration().getJobBatchSize();
allCompletedSameParentBusiness =
taskanaEngine.getConfiguration().isTaskCleanupJobAllCompletedSameParentBusiness();
}

View File

@ -31,7 +31,7 @@ public class WorkbasketCleanupJob extends AbstractTaskanaJob {
public WorkbasketCleanupJob(
TaskanaEngine taskanaEngine, TaskanaTransactionProvider txProvider, ScheduledJob job) {
super(taskanaEngine, txProvider, job, true);
batchSize = taskanaEngine.getConfiguration().getMaxNumberOfUpdatesPerTransaction();
batchSize = taskanaEngine.getConfiguration().getJobBatchSize();
}
@Override

View File

@ -84,7 +84,7 @@ class TaskanaConfigAccTest {
true)
.initTaskanaProperties(propertiesFileName, delimiter)
.build();
assertThat(taskanaEngineConfiguration.getClassificationCategoriesByTypeMap())
assertThat(taskanaEngineConfiguration.getClassificationCategoriesByType())
.containsExactly(
Map.entry("TASK", Collections.emptyList()),
Map.entry("DOCUMENT", Collections.emptyList()));
@ -102,7 +102,7 @@ class TaskanaConfigAccTest {
true)
.initTaskanaProperties(propertiesFileName, delimiter)
.build();
assertThat(taskanaEngineConfiguration.getClassificationCategoriesByTypeMap())
assertThat(taskanaEngineConfiguration.getClassificationCategoriesByType())
.containsExactly(
Map.entry("TASK", List.of("EXTERNAL", "MANUAL", "AUTOMATIC", "PROCESS")),
Map.entry("DOCUMENT", List.of("EXTERNAL")));

View File

@ -199,7 +199,7 @@ class CreateTaskAccTest extends AbstractAccTest {
// Given
TaskanaConfiguration taskanaEngineConfiguration =
new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngineConfiguration)
.validationAllowTimestampServiceLevelMismatch(true)
.allowTimestampServiceLevelMismatch(true)
.build();
TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaEngineConfiguration);
Task newTask = taskanaEngine.getTaskService().newTask("USER-1-1", "DOMAIN_A");

View File

@ -74,7 +74,7 @@ class UpdateTaskAccTest extends AbstractAccTest {
// Given
TaskanaConfiguration taskanaEngineConfiguration =
new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngineConfiguration)
.validationAllowTimestampServiceLevelMismatch(false)
.allowTimestampServiceLevelMismatch(false)
.build();
TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaEngineConfiguration);
Task task = taskanaEngine.getTaskService().getTask("TKI:000000000000000000000000000000000000");
@ -96,7 +96,7 @@ class UpdateTaskAccTest extends AbstractAccTest {
// Given
TaskanaConfiguration taskanaEngineConfiguration =
new TaskanaConfiguration.Builder(AbstractAccTest.taskanaEngineConfiguration)
.validationAllowTimestampServiceLevelMismatch(true)
.allowTimestampServiceLevelMismatch(true)
.build();
TaskanaEngine taskanaEngine = TaskanaEngine.buildTaskanaEngine(taskanaEngineConfiguration);
Task task = taskanaEngine.getTaskService().getTask("TKI:000000000000000000000000000000000000");

View File

@ -91,7 +91,7 @@ public class TaskanaEngineController {
@GetMapping(path = RestEndpoints.URL_CLASSIFICATION_CATEGORIES_BY_TYPES)
@Transactional(readOnly = true, rollbackFor = Exception.class)
public ResponseEntity<Map<String, List<String>>> getClassificationCategoriesByTypeMap() {
return ResponseEntity.ok(taskanaEngineConfiguration.getClassificationCategoriesByTypeMap());
return ResponseEntity.ok(taskanaEngineConfiguration.getClassificationCategoriesByType());
}
/**