Reformat Code Using google-java-format 1.23.0

This commit is contained in:
James Reynaldi 2024-08-23 14:20:16 +02:00 committed by ryzheboka
parent 4092162e93
commit d70080255a
217 changed files with 7474 additions and 7189 deletions

View File

@ -1,20 +1,20 @@
version: 2
updates:
- package-ecosystem: maven
- package-ecosystem: maven
directory: "/"
schedule:
interval: daily
time: "06:00"
timezone: Europe/Berlin
open-pull-requests-limit: 99
- package-ecosystem: github-actions
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
time: "06:00"
timezone: Europe/Berlin
open-pull-requests-limit: 99
- package-ecosystem: docker
- package-ecosystem: docker
directory: "/"
schedule:
interval: daily

View File

@ -1,7 +1,9 @@
<!-- if needed please write above the given line -->
### Thanks for your PR! Please fill out the following list :)
---
- [ ] I put the ticket or multiple tickets in review
- [ ] Commit message format → Closes #&lt;Issue Number&gt; - Your commit message.
- [ ] Sonarcloud link : \<add the link here>
@ -9,7 +11,9 @@
- [ ] Link to PR with documentation update: \<add the link here>
- [ ] No Release Notes needed
- [ ] Release Notes :
<!-- Please write your release notes between ```-->
```
```

View File

@ -1,31 +1,31 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build Backend No Checkstyle" type="MavenRunConfiguration" factoryName="Maven">
<MavenSettings>
<option name="myGeneralSettings" />
<option name="myRunnerSettings" />
<option name="myGeneralSettings"/>
<option name="myRunnerSettings"/>
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="profiles">
<set />
<set/>
</option>
<option name="goals">
<list>
<option value="clean" />
<option value="install" />
<option value="-DskipTests" />
<option value="-Dcheckstyle.skip" />
<option value="-Dasciidoctor.skip" />
<option value="clean"/>
<option value="install"/>
<option value="-DskipTests"/>
<option value="-Dcheckstyle.skip"/>
<option value="-Dasciidoctor.skip"/>
</list>
</option>
<option name="pomFileName" />
<option name="pomFileName"/>
<option name="profilesMap">
<map />
<map/>
</option>
<option name="resolveToWorkspace" value="false" />
<option name="workingDirPath" value="$PROJECT_DIR$" />
<option name="resolveToWorkspace" value="false"/>
<option name="workingDirPath" value="$PROJECT_DIR$"/>
</MavenRunnerParameters>
</option>
</MavenSettings>
<method v="2" />
<method v="2"/>
</configuration>
</component>

View File

@ -1,29 +1,29 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Build Backend" type="MavenRunConfiguration" factoryName="Maven">
<MavenSettings>
<option name="myGeneralSettings" />
<option name="myRunnerSettings" />
<option name="myGeneralSettings"/>
<option name="myRunnerSettings"/>
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="profiles">
<set />
<set/>
</option>
<option name="goals">
<list>
<option value="clean" />
<option value="install" />
<option value="-DskipTests" />
<option value="clean"/>
<option value="install"/>
<option value="-DskipTests"/>
</list>
</option>
<option name="pomFileName" />
<option name="pomFileName"/>
<option name="profilesMap">
<map />
<map/>
</option>
<option name="resolveToWorkspace" value="false" />
<option name="workingDirPath" value="$PROJECT_DIR$" />
<option name="resolveToWorkspace" value="false"/>
<option name="workingDirPath" value="$PROJECT_DIR$"/>
</MavenRunnerParameters>
</option>
</MavenSettings>
<method v="2" />
<method v="2"/>
</configuration>
</component>

View File

@ -1,28 +1,28 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Clean Install" type="MavenRunConfiguration" factoryName="Maven">
<MavenSettings>
<option name="myGeneralSettings" />
<option name="myRunnerSettings" />
<option name="myGeneralSettings"/>
<option name="myRunnerSettings"/>
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="profiles">
<set />
<set/>
</option>
<option name="goals">
<list>
<option value="clean" />
<option value="install" />
<option value="clean"/>
<option value="install"/>
</list>
</option>
<option name="pomFileName" />
<option name="pomFileName"/>
<option name="profilesMap">
<map />
<map/>
</option>
<option name="resolveToWorkspace" value="false" />
<option name="workingDirPath" value="$PROJECT_DIR$" />
<option name="resolveToWorkspace" value="false"/>
<option name="workingDirPath" value="$PROJECT_DIR$"/>
</MavenRunnerParameters>
</option>
</MavenSettings>
<method v="2" />
<method v="2"/>
</configuration>
</component>

View File

@ -1,6 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug Frontend" type="JavascriptDebugType" uri="http://localhost:4200" useFirstLineBreakpoints="true">
<mapping url="webpack:///./src" local-file="$PROJECT_DIR$/web/src" />
<method v="2" />
<configuration default="false" name="Debug Frontend" type="JavascriptDebugType" uri="http://localhost:4200"
useFirstLineBreakpoints="true">
<mapping url="webpack:///./src" local-file="$PROJECT_DIR$/web/src"/>
<method v="2"/>
</configuration>
</component>

View File

@ -1,17 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Postgres" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="bash ./docker-databases/prepare_db.sh POSTGRES_14 &amp;&amp; exit" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/bash" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="true" />
<option name="EXECUTE_SCRIPT_FILE" value="false" />
<envs />
<method v="2" />
<option name="SCRIPT_TEXT" value="bash ./docker-databases/prepare_db.sh POSTGRES_14 &amp;&amp; exit"/>
<option name="INDEPENDENT_SCRIPT_PATH" value="true"/>
<option name="SCRIPT_PATH" value=""/>
<option name="SCRIPT_OPTIONS" value=""/>
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true"/>
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$"/>
<option name="INDEPENDENT_INTERPRETER_PATH" value="true"/>
<option name="INTERPRETER_PATH" value="/bin/bash"/>
<option name="INTERPRETER_OPTIONS" value=""/>
<option name="EXECUTE_IN_TERMINAL" value="true"/>
<option name="EXECUTE_SCRIPT_FILE" value="false"/>
<envs/>
<method v="2"/>
</configuration>
</component>

View File

@ -1,12 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Start Frontend" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/web/package.json" />
<command value="run" />
<package-json value="$PROJECT_DIR$/web/package.json"/>
<command value="run"/>
<scripts>
<script value="start" />
<script value="start"/>
</scripts>
<node-interpreter value="project" />
<envs />
<method v="2" />
<node-interpreter value="project"/>
<envs/>
<method v="2"/>
</configuration>
</component>

View File

@ -1,17 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Stop all DB" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="bash ./docker-databases/prepare_db.sh stop &amp;&amp; exit" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/bash" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="true" />
<option name="EXECUTE_SCRIPT_FILE" value="false" />
<envs />
<method v="2" />
<option name="SCRIPT_TEXT" value="bash ./docker-databases/prepare_db.sh stop &amp;&amp; exit"/>
<option name="INDEPENDENT_SCRIPT_PATH" value="true"/>
<option name="SCRIPT_PATH" value=""/>
<option name="SCRIPT_OPTIONS" value=""/>
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true"/>
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$"/>
<option name="INDEPENDENT_INTERPRETER_PATH" value="true"/>
<option name="INTERPRETER_PATH" value="/bin/bash"/>
<option name="INTERPRETER_OPTIONS" value=""/>
<option name="EXECUTE_IN_TERMINAL" value="true"/>
<option name="EXECUTE_SCRIPT_FILE" value="false"/>
<envs/>
<method v="2"/>
</configuration>
</component>

View File

@ -1,31 +1,32 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test E2E" type="CypressConfigurationType" factoryName="Cypress" show_console_on_std_err="false" show_console_on_std_out="false">
<option name="allowRunningInParallel" value="false" />
<configuration default="false" name="Test E2E" type="CypressConfigurationType" factoryName="Cypress"
show_console_on_std_err="false" show_console_on_std_out="false">
<option name="allowRunningInParallel" value="false"/>
<option name="envs">
<map />
<map/>
</option>
<option name="passParentEnvs" value="true" />
<option name="programParameters" value="" />
<option name="projectPathOnTarget" />
<option name="passParentEnvs" value="true"/>
<option name="programParameters" value=""/>
<option name="projectPathOnTarget"/>
<option name="selectedOptions">
<list />
<list/>
</option>
<option name="workingDirectory" value="$PROJECT_DIR$/web" />
<option name="textRange" />
<option name="allNames" />
<option name="specsDir" value="$PROJECT_DIR$/web/cypress/integration" />
<option name="specFile" />
<option name="testName" />
<option name="workingDirectory" value="file://$PROJECT_DIR$/web" />
<option name="workingDirectory" value="$PROJECT_DIR$/web"/>
<option name="textRange"/>
<option name="allNames"/>
<option name="specsDir" value="$PROJECT_DIR$/web/cypress/integration"/>
<option name="specFile"/>
<option name="testName"/>
<option name="workingDirectory" value="file://$PROJECT_DIR$/web"/>
<option name="envs">
<map />
<map/>
</option>
<option name="additionalParams" value="" />
<option name="passParentEnvs" value="true" />
<option name="nodeJsRef" value="project" />
<option name="npmRef" value="Project" />
<option name="kind" value="DIRECTORY" />
<option name="interactive" value="false" />
<method v="2" />
<option name="additionalParams" value=""/>
<option name="passParentEnvs" value="true"/>
<option name="nodeJsRef" value="project"/>
<option name="npmRef" value="Project"/>
<option name="kind" value="DIRECTORY"/>
<option name="interactive" value="false"/>
<method v="2"/>
</configuration>
</component>

View File

@ -1,12 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test Frontend" type="JavaScriptTestRunnerJest">
<config-file value="$PROJECT_DIR$/web/jest.config.js" />
<node-interpreter value="project" />
<node-options value="" />
<jest-package value="$PROJECT_DIR$/web/node_modules/jest" />
<working-dir value="$PROJECT_DIR$/web" />
<envs />
<scope-kind value="ALL" />
<method v="2" />
<config-file value="$PROJECT_DIR$/web/jest.config.js"/>
<node-interpreter value="project"/>
<node-options value=""/>
<jest-package value="$PROJECT_DIR$/web/node_modules/jest"/>
<working-dir value="$PROJECT_DIR$/web"/>
<envs/>
<scope-kind value="ALL"/>
<method v="2"/>
</configuration>
</component>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>kadai-common-logging</artifactId>

View File

@ -21,6 +21,27 @@ public class LoggingAspect {
public static final String ENABLE_LOGGING_ASPECT_PROPERTY_KEY = "enableLoggingAspect";
private static final Map<String, Logger> CLASS_TO_LOGGER = new ConcurrentHashMap<>();
// This method exists, so that we can mock the system property during testing.
public static boolean isLoggingAspectEnabled() {
return LazyHolder.LOGGING_ASPECT_ENABLED;
}
private static String mapParametersNameValue(String[] parameterNames, Object[] values) {
Map<String, Object> parametersNameToValue = new HashMap<>();
if (parameterNames.length > 0) {
for (int i = 0; i < parameterNames.length; i++) {
parametersNameToValue.put(parameterNames[i], values[i]);
}
}
StringBuilder stringBuilder = new StringBuilder();
for (Entry<String, Object> parameter : parametersNameToValue.entrySet()) {
stringBuilder.append(parameter.getKey()).append(" = ").append(parameter.getValue());
}
return stringBuilder.toString();
}
@Pointcut(
"!@annotation(io.kadai.common.internal.logging.NoLogging)"
+ " && !within(@io.kadai.common.internal.logging.NoLogging *)"
@ -33,11 +54,6 @@ public class LoggingAspect {
+ " && !execution(boolean *.equals(Object))")
public void traceLogging() {}
// This method exists, so that we can mock the system property during testing.
public static boolean isLoggingAspectEnabled() {
return LazyHolder.LOGGING_ASPECT_ENABLED;
}
@Before("traceLogging()")
public void beforeMethodExecuted(JoinPoint joinPoint) {
if (isLoggingAspectEnabled()) {
@ -81,22 +97,6 @@ public class LoggingAspect {
}
}
private static String mapParametersNameValue(String[] parameterNames, Object[] values) {
Map<String, Object> parametersNameToValue = new HashMap<>();
if (parameterNames.length > 0) {
for (int i = 0; i < parameterNames.length; i++) {
parametersNameToValue.put(parameterNames[i], values[i]);
}
}
StringBuilder stringBuilder = new StringBuilder();
for (Entry<String, Object> parameter : parametersNameToValue.entrySet()) {
stringBuilder.append(parameter.getKey()).append(" = ").append(parameter.getValue());
}
return stringBuilder.toString();
}
// This Initialization-on-demand holder idiom is necessary so that the retrieval of the system
// property will be executed during the execution of the first JointPoint.
// This allows us to set the system property during test execution BEFORE retrieving the system

View File

@ -19,16 +19,16 @@ import outside.of.io.kadai.OutsideOfProKadaiPackageLoggingTestClass;
@NoLogging
class LoggingAspectTest {
@BeforeEach
public void clearLoggers() {
TestLoggerFactory.clear();
}
@BeforeAll
public static void setup() {
System.setProperty(LoggingAspect.ENABLE_LOGGING_ASPECT_PROPERTY_KEY, "true");
}
@BeforeEach
public void clearLoggers() {
TestLoggerFactory.clear();
}
@Test
void should_NotLogMethodCalls_When_ClassDoesNotResideWithinKadaiPackage() {
OutsideOfProKadaiPackageLoggingTestClass loggingTestClass =

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>kadai-common-security</artifactId>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>kadai-common-test</artifactId>

View File

@ -48,6 +48,66 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
// region InvocationInterceptor
private static void persistDynamicContainerChildren(
Iterable<DynamicNode> nodes, Map<String, List<DynamicNode>> childrenMap) {
nodes.forEach(
node -> {
if (node instanceof DynamicContainer) {
DynamicContainer container = (DynamicContainer) node;
List<DynamicNode> children = container.getChildren().collect(Collectors.toList());
childrenMap.put(container.hashCode() + container.getDisplayName(), children);
persistDynamicContainerChildren(children, childrenMap);
}
});
}
private static DynamicNode duplicateDynamicNode(
DynamicNode node, Map<String, List<DynamicNode>> lookupMap) {
if (node instanceof DynamicContainer) {
DynamicContainer container = (DynamicContainer) node;
Stream<DynamicNode> children =
lookupMap.get(node.hashCode() + node.getDisplayName()).stream()
.map(x -> duplicateDynamicNode(x, lookupMap));
return DynamicContainer.dynamicContainer(container.getDisplayName(), children);
}
return node;
}
private static <T> T extractAccessIdAndPerformInvocation(
Invocation<T> invocation, AnnotatedElement executable) {
return performInvocationWithAccessId(invocation, executable.getAnnotation(WithAccessId.class));
}
private static <T> T performInvocationWithAccessId(
Invocation<T> invocation, WithAccessId withAccessId) {
Subject subject = new Subject();
subject.getPrincipals().addAll(getPrincipals(withAccessId));
Function<Invocation<T>, T> proceedInvocation =
wrapExceptFor(Invocation::proceed, TestAbortedException.class);
PrivilegedAction<T> performInvocation = () -> proceedInvocation.apply(invocation);
return Subject.doAs(subject, performInvocation);
}
private static List<Principal> getPrincipals(WithAccessId withAccessId) {
if (withAccessId != null) {
return Stream.concat(
Stream.of(withAccessId.user()).map(UserPrincipal::new),
Arrays.stream(withAccessId.groups()).map(GroupPrincipal::new))
.toList();
}
return Collections.emptyList();
}
private static Store getMethodLevelStore(ExtensionContext context) {
return context.getStore(
Namespace.create(context.getRequiredTestClass(), context.getRequiredTestMethod()));
}
private static String getDisplayNameForAccessId(WithAccessId withAccessId) {
return String.format("for user '%s'", withAccessId.user());
}
@Override
public <T> T interceptTestClassConstructor(
Invocation<T> invocation,
@ -64,6 +124,10 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
// region TestTemplateInvocationContextProvider
@Override
public void interceptBeforeEachMethod(
Invocation<Void> invocation,
@ -83,6 +147,8 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
@Override
@SuppressWarnings("unchecked")
public <T> T interceptTestFactoryMethod(
@ -193,10 +259,6 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
// region TestTemplateInvocationContextProvider
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return isAnnotated(context.getElement(), WithAccessIds.class)
@ -217,59 +279,6 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
});
}
// endregion
private static void persistDynamicContainerChildren(
Iterable<DynamicNode> nodes, Map<String, List<DynamicNode>> childrenMap) {
nodes.forEach(
node -> {
if (node instanceof DynamicContainer) {
DynamicContainer container = (DynamicContainer) node;
List<DynamicNode> children = container.getChildren().collect(Collectors.toList());
childrenMap.put(container.hashCode() + container.getDisplayName(), children);
persistDynamicContainerChildren(children, childrenMap);
}
});
}
private static DynamicNode duplicateDynamicNode(
DynamicNode node, Map<String, List<DynamicNode>> lookupMap) {
if (node instanceof DynamicContainer) {
DynamicContainer container = (DynamicContainer) node;
Stream<DynamicNode> children =
lookupMap.get(node.hashCode() + node.getDisplayName()).stream()
.map(x -> duplicateDynamicNode(x, lookupMap));
return DynamicContainer.dynamicContainer(container.getDisplayName(), children);
}
return node;
}
private static <T> T extractAccessIdAndPerformInvocation(
Invocation<T> invocation, AnnotatedElement executable) {
return performInvocationWithAccessId(invocation, executable.getAnnotation(WithAccessId.class));
}
private static <T> T performInvocationWithAccessId(
Invocation<T> invocation, WithAccessId withAccessId) {
Subject subject = new Subject();
subject.getPrincipals().addAll(getPrincipals(withAccessId));
Function<Invocation<T>, T> proceedInvocation =
wrapExceptFor(Invocation::proceed, TestAbortedException.class);
PrivilegedAction<T> performInvocation = () -> proceedInvocation.apply(invocation);
return Subject.doAs(subject, performInvocation);
}
private static List<Principal> getPrincipals(WithAccessId withAccessId) {
if (withAccessId != null) {
return Stream.concat(
Stream.of(withAccessId.user()).map(UserPrincipal::new),
Arrays.stream(withAccessId.groups()).map(GroupPrincipal::new))
.toList();
}
return Collections.emptyList();
}
private ExtensionContext getParentMethodExtensionContent(ExtensionContext extensionContext) {
Optional<ExtensionContext> parent = extensionContext.getParent();
// the class MethodExtensionContext is part of junit-jupiter-engine and has only a
@ -288,15 +297,6 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
"Test '%s' does not have a parent method", extensionContext.getUniqueId())));
}
private static Store getMethodLevelStore(ExtensionContext context) {
return context.getStore(
Namespace.create(context.getRequiredTestClass(), context.getRequiredTestMethod()));
}
private static String getDisplayNameForAccessId(WithAccessId withAccessId) {
return String.format("for user '%s'", withAccessId.user());
}
private static class JaasExtensionInvocationContext implements TestTemplateInvocationContext {
private final WithAccessId withAccessId;

View File

@ -64,6 +64,28 @@ class JaasExtensionTest {
// region JaasExtension#interceptBeforeEachMethod
@AfterAll
static void should_NotSetJaasSubject_When_AnnotationIsMissing_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
@WithAccessId(user = "afterall")
@AfterAll
static void should_SetJaasSubject_When_AnnotationExists_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("afterall");
}
@WithAccessId(user = "afterall")
@WithAccessId(user = "afterall2")
@AfterAll
static void should_NotSetJaasSubject_When_MultipleAnnotationsExist_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
// endregion
// region JaasExtension#interceptAfterEachMethod
@BeforeEach
void should_NotSetJaasSubject_When_AnnotationIsMissing_On_BeforeEach() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
@ -84,7 +106,7 @@ class JaasExtensionTest {
// endregion
// region JaasExtension#interceptAfterEachMethod
// region JaasExtension#interceptAfterAllMethod
@AfterEach
void should_NotSetJaasSubject_When_AnnotationIsMissing_On_AfterEach() {
@ -106,28 +128,6 @@ class JaasExtensionTest {
// endregion
// region JaasExtension#interceptAfterAllMethod
@AfterAll
static void should_NotSetJaasSubject_When_AnnotationIsMissing_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
@WithAccessId(user = "afterall")
@AfterAll
static void should_SetJaasSubject_When_AnnotationExists_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("afterall");
}
@WithAccessId(user = "afterall")
@WithAccessId(user = "afterall2")
@AfterAll
static void should_NotSetJaasSubject_When_MultipleAnnotationsExist_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
// endregion
// region JaasExtension#interceptTestMethod
@Test
@ -412,8 +412,7 @@ class JaasExtensionTest {
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)
@TestFactory
Iterable<DynamicTest> should_SetAccessIdForDynamicTestInIterable_When_AnnotationExists() {
return Stream.of(DYNAMIC_TEST_USER_DYNAMIC_TEST, DYNAMIC_TEST_USER_DYNAMIC_TEST)
.toList();
return Stream.of(DYNAMIC_TEST_USER_DYNAMIC_TEST, DYNAMIC_TEST_USER_DYNAMIC_TEST).toList();
}
@WithAccessId(user = INSIDE_DYNAMIC_TEST_USER)

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>kadai-common</artifactId>

View File

@ -11,6 +11,16 @@ import java.util.List;
*/
public interface BaseQuery<T, U extends Enum<U> & QueryColumnName> {
static String[] toLowerCopy(String... source) {
if (source == null || source.length == 0) {
return null;
// we are currently aware that this is a code smell. Unfortunately the resolution of this
// would cause havoc in our queries, since we do not have a concept
// for a user input validation yet. As soon as that is done we can resolve this code smell.
}
return Arrays.stream(source).map(String::toLowerCase).toArray(String[]::new);
}
/**
* This method will return a list of defined {@link T} objects. In case of a TaskQuery, this
* method can throw a NotAuthorizedToQueryWorkbasketException.
@ -76,16 +86,6 @@ public interface BaseQuery<T, U extends Enum<U> & QueryColumnName> {
*/
long count();
static String[] toLowerCopy(String... source) {
if (source == null || source.length == 0) {
return null;
// we are currently aware that this is a code smell. Unfortunately the resolution of this
// would cause havoc in our queries, since we do not have a concept
// for a user input validation yet. As soon as that is done we can resolve this code smell.
}
return Arrays.stream(source).map(String::toLowerCase).toArray(String[]::new);
}
/** Determines the sort direction. */
enum SortDirection {
ASCENDING("ASC"),

View File

@ -12,6 +12,10 @@ public final class CustomHoliday {
this.month = month;
}
public static CustomHoliday of(Integer day, Integer month) {
return new CustomHoliday(day, month);
}
public Integer getDay() {
return day;
}
@ -20,10 +24,6 @@ public final class CustomHoliday {
return month;
}
public static CustomHoliday of(Integer day, Integer month) {
return new CustomHoliday(day, month);
}
@Override
public int hashCode() {
return Objects.hash(day, month);

View File

@ -16,14 +16,14 @@ public class KadaiException extends Exception {
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
protected static Serializable ensureNullIsHandled(Serializable o) {
return o == null ? "null" : o;
}
public ErrorCode getErrorCode() {
return errorCode;
}
@Override
public String toString() {
return getClass().getSimpleName()

View File

@ -16,14 +16,14 @@ public class KadaiRuntimeException extends RuntimeException {
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
protected static Serializable ensureNullIsHandled(Serializable o) {
return o == null ? "null" : o;
}
public ErrorCode getErrorCode() {
return errorCode;
}
@Override
public String toString() {
return getClass().getSimpleName()

View File

@ -5,8 +5,8 @@ import java.util.Arrays;
import java.util.Map;
/**
* This exception is thrown when the current user is not in a certain {@linkplain KadaiRole role}
* it is supposed to be.
* This exception is thrown when the current user is not in a certain {@linkplain KadaiRole role} it
* is supposed to be.
*/
public class NotAuthorizedException extends KadaiException {

View File

@ -21,10 +21,7 @@ public class MapPropertyParser implements PropertyParser<Map<?, ?>> {
@Override
public Optional<Map<?, ?>> parse(
Map<String, String> properties,
String separator,
Field field,
KadaiProperty kadaiProperty) {
Map<String, String> properties, String separator, Field field, KadaiProperty kadaiProperty) {
if (!Map.class.isAssignableFrom(field.getType())) {
throw new SystemException(
String.format(

View File

@ -21,6 +21,13 @@ public class SimpleParser<T> implements PropertyParser<T> {
this.parseFunction = parseFunction;
}
protected static List<String> splitStringAndTrimElements(String str, String separator) {
return Arrays.stream(str.split(Pattern.quote(separator)))
.filter(not(String::isEmpty))
.map(String::trim)
.toList();
}
@Override
public Optional<T> parse(String value, String separator, Type type) {
Class<?> rawClass = ReflectionUtil.getRawClass(type);
@ -37,11 +44,4 @@ public class SimpleParser<T> implements PropertyParser<T> {
public Class<?> getTargetClass() {
return targetClass;
}
protected static List<String> splitStringAndTrimElements(String str, String separator) {
return Arrays.stream(str.split(Pattern.quote(separator)))
.filter(not(String::isEmpty))
.map(String::trim)
.toList();
}
}

View File

@ -14,6 +14,13 @@ import org.apache.ibatis.type.JdbcType;
/** Instruct jdbc driver to interpret timestamps as being in utc timezone. */
public class InstantTypeHandler extends BaseTypeHandler<Instant> {
private static Instant getInstant(Timestamp timestamp) {
if (timestamp != null) {
return timestamp.toInstant();
}
return null;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Instant parameter, JdbcType jdbcType)
throws SQLException {
@ -41,11 +48,4 @@ public class InstantTypeHandler extends BaseTypeHandler<Instant> {
cs.getTimestamp(columnIndex, Calendar.getInstance(TimeZone.getTimeZone("UTC")));
return getInstant(timestamp);
}
private static Instant getInstant(Timestamp timestamp) {
if (timestamp != null) {
return timestamp.toInstant();
}
return null;
}
}

View File

@ -6,8 +6,6 @@ import java.util.function.Supplier;
@FunctionalInterface
public interface KadaiTransactionProvider {
<T> T executeInTransaction(Supplier<T> supplier);
static <T> T executeInTransactionIfPossible(
KadaiTransactionProvider transactionProvider, Supplier<T> supplier) {
return transactionProvider != null
@ -24,4 +22,6 @@ public interface KadaiTransactionProvider {
return null;
});
}
<T> T executeInTransaction(Supplier<T> supplier);
}

View File

@ -83,6 +83,34 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
return new ComparableVersion(version);
}
private static Item parseItem(boolean isDigit, String buf) {
if (isDigit) {
buf = stripLeadingZeroes(buf);
if (buf.length() <= MAX_INT_ITEM_LENGTH) {
// lower than 2^31
return new IntItem(buf);
} else if (buf.length() <= MAX_LONG_ITEM_LENGTH) {
// lower than 2^63
return new LongItem(buf);
}
return new BigIntegerItem(buf);
}
return new StringItem(buf, false);
}
private static String stripLeadingZeroes(String buf) {
if (buf == null || buf.isEmpty()) {
return "0";
}
for (int i = 0; i < buf.length(); ++i) {
char c = buf.charAt(i);
if (c != '0') {
return buf.substring(i);
}
}
return buf;
}
public final void parseVersion(String version) {
this.value = version;
@ -164,34 +192,6 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
return canonical;
}
private static Item parseItem(boolean isDigit, String buf) {
if (isDigit) {
buf = stripLeadingZeroes(buf);
if (buf.length() <= MAX_INT_ITEM_LENGTH) {
// lower than 2^31
return new IntItem(buf);
} else if (buf.length() <= MAX_LONG_ITEM_LENGTH) {
// lower than 2^63
return new LongItem(buf);
}
return new BigIntegerItem(buf);
}
return new StringItem(buf, false);
}
private static String stripLeadingZeroes(String buf) {
if (buf == null || buf.isEmpty()) {
return "0";
}
for (int i = 0; i < buf.length(); ++i) {
char c = buf.charAt(i);
if (c != '0') {
return buf.substring(i);
}
}
return buf;
}
@Override
public int hashCode() {
return items.hashCode();
@ -472,16 +472,6 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
this.value = ALIASES.getProperty(value, value);
}
@Override
public int getType() {
return STRING_ITEM;
}
@Override
public boolean isNull() {
return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0);
}
/**
* Returns a comparable value for a qualifier.
*
@ -502,6 +492,16 @@ public class ComparableVersion implements Comparable<ComparableVersion> {
return i == -1 ? (QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i);
}
@Override
public int getType() {
return STRING_ITEM;
}
@Override
public boolean isNull() {
return (comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0);
}
@Override
public int compareTo(Item item) {
if (item == null) {

View File

@ -13,6 +13,10 @@ public final class Pair<L, R> {
this.right = right;
}
public static <L, R> Pair<L, R> of(L left, R right) {
return new Pair<>(left, right);
}
public L getLeft() {
return left;
}
@ -21,10 +25,6 @@ public final class Pair<L, R> {
return right;
}
public static <L, R> Pair<L, R> of(L left, R right) {
return new Pair<>(left, right);
}
@Override
public int hashCode() {
return Objects.hash(left, right);

View File

@ -33,6 +33,26 @@ public class WorkingTimeCalculatorImpl implements WorkingTimeCalculator {
this.zoneId = Objects.requireNonNull(zoneId);
}
private static boolean isBeforeOrEquals(LocalTime time, ZonedDateTime currentDateTime) {
return !time.isAfter(currentDateTime.toLocalTime());
}
private static ZonedDateTime max(ZonedDateTime a, ZonedDateTime b) {
if (a.isAfter(b)) {
return a;
} else {
return b;
}
}
private static ZonedDateTime min(ZonedDateTime a, ZonedDateTime b) {
if (a.isBefore(b)) {
return a;
} else {
return b;
}
}
@Override
public Instant subtractWorkingTime(Instant workStart, Duration workingTime)
throws InvalidArgumentException {
@ -189,10 +209,6 @@ public class WorkingTimeCalculatorImpl implements WorkingTimeCalculator {
getWorkSlotOrPrevious(getDayBefore(currentDateTime)));
}
private static boolean isBeforeOrEquals(LocalTime time, ZonedDateTime currentDateTime) {
return !time.isAfter(currentDateTime.toLocalTime());
}
private ZonedDateTime getDayAfter(ZonedDateTime current) {
return LocalDateTime.of(current.toLocalDate().plusDays(1), LocalTime.MIN)
.atZone(current.getZone());
@ -223,22 +239,6 @@ public class WorkingTimeCalculatorImpl implements WorkingTimeCalculator {
return LocalDate.ofInstant(instant, zoneId);
}
private static ZonedDateTime max(ZonedDateTime a, ZonedDateTime b) {
if (a.isAfter(b)) {
return a;
} else {
return b;
}
}
private static ZonedDateTime min(ZonedDateTime a, ZonedDateTime b) {
if (a.isBefore(b)) {
return a;
} else {
return b;
}
}
class WorkSlot {
private final ZonedDateTime start;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>kadai-loghistory-provider</artifactId>

View File

@ -28,11 +28,6 @@ class LogfileHistoryServiceImplTest {
new LogfileHistoryServiceImpl();
private final TestLogger logger = TestLoggerFactory.getTestLogger("AUDIT");
@AfterEach
public void clearLoggers() {
TestLoggerFactory.clear();
}
@BeforeAll
public static void setupObjectMapper() {
KadaiConfiguration kadaiConfiguration = Mockito.mock(KadaiConfiguration.class);
@ -41,6 +36,11 @@ class LogfileHistoryServiceImplTest {
Mockito.when(kadaiConfiguration.getLogHistoryLoggerName()).thenReturn("AUDIT");
}
@AfterEach
public void clearLoggers() {
TestLoggerFactory.clear();
}
@Test
void should_LogTaskEventAsJson_When_CreateIsCalled() throws Exception {

View File

@ -51,8 +51,7 @@ public class SimpleHistoryServiceImpl implements KadaiHistory {
Field internalKadaiEngineImpl =
KadaiEngineImpl.class.getDeclaredField("internalKadaiEngineImpl");
internalKadaiEngineImpl.setAccessible(true);
this.internalKadaiEngine =
(InternalKadaiEngine) internalKadaiEngineImpl.get(kadaiEngine);
this.internalKadaiEngine = (InternalKadaiEngine) internalKadaiEngineImpl.get(kadaiEngine);
sessionManager = KadaiEngineImpl.class.getDeclaredField("sessionManager");
sessionManager.setAccessible(true);
} catch (NoSuchFieldException e) {

View File

@ -123,38 +123,6 @@ public abstract class AbstractAccTest {
return historyService;
}
protected TaskHistoryQueryMapper getHistoryQueryMapper()
throws NoSuchFieldException, IllegalAccessException {
Field sessionManagerField = KadaiEngineImpl.class.getDeclaredField("sessionManager");
sessionManagerField.setAccessible(true);
SqlSessionManager sqlSessionManager =
(SqlSessionManager) sessionManagerField.get(kadaiEngine);
return sqlSessionManager.getMapper(TaskHistoryQueryMapper.class);
}
protected JobMapper getJobMapper() throws NoSuchFieldException, IllegalAccessException {
Field sessionManagerField = KadaiEngineImpl.class.getDeclaredField("sessionManager");
sessionManagerField.setAccessible(true);
SqlSessionManager sqlSessionManager =
(SqlSessionManager) sessionManagerField.get(kadaiEngine);
return sqlSessionManager.getMapper(JobMapper.class);
}
protected ObjectReference createObjectRef(
String company, String system, String systemInstance, String type, String value) {
ObjectReferenceImpl objectRef = new ObjectReferenceImpl();
objectRef.setCompany(company);
objectRef.setSystem(system);
objectRef.setSystemInstance(systemInstance);
objectRef.setType(type);
objectRef.setValue(value);
return objectRef;
}
protected static WorkbasketHistoryEventMapper getWorkbasketHistoryEventMapper() {
try {
Field sessionManager = KadaiEngineImpl.class.getDeclaredField("sessionManager");
@ -190,4 +158,34 @@ public abstract class AbstractAccTest {
static void setupTest() throws Exception {
resetDb(null);
}
protected TaskHistoryQueryMapper getHistoryQueryMapper()
throws NoSuchFieldException, IllegalAccessException {
Field sessionManagerField = KadaiEngineImpl.class.getDeclaredField("sessionManager");
sessionManagerField.setAccessible(true);
SqlSessionManager sqlSessionManager = (SqlSessionManager) sessionManagerField.get(kadaiEngine);
return sqlSessionManager.getMapper(TaskHistoryQueryMapper.class);
}
protected JobMapper getJobMapper() throws NoSuchFieldException, IllegalAccessException {
Field sessionManagerField = KadaiEngineImpl.class.getDeclaredField("sessionManager");
sessionManagerField.setAccessible(true);
SqlSessionManager sqlSessionManager = (SqlSessionManager) sessionManagerField.get(kadaiEngine);
return sqlSessionManager.getMapper(JobMapper.class);
}
protected ObjectReference createObjectRef(
String company, String system, String systemInstance, String type, String value) {
ObjectReferenceImpl objectRef = new ObjectReferenceImpl();
objectRef.setCompany(company);
objectRef.setSystem(system);
objectRef.setSystemInstance(systemInstance);
objectRef.setType(type);
objectRef.setValue(value);
return objectRef;
}
}

View File

@ -480,8 +480,7 @@ class QueryTaskHistoryAccTest extends AbstractAccTest {
.idIn(taskHistoryEvents.get(0).getTaskId())
.single();
assertThat(task).isNotNull();
String taskOwnerLongName =
kadaiEngine.getUserService().getUser(task.getOwner()).getLongName();
String taskOwnerLongName = kadaiEngine.getUserService().getUser(task.getOwner()).getLongName();
assertThat(taskHistoryEvents.get(0))
.extracting(TaskHistoryEvent::getTaskOwnerLongName)

View File

@ -12,150 +12,6 @@ import java.beans.ConstructorProperties;
import java.time.Instant;
public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHistoryQuery, Void> {
public String[] getEventType() {
return eventType;
}
public String[] getEventTypeLike() {
return eventTypeLike;
}
public String[] getUserId() {
return userId;
}
public String[] getUserIdLike() {
return userIdLike;
}
public Instant[] getCreated() {
return created;
}
public String[] getDomain() {
return domain;
}
public String[] getTaskId() {
return taskId;
}
public String[] getTaskIdLike() {
return taskIdLike;
}
public String[] getBusinessProcessId() {
return businessProcessId;
}
public String[] getBusinessProcessIdLike() {
return businessProcessIdLike;
}
public String[] getParentBusinessProcessId() {
return parentBusinessProcessId;
}
public String[] getParentBusinessProcessIdLike() {
return parentBusinessProcessIdLike;
}
public String[] getTaskClassificationKey() {
return taskClassificationKey;
}
public String[] getTaskClassificationKeyLike() {
return taskClassificationKeyLike;
}
public String[] getTaskClassificationCategory() {
return taskClassificationCategory;
}
public String[] getTaskClassificationCategoryLike() {
return taskClassificationCategoryLike;
}
public String[] getAttachmentClassificationKey() {
return attachmentClassificationKey;
}
public String[] getAttachmentClassificationKeyLike() {
return attachmentClassificationKeyLike;
}
public String[] getWorkbasketKey() {
return workbasketKey;
}
public String[] getWorkbasketKeyLike() {
return workbasketKeyLike;
}
public String[] getPorCompany() {
return porCompany;
}
public String[] getPorCompanyLike() {
return porCompanyLike;
}
public String[] getPorSystem() {
return porSystem;
}
public String[] getPorSystemLike() {
return porSystemLike;
}
public String[] getPorInstance() {
return porInstance;
}
public String[] getPorInstanceLike() {
return porInstanceLike;
}
public String[] getPorValue() {
return porValue;
}
public String[] getPorValueLike() {
return porValueLike;
}
public String[] getCustom1() {
return custom1;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom2() {
return custom2;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom3() {
return custom3;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom4() {
return custom4;
}
public String[] getCustom4Like() {
return custom4Like;
}
@Schema(
name = "event-type",
description = "Filter by the event type of the Task History Event. This is an exact match.")
@ -563,6 +419,150 @@ public class TaskHistoryQueryFilterParameter implements QueryParameter<TaskHisto
validateFilterParameters();
}
public String[] getEventType() {
return eventType;
}
public String[] getEventTypeLike() {
return eventTypeLike;
}
public String[] getUserId() {
return userId;
}
public String[] getUserIdLike() {
return userIdLike;
}
public Instant[] getCreated() {
return created;
}
public String[] getDomain() {
return domain;
}
public String[] getTaskId() {
return taskId;
}
public String[] getTaskIdLike() {
return taskIdLike;
}
public String[] getBusinessProcessId() {
return businessProcessId;
}
public String[] getBusinessProcessIdLike() {
return businessProcessIdLike;
}
public String[] getParentBusinessProcessId() {
return parentBusinessProcessId;
}
public String[] getParentBusinessProcessIdLike() {
return parentBusinessProcessIdLike;
}
public String[] getTaskClassificationKey() {
return taskClassificationKey;
}
public String[] getTaskClassificationKeyLike() {
return taskClassificationKeyLike;
}
public String[] getTaskClassificationCategory() {
return taskClassificationCategory;
}
public String[] getTaskClassificationCategoryLike() {
return taskClassificationCategoryLike;
}
public String[] getAttachmentClassificationKey() {
return attachmentClassificationKey;
}
public String[] getAttachmentClassificationKeyLike() {
return attachmentClassificationKeyLike;
}
public String[] getWorkbasketKey() {
return workbasketKey;
}
public String[] getWorkbasketKeyLike() {
return workbasketKeyLike;
}
public String[] getPorCompany() {
return porCompany;
}
public String[] getPorCompanyLike() {
return porCompanyLike;
}
public String[] getPorSystem() {
return porSystem;
}
public String[] getPorSystemLike() {
return porSystemLike;
}
public String[] getPorInstance() {
return porInstance;
}
public String[] getPorInstanceLike() {
return porInstanceLike;
}
public String[] getPorValue() {
return porValue;
}
public String[] getPorValueLike() {
return porValueLike;
}
public String[] getCustom1() {
return custom1;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom2() {
return custom2;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom3() {
return custom3;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom4() {
return custom4;
}
public String[] getCustom4Like() {
return custom4Like;
}
@Override
public Void apply(TaskHistoryQuery query) {
ofNullable(eventType).ifPresent(query::eventTypeIn);

View File

@ -12,18 +12,23 @@ public class TaskHistoryEventRepresentationModel
/** Unique Id. */
@Schema(name = "taskHistoryId", description = "Unique Id.")
private String taskHistoryId;
/** The Id of the business process. */
@Schema(name = "businessProcessId", description = "The Id of the business process.")
private String businessProcessId;
/** The Id of the parent business process. */
@Schema(name = "parentBusinessProcessId", description = "The Id of the parent business process.")
private String parentBusinessProcessId;
/** The Id of the task. */
@Schema(name = "taskId", description = "The Id of the task.")
private String taskId;
/** The type of the event. */
@Schema(name = "eventType", description = "The type of the event.")
private String eventType;
/**
* The time of event creation.
*
@ -31,29 +36,36 @@ public class TaskHistoryEventRepresentationModel
*/
@Schema(name = "created", description = "The time of event creation.<p>The format is ISO-8601.")
private Instant created;
/** The Id of the user. */
@Schema(name = "userId", description = "The Id of the user.")
private String userId;
/** The long name of the user. */
@Schema(name = "userLongName", description = "The long name of the user.")
private String userLongName;
/** Domain. */
@Schema(name = "domain", description = "Domain.")
private String domain;
/** The key of the Workbasket. */
@Schema(name = "workbasketKey", description = "The key of the Workbasket.")
private String workbasketKey;
/** The company the referenced primary object belongs to. */
@Schema(
name = "porCompany",
description = "The company the referenced primary object belongs to.")
private String porCompany;
/** The type of the referenced primary object (contract, claim, policy, customer, ...). */
@Schema(
name = "porType",
description =
"The type of the referenced primary object (contract, claim, policy, customer, ...).")
private String porType;
/** The (kind of) system, the referenced primary object resides in (e.g. SAP, MySystem A, ...). */
@Schema(
name = "porSystem",
@ -61,48 +73,61 @@ public class TaskHistoryEventRepresentationModel
"The (kind of) system, the referenced primary object resides in (e.g. SAP, MySystem A, "
+ "...).")
private String porSystem;
/** The instance of the system where the referenced primary object is located. */
@Schema(
name = "porInstance",
description = "The instance of the system where the referenced primary object is located.")
private String porInstance;
/** The value of the primary object reference. */
@Schema(name = "porValue", description = "The value of the primary object reference.")
private String porValue;
/** The long name of the task owner. */
@Schema(name = "taskOwnerLongName", description = "The long name of the task owner.")
private String taskOwnerLongName;
/** The key of the task's classification. */
@Schema(name = "taskClassificationKey", description = "The key of the task's classification.")
private String taskClassificationKey;
/** The category of the task's classification. */
@Schema(
name = "taskClassificationCategory",
description = "The category of the task's classification.")
private String taskClassificationCategory;
/** The classification key of the task's attachment. */
@Schema(
name = "attachmentClassificationKey",
description = "The classification key of the task's attachment.")
private String attachmentClassificationKey;
/** The old value. */
@Schema(name = "oldValue", description = "The old value.")
private String oldValue;
/** The new value. */
@Schema(name = "newValue", description = "The new value.")
private String newValue;
/** A custom property with name "1". */
@Schema(name = "custom1", description = "A custom property with name '1'.")
private String custom1;
/** A custom property with name "2". */
@Schema(name = "custom2", description = "A custom property with name '2'.")
private String custom2;
/** A custom property with name "3". */
@Schema(name = "custom3", description = "A custom property with name '3'.")
private String custom3;
/** A custom property with name "4". */
@Schema(name = "custom4", description = "A custom property with name '4'.")
private String custom4;
/** details of changes within the task. */
@Schema(name = "details", description = "details of changes within the task.")
private String details;

View File

@ -1,3 +1,3 @@
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://jakarta.ee/xml/ns/jakartaee"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd">
</beans>

View File

@ -1,5 +1,5 @@
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 6.0"/>

View File

@ -31,12 +31,10 @@ public class KadaiProducers {
private static final Logger LOGGER = LoggerFactory.getLogger(KadaiProducers.class);
private static final String KADAI_PROPERTIES = "kadai.properties";
private final KadaiEngine kadaiEngine;
// initalized during post construct
private KadaiConfiguration kadaiConfiguration;
private final KadaiEngine kadaiEngine;
public KadaiProducers() {
this.kadaiEngine = null;
}

View File

@ -1,3 +1,3 @@
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://jakarta.ee/xml/ns/jakartaee"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd">
</beans>

View File

@ -1,5 +1,5 @@
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 6.0"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web version="7.2"
<jboss-web xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="7.2"
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_7_2.xsd">
<context-root>/kadai</context-root>
</jboss-web>

View File

@ -103,389 +103,6 @@ class ArchitectureTest {
// region Coding Guidelines
@Test
void testMethodNamesShouldMatchAccordingToOurGuidelines() {
methods()
.that(
are(
annotatedWith(Test.class)
.or(annotatedWith(ParameterizedTest.class))
.or(annotatedWith(TestFactory.class))
.or(annotatedWith(TestTemplate.class))))
.and()
.areNotDeclaredIn(ArchitectureTest.class)
.and()
.areNotDeclaredIn(PojoTest.class) // we have to find a proper naming for those tests
.should()
.bePackagePrivate()
.andShould()
.haveNameMatching("^should_[A-Z][^_]+(_(For|When)_[A-Z][^_]+)?$")
.check(importedClasses);
}
@Test
void classesShouldNotUseJunit5Assertions() {
classes()
.that()
.areNotAssignableFrom(ArchitectureTest.class)
.should()
.onlyDependOnClassesThat()
.areNotAssignableTo(org.junit.jupiter.api.Assertions.class)
.because("we consistently want to use assertj in our tests")
.check(importedClasses);
}
@Test
void mapperClassesShouldNotUseCurrentTimestampSqlFunction() {
classes()
.that()
.haveSimpleNameEndingWith("Mapper")
.should(notUseCurrentTimestampSqlFunction())
.check(importedClasses);
}
@Test
void kadaiIntegrationTestsShouldOnlyHavePackagePrivateFields() {
classes()
.that()
.areAnnotatedWith(KadaiIntegrationTest.class)
.or(areNestedKadaiIntegrationTestClasses())
.should(onlyHaveFieldsWithNoModifierAndPrivateConstants())
.check(importedClasses);
}
@Test
void nestedKadaiIntegrationTestsShouldBeAnnotatedWithTestInstance() {
classes()
.that(areNestedKadaiIntegrationTestClasses())
.should(beAnnotatedWithTestInstancePerClass())
.check(importedClasses);
}
@Test
void noClassShouldThrowGenericException() {
noClasses().should(THROW_GENERIC_EXCEPTIONS).check(importedClasses);
}
@Test
void noClassShouldAccessStandardStreams() {
noClasses().should(ACCESS_STANDARD_STREAMS).check(importedClasses);
}
@Test
void utilityClassesShouldNotBeInitializable() {
classes()
.that()
.resideInAPackage("..util..")
.and()
.areNotNestedClasses()
.should()
.haveOnlyPrivateConstructors()
.check(importedClasses);
}
@Test
void noClassesShouldUseFieldInjection() {
noFields()
.should(BE_ANNOTATED_WITH_AN_INJECTION_ANNOTATION)
.as("no classes should use field injection")
.because(
"field injection is considered harmful; use constructor injection or setter"
+ " injection instead; see https://stackoverflow.com/q/39890849 for"
+ " detailed explanations")
.check(importedClasses);
}
@Test
void noClassesShouldUseJavaUtilLogging() {
noClasses().should(USE_JAVA_UTIL_LOGGING).check(importedClasses);
}
@Test
void noClassesShouldUseJodatime() {
noClasses()
.should(USE_JODATIME)
.because("modern Java projects use the [java.time] API instead")
.check(importedClasses);
}
// endregion
// region Dependencies
@Test
void apiClassesShouldNotDependOnInternalClasses() {
classes()
.that()
.resideInAPackage("..api..")
.and()
.areNotAssignableFrom(KadaiEngine.class)
.and()
.areNotAssignableTo(Interval.class)
.should()
.onlyDependOnClassesThat(
resideOutsideOfPackage("..io.kadai..internal..").or(assignableTo(LoggingAspect.class)))
.check(importedClasses);
}
@Test
@Disabled("this has way too many false positives during regular development without refactoring")
void packagesShouldBeFreeOfCyclicDependencies() {
// Frozen, so it can be improved over time:
// https://www.archunit.org/userguide/html/000_Index.html#_freezing_arch_rules
freeze(slices().matching("io.kadai.(**)").should().beFreeOfCycles()).check(importedClasses);
}
@Test
@Disabled("this has way too many false positives during regular development without refactoring")
void classesShouldBeFreeOfCyclicDependencies() {
SliceAssignment everySingleClass =
new SliceAssignment() {
// this will specify which classes belong together in the same slice
@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
return SliceIdentifier.of(javaClass.getFullName());
}
// this will be part of the rule description if the test fails
@Override
public String getDescription() {
return "every single class";
}
};
freeze(slices().assignedFrom(everySingleClass).should().beFreeOfCycles())
.check(importedClasses);
}
@Test
void moduleTaskShouldOnlyDependOn() {
// FIXME should not depend on spi
moduleShouldOnlyDependOn("task", List.of("workbasket", "classification", "common", "spi"));
}
@Test
void moduleClassificationShouldOnlyDependOn() {
moduleShouldOnlyDependOn("workbasket", List.of("common"));
}
@Test
void moduleWorkbasketShouldOnlyDependOn() {
moduleShouldOnlyDependOn("workbasket", List.of("common"));
}
@Test
@Disabled("Test is failing for an unknown reason")
void moduleMonitorShouldOnlyDependOn() {
// FIXME fails for some unknown reason...
moduleShouldOnlyDependOn("monitor", List.of("common", "classification", "task", "workbasket"));
}
@Test
void moduleUserShouldOnlyDependOn() {
moduleShouldOnlyDependOn("user", List.of("common"));
}
@Test
void moduleSpiShouldOnlyDependOn() {
// FIXME should not depend on task, classification and workbasket
moduleShouldOnlyDependOn("spi", List.of("common", "task", "classification", "workbasket"));
}
@TestFactory
Stream<DynamicTest> rootModulesShouldExist() {
Function<String, String> descriptionProvider = p -> String.format("Package '%s' exists", p);
ThrowingConsumer<String> testProvider =
p -> assertThat(importedClasses.containPackage(p)).isTrue();
return DynamicTest.stream(KADAI_ROOT_PACKAGES.stream(), descriptionProvider, testProvider);
}
@Test
@Disabled("Needs to be replaced")
void allClassesAreInsideApiOrInternal() {
classes()
.that()
.resideOutsideOfPackages("acceptance..", "testapi..", "..test..")
.should()
.resideInAnyPackage("..api..", "..internal..")
.check(importedClasses);
}
@TestFactory
Stream<DynamicTest> commonClassesShouldNotDependOnOtherPackages() {
Stream<String> input = KADAI_ROOT_PACKAGES.stream().filter(not("io.kadai.common"::equals));
Function<String, String> descriptionProvider =
p -> String.format("Common classes of %s should not depend on domain classes", p);
ThrowingConsumer<String> testDefinitionProvider =
rootPackage ->
classes()
.that()
.resideInAPackage("..common..")
.and()
.areNotAssignableTo(KadaiEngine.class)
.and()
.areNotAssignableTo(InternalKadaiEngine.class)
.and()
.areNotAssignableTo(JobScheduler.class)
.should()
.onlyDependOnClassesThat()
.resideOutsideOfPackage(rootPackage + "..")
.check(importedClasses);
return DynamicTest.stream(input, descriptionProvider, testDefinitionProvider);
}
@Test
void classesShouldNotDependOnMonitorDomainClasses() {
noClasses()
.that()
.resideInAPackage("io.kadai..")
.and()
.areNotAssignableTo(KadaiEngine.class)
.and()
.resideOutsideOfPackages("..monitor..", "io.kadai.testapi..")
.should()
.dependOnClassesThat()
.resideInAPackage("..monitor..")
.check(importedClasses);
}
// endregion
// region Structure
@Test
void exceptionsShouldNotImplementToStringMethod() {
classes()
.that()
.areAssignableTo(KadaiException.class)
.or()
.areAssignableTo(KadaiRuntimeException.class)
.and()
.doNotBelongToAnyOf(KadaiRuntimeException.class, KadaiException.class)
.should(notImplementToString())
.check(importedClasses);
}
@Test
void rootExceptionsShouldImplementToStringMethod() {
classes()
.that()
.areAssignableFrom(KadaiRuntimeException.class)
.or()
.areAssignableFrom(KadaiException.class)
.should(implementToString())
.check(importedClasses);
}
@Test
void exceptionsShouldBePlacedInExceptionPackage() {
classes()
.that()
.areAssignableTo(Throwable.class)
.should()
.resideInAPackage("..exceptions")
.check(importedClasses);
}
@Test
void exceptionsPackageShouldOnlyContainExceptions() {
classes()
.that()
.resideInAPackage("..exceptions..")
.and()
.doNotBelongToAnyOf(ErrorCode.class)
.should()
.beAssignableTo(Throwable.class)
.check(importedClasses);
}
@Test
void exceptionsShouldHaveSuffixException() {
classes()
.that()
.areAssignableTo(Throwable.class)
.should()
.haveSimpleNameEndingWith("Exception")
.check(importedClasses);
}
@Test
void exceptionsShouldInheritFromKadaiRootExceptions() {
classes()
.that()
.areAssignableTo(Throwable.class)
.should()
.beAssignableTo(
assignableTo(KadaiException.class).or(assignableTo(KadaiRuntimeException.class)))
.check(importedClasses);
}
@Test
void exceptionsShouldBePublic() {
classes().that().areAssignableTo(Throwable.class).should().bePublic().check(importedClasses);
}
@Test
void classesShouldNotUseWorkingDaysToDaysConverter() {
classes()
.that()
.areNotAssignableFrom(ArchitectureTest.class)
.and()
.areNotAssignableTo(WorkingTimeCalculator.class)
.and()
.areNotAssignableTo(KadaiEngineImpl.class)
.and()
.haveSimpleNameNotEndingWith("Test")
.should()
.onlyDependOnClassesThat()
.areNotAssignableTo(HolidaySchedule.class)
.because(
"we want to enforce the usage of the WorkingTimeCalculator"
+ " instead of the WorkingDaysToDaysConverter")
.check(importedClasses);
}
// endregion
// region Helper Methods
/**
* Test the dependencies of the packages. Adds the prefix <code>io.kadai</code> to every given
* value.
*
* @param module the module which should be tested
* @param dependentModules the expected dependent modules
*/
private void moduleShouldOnlyDependOn(String module, List<String> dependentModules) {
String moduleTemplate = "io.kadai.%s..";
String moduleUndertest = String.format(moduleTemplate, module);
List<String> dependentModulesList =
dependentModules.stream()
.map(dp -> String.format(moduleTemplate, dp))
.collect(toCollection(ArrayList::new));
dependentModulesList.addAll(List.of("java..", "org.."));
dependentModulesList.add(moduleUndertest);
classes()
.that()
.resideInAPackage(moduleUndertest)
.should()
.onlyAccessClassesThat()
.resideInAnyPackage(dependentModulesList.toArray(new String[0]))
.orShould()
.dependOnClassesThat()
.areAssignableTo(KadaiConfiguration.class)
.check(importedClasses);
}
private static ArchCondition<JavaClass> implementToString() {
return new ArchCondition<>("implement toString()") {
@Override
@ -667,5 +284,388 @@ class ArchitectureTest {
return clazz.getMethod(methodName).invoke(null).toString();
}
@Test
void testMethodNamesShouldMatchAccordingToOurGuidelines() {
methods()
.that(
are(
annotatedWith(Test.class)
.or(annotatedWith(ParameterizedTest.class))
.or(annotatedWith(TestFactory.class))
.or(annotatedWith(TestTemplate.class))))
.and()
.areNotDeclaredIn(ArchitectureTest.class)
.and()
.areNotDeclaredIn(PojoTest.class) // we have to find a proper naming for those tests
.should()
.bePackagePrivate()
.andShould()
.haveNameMatching("^should_[A-Z][^_]+(_(For|When)_[A-Z][^_]+)?$")
.check(importedClasses);
}
@Test
void classesShouldNotUseJunit5Assertions() {
classes()
.that()
.areNotAssignableFrom(ArchitectureTest.class)
.should()
.onlyDependOnClassesThat()
.areNotAssignableTo(org.junit.jupiter.api.Assertions.class)
.because("we consistently want to use assertj in our tests")
.check(importedClasses);
}
@Test
void mapperClassesShouldNotUseCurrentTimestampSqlFunction() {
classes()
.that()
.haveSimpleNameEndingWith("Mapper")
.should(notUseCurrentTimestampSqlFunction())
.check(importedClasses);
}
@Test
void kadaiIntegrationTestsShouldOnlyHavePackagePrivateFields() {
classes()
.that()
.areAnnotatedWith(KadaiIntegrationTest.class)
.or(areNestedKadaiIntegrationTestClasses())
.should(onlyHaveFieldsWithNoModifierAndPrivateConstants())
.check(importedClasses);
}
// endregion
@Test
void nestedKadaiIntegrationTestsShouldBeAnnotatedWithTestInstance() {
classes()
.that(areNestedKadaiIntegrationTestClasses())
.should(beAnnotatedWithTestInstancePerClass())
.check(importedClasses);
}
@Test
void noClassShouldThrowGenericException() {
noClasses().should(THROW_GENERIC_EXCEPTIONS).check(importedClasses);
}
@Test
void noClassShouldAccessStandardStreams() {
noClasses().should(ACCESS_STANDARD_STREAMS).check(importedClasses);
}
@Test
void utilityClassesShouldNotBeInitializable() {
classes()
.that()
.resideInAPackage("..util..")
.and()
.areNotNestedClasses()
.should()
.haveOnlyPrivateConstructors()
.check(importedClasses);
}
@Test
void noClassesShouldUseFieldInjection() {
noFields()
.should(BE_ANNOTATED_WITH_AN_INJECTION_ANNOTATION)
.as("no classes should use field injection")
.because(
"field injection is considered harmful; use constructor injection or setter"
+ " injection instead; see https://stackoverflow.com/q/39890849 for"
+ " detailed explanations")
.check(importedClasses);
}
@Test
void noClassesShouldUseJavaUtilLogging() {
noClasses().should(USE_JAVA_UTIL_LOGGING).check(importedClasses);
}
@Test
void noClassesShouldUseJodatime() {
noClasses()
.should(USE_JODATIME)
.because("modern Java projects use the [java.time] API instead")
.check(importedClasses);
}
// region Dependencies
@Test
void apiClassesShouldNotDependOnInternalClasses() {
classes()
.that()
.resideInAPackage("..api..")
.and()
.areNotAssignableFrom(KadaiEngine.class)
.and()
.areNotAssignableTo(Interval.class)
.should()
.onlyDependOnClassesThat(
resideOutsideOfPackage("..io.kadai..internal..").or(assignableTo(LoggingAspect.class)))
.check(importedClasses);
}
@Test
@Disabled("this has way too many false positives during regular development without refactoring")
void packagesShouldBeFreeOfCyclicDependencies() {
// Frozen, so it can be improved over time:
// https://www.archunit.org/userguide/html/000_Index.html#_freezing_arch_rules
freeze(slices().matching("io.kadai.(**)").should().beFreeOfCycles()).check(importedClasses);
}
@Test
@Disabled("this has way too many false positives during regular development without refactoring")
void classesShouldBeFreeOfCyclicDependencies() {
SliceAssignment everySingleClass =
new SliceAssignment() {
// this will specify which classes belong together in the same slice
@Override
public SliceIdentifier getIdentifierOf(JavaClass javaClass) {
return SliceIdentifier.of(javaClass.getFullName());
}
// this will be part of the rule description if the test fails
@Override
public String getDescription() {
return "every single class";
}
};
freeze(slices().assignedFrom(everySingleClass).should().beFreeOfCycles())
.check(importedClasses);
}
@Test
void moduleTaskShouldOnlyDependOn() {
// FIXME should not depend on spi
moduleShouldOnlyDependOn("task", List.of("workbasket", "classification", "common", "spi"));
}
@Test
void moduleClassificationShouldOnlyDependOn() {
moduleShouldOnlyDependOn("workbasket", List.of("common"));
}
@Test
void moduleWorkbasketShouldOnlyDependOn() {
moduleShouldOnlyDependOn("workbasket", List.of("common"));
}
// endregion
// region Structure
@Test
@Disabled("Test is failing for an unknown reason")
void moduleMonitorShouldOnlyDependOn() {
// FIXME fails for some unknown reason...
moduleShouldOnlyDependOn("monitor", List.of("common", "classification", "task", "workbasket"));
}
@Test
void moduleUserShouldOnlyDependOn() {
moduleShouldOnlyDependOn("user", List.of("common"));
}
@Test
void moduleSpiShouldOnlyDependOn() {
// FIXME should not depend on task, classification and workbasket
moduleShouldOnlyDependOn("spi", List.of("common", "task", "classification", "workbasket"));
}
@TestFactory
Stream<DynamicTest> rootModulesShouldExist() {
Function<String, String> descriptionProvider = p -> String.format("Package '%s' exists", p);
ThrowingConsumer<String> testProvider =
p -> assertThat(importedClasses.containPackage(p)).isTrue();
return DynamicTest.stream(KADAI_ROOT_PACKAGES.stream(), descriptionProvider, testProvider);
}
@Test
@Disabled("Needs to be replaced")
void allClassesAreInsideApiOrInternal() {
classes()
.that()
.resideOutsideOfPackages("acceptance..", "testapi..", "..test..")
.should()
.resideInAnyPackage("..api..", "..internal..")
.check(importedClasses);
}
@TestFactory
Stream<DynamicTest> commonClassesShouldNotDependOnOtherPackages() {
Stream<String> input = KADAI_ROOT_PACKAGES.stream().filter(not("io.kadai.common"::equals));
Function<String, String> descriptionProvider =
p -> String.format("Common classes of %s should not depend on domain classes", p);
ThrowingConsumer<String> testDefinitionProvider =
rootPackage ->
classes()
.that()
.resideInAPackage("..common..")
.and()
.areNotAssignableTo(KadaiEngine.class)
.and()
.areNotAssignableTo(InternalKadaiEngine.class)
.and()
.areNotAssignableTo(JobScheduler.class)
.should()
.onlyDependOnClassesThat()
.resideOutsideOfPackage(rootPackage + "..")
.check(importedClasses);
return DynamicTest.stream(input, descriptionProvider, testDefinitionProvider);
}
@Test
void classesShouldNotDependOnMonitorDomainClasses() {
noClasses()
.that()
.resideInAPackage("io.kadai..")
.and()
.areNotAssignableTo(KadaiEngine.class)
.and()
.resideOutsideOfPackages("..monitor..", "io.kadai.testapi..")
.should()
.dependOnClassesThat()
.resideInAPackage("..monitor..")
.check(importedClasses);
}
@Test
void exceptionsShouldNotImplementToStringMethod() {
classes()
.that()
.areAssignableTo(KadaiException.class)
.or()
.areAssignableTo(KadaiRuntimeException.class)
.and()
.doNotBelongToAnyOf(KadaiRuntimeException.class, KadaiException.class)
.should(notImplementToString())
.check(importedClasses);
}
// endregion
// region Helper Methods
@Test
void rootExceptionsShouldImplementToStringMethod() {
classes()
.that()
.areAssignableFrom(KadaiRuntimeException.class)
.or()
.areAssignableFrom(KadaiException.class)
.should(implementToString())
.check(importedClasses);
}
@Test
void exceptionsShouldBePlacedInExceptionPackage() {
classes()
.that()
.areAssignableTo(Throwable.class)
.should()
.resideInAPackage("..exceptions")
.check(importedClasses);
}
@Test
void exceptionsPackageShouldOnlyContainExceptions() {
classes()
.that()
.resideInAPackage("..exceptions..")
.and()
.doNotBelongToAnyOf(ErrorCode.class)
.should()
.beAssignableTo(Throwable.class)
.check(importedClasses);
}
@Test
void exceptionsShouldHaveSuffixException() {
classes()
.that()
.areAssignableTo(Throwable.class)
.should()
.haveSimpleNameEndingWith("Exception")
.check(importedClasses);
}
@Test
void exceptionsShouldInheritFromKadaiRootExceptions() {
classes()
.that()
.areAssignableTo(Throwable.class)
.should()
.beAssignableTo(
assignableTo(KadaiException.class).or(assignableTo(KadaiRuntimeException.class)))
.check(importedClasses);
}
@Test
void exceptionsShouldBePublic() {
classes().that().areAssignableTo(Throwable.class).should().bePublic().check(importedClasses);
}
@Test
void classesShouldNotUseWorkingDaysToDaysConverter() {
classes()
.that()
.areNotAssignableFrom(ArchitectureTest.class)
.and()
.areNotAssignableTo(WorkingTimeCalculator.class)
.and()
.areNotAssignableTo(KadaiEngineImpl.class)
.and()
.haveSimpleNameNotEndingWith("Test")
.should()
.onlyDependOnClassesThat()
.areNotAssignableTo(HolidaySchedule.class)
.because(
"we want to enforce the usage of the WorkingTimeCalculator"
+ " instead of the WorkingDaysToDaysConverter")
.check(importedClasses);
}
/**
* Test the dependencies of the packages. Adds the prefix <code>io.kadai</code> to every given
* value.
*
* @param module the module which should be tested
* @param dependentModules the expected dependent modules
*/
private void moduleShouldOnlyDependOn(String module, List<String> dependentModules) {
String moduleTemplate = "io.kadai.%s..";
String moduleUndertest = String.format(moduleTemplate, module);
List<String> dependentModulesList =
dependentModules.stream()
.map(dp -> String.format(moduleTemplate, dp))
.collect(toCollection(ArrayList::new));
dependentModulesList.addAll(List.of("java..", "org.."));
dependentModulesList.add(moduleUndertest);
classes()
.that()
.resideInAPackage(moduleUndertest)
.should()
.onlyAccessClassesThat()
.resideInAnyPackage(dependentModulesList.toArray(new String[0]))
.orShould()
.dependOnClassesThat()
.areAssignableTo(KadaiConfiguration.class)
.check(importedClasses);
}
// endregion
}

View File

@ -29,6 +29,25 @@ class PojoTest {
private static final List<Class<?>> POJO_CLASSES = getPojoClasses();
private static List<Class<?>> getPojoClasses() {
// TODO how to identify pojos? Is overwritten equals method enough?
return new ClassFileImporter()
.importPackages("io.kadai").stream()
.filter(javaClass -> javaClass.tryGetMethod("equals", Object.class).isPresent())
.filter(
javaClass ->
!javaClass.getSimpleName().equals("TaskHistoryEvent")
&& !javaClass.getSimpleName().equals("WorkbasketHistoryEvent")
&& !javaClass.getSimpleName().equals("ClassificationHistoryEvent")
&& !javaClass.getSimpleName().equals("ComparableVersion")
&& !javaClass.getSimpleName().equals("StringItem")
&& !javaClass.getSimpleName().equals("BigIntegerItem")
&& !javaClass.getSimpleName().equals("IntItem")
&& !javaClass.getSimpleName().equals("LongItem"))
.map(JavaClass::reflect)
.collect(Collectors.toList());
}
@Test
void testsThatPojoClassesAreFound() {
assertThat(POJO_CLASSES).isNotEmpty();
@ -109,23 +128,4 @@ class PojoTest {
.withRedefinedSuperclass()
.verify();
}
private static List<Class<?>> getPojoClasses() {
// TODO how to identify pojos? Is overwritten equals method enough?
return new ClassFileImporter()
.importPackages("io.kadai").stream()
.filter(javaClass -> javaClass.tryGetMethod("equals", Object.class).isPresent())
.filter(
javaClass ->
!javaClass.getSimpleName().equals("TaskHistoryEvent")
&& !javaClass.getSimpleName().equals("WorkbasketHistoryEvent")
&& !javaClass.getSimpleName().equals("ClassificationHistoryEvent")
&& !javaClass.getSimpleName().equals("ComparableVersion")
&& !javaClass.getSimpleName().equals("StringItem")
&& !javaClass.getSimpleName().equals("BigIntegerItem")
&& !javaClass.getSimpleName().equals("IntItem")
&& !javaClass.getSimpleName().equals("LongItem"))
.map(JavaClass::reflect)
.collect(Collectors.toList());
}
}

View File

@ -82,32 +82,6 @@ class AbstractKadaiJobAccTest {
assertThat(jobsToRun).extracting(ScheduledJob::getDue).containsExactly(firstDue.plus(runEvery));
}
@Nested
@TestInstance(Lifecycle.PER_CLASS)
class CleanCompletedTasks implements KadaiConfigurationModifier {
@KadaiInject KadaiEngine kadaiEngine;
@KadaiInject JobMapper jobMapper;
@Override
public Builder modify(Builder builder) {
return builder
.taskCleanupJobEnabled(true)
.jobRunEvery(Duration.ofMillis(1))
.jobFirstRun(Instant.now().plus(5, ChronoUnit.MINUTES));
}
@WithAccessId(user = "admin")
@Test
void should_FindNoJobsToRunUntilFirstRunIsReached_When_CleanupScheduleIsInitialized()
throws Exception {
AbstractKadaiJob.initializeSchedule(kadaiEngine, TaskCleanupJob.class);
List<ScheduledJob> nextJobs = jobMapper.findJobsToRun(Instant.now());
assertThat(nextJobs).isEmpty();
}
}
@WithAccessId(user = "admin")
@TestFactory
Stream<DynamicTest> should_DeleteOldCleanupJobs_When_InitializingSchedule() throws Exception {
@ -184,4 +158,30 @@ class AbstractKadaiJobAccTest {
@Override
protected void execute() throws KadaiException {}
}
@Nested
@TestInstance(Lifecycle.PER_CLASS)
class CleanCompletedTasks implements KadaiConfigurationModifier {
@KadaiInject KadaiEngine kadaiEngine;
@KadaiInject JobMapper jobMapper;
@Override
public Builder modify(Builder builder) {
return builder
.taskCleanupJobEnabled(true)
.jobRunEvery(Duration.ofMillis(1))
.jobFirstRun(Instant.now().plus(5, ChronoUnit.MINUTES));
}
@WithAccessId(user = "admin")
@Test
void should_FindNoJobsToRunUntilFirstRunIsReached_When_CleanupScheduleIsInitialized()
throws Exception {
AbstractKadaiJob.initializeSchedule(kadaiEngine, TaskCleanupJob.class);
List<ScheduledJob> nextJobs = jobMapper.findJobsToRun(Instant.now());
assertThat(nextJobs).isEmpty();
}
}
}

View File

@ -999,6 +999,18 @@ public class KadaiConfiguration {
this.properties = conf.properties;
}
private static Map<DayOfWeek, Set<LocalTimeInterval>> initDefaultWorkingTimeSchedule() {
Map<DayOfWeek, Set<LocalTimeInterval>> workingTime = new EnumMap<>(DayOfWeek.class);
Set<LocalTimeInterval> standardWorkingSlots =
Set.of(new LocalTimeInterval(LocalTime.MIN, LocalTime.MAX));
workingTime.put(DayOfWeek.MONDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.TUESDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.WEDNESDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.THURSDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.FRIDAY, standardWorkingSlots);
return workingTime;
}
/**
* Configure the {@linkplain KadaiConfiguration} with the default {@linkplain
* #DEFAULT_KADAI_PROPERTIES property file location} and {@linkplain
@ -1022,6 +1034,10 @@ public class KadaiConfiguration {
return initKadaiProperties(propertiesFile, DEFAULT_KADAI_PROPERTY_SEPARATOR);
}
// region builder methods
// region general configuration
/**
* Configure the {@linkplain KadaiConfiguration} using a property file from the classpath of
* {@linkplain KadaiConfiguration KadaiConfigurations} or the system.
@ -1051,15 +1067,15 @@ public class KadaiConfiguration {
return this;
}
// region builder methods
// region general configuration
public Builder domains(List<String> domains) {
this.domains = domains;
return this;
}
// endregion
// region authentication configuration
public Builder enforceServiceLevel(boolean enforceServiceLevel) {
this.enforceServiceLevel = enforceServiceLevel;
return this;
@ -1067,32 +1083,28 @@ public class KadaiConfiguration {
// endregion
// region authentication configuration
// region classification configuration
public Builder roleMap(Map<KadaiRole, Set<String>> roleMap) {
this.roleMap = roleMap;
return this;
}
// endregion
// region classification configuration
public Builder classificationTypes(List<String> classificationTypes) {
this.classificationTypes = classificationTypes;
return this;
}
public Builder classificationCategoriesByType(
Map<String, List<String>> classificationCategoriesByType) {
this.classificationCategoriesByType = classificationCategoriesByType;
return this;
}
// endregion
// region working time configuration
public Builder classificationCategoriesByType(
Map<String, List<String>> classificationCategoriesByType) {
this.classificationCategoriesByType = classificationCategoriesByType;
return this;
}
public Builder useWorkingTimeCalculation(boolean useWorkingTimeCalculation) {
this.useWorkingTimeCalculation = useWorkingTimeCalculation;
return this;
@ -1118,31 +1130,31 @@ public class KadaiConfiguration {
return this;
}
// endregion
// region history configuration
public Builder germanPublicHolidaysCorpusChristiEnabled(
boolean germanPublicHolidaysCorpusChristiEnabled) {
this.germanPublicHolidaysCorpusChristiEnabled = germanPublicHolidaysCorpusChristiEnabled;
return this;
}
// endregion
// region history configuration
public Builder deleteHistoryEventsOnTaskDeletionEnabled(
boolean deleteHistoryEventsOnTaskDeletionEnabled) {
this.deleteHistoryEventsOnTaskDeletionEnabled = deleteHistoryEventsOnTaskDeletionEnabled;
return this;
}
// endregion
// region job configuration
public Builder logHistoryLoggerName(String loggerName) {
this.logHistoryLoggerName = loggerName;
return this;
}
// endregion
// region job configuration
public Builder jobSchedulerEnabled(boolean jobSchedulerEnabled) {
this.jobSchedulerEnabled = jobSchedulerEnabled;
return this;
@ -1296,15 +1308,15 @@ public class KadaiConfiguration {
return this;
}
// endregion
// region user configuration
public Builder customJobs(Set<String> customJobs) {
this.customJobs = customJobs;
return this;
}
// endregion
// region user configuration
public Builder addAdditionalUserInfo(boolean addAdditionalUserInfo) {
this.addAdditionalUserInfo = addAdditionalUserInfo;
return this;
@ -1323,14 +1335,14 @@ public class KadaiConfiguration {
return this;
}
// endregion
public KadaiConfiguration build() {
adjustConfiguration();
validateConfiguration();
return new KadaiConfiguration(this);
}
// endregion
private void addMasterDomain() {
// Master Domain is treat as empty string
// it must be always added to the configuration
@ -1502,17 +1514,5 @@ public class KadaiConfiguration {
Collectors.toUnmodifiableMap(
e -> e.getKey().toString(), e -> e.getValue().toString()));
}
private static Map<DayOfWeek, Set<LocalTimeInterval>> initDefaultWorkingTimeSchedule() {
Map<DayOfWeek, Set<LocalTimeInterval>> workingTime = new EnumMap<>(DayOfWeek.class);
Set<LocalTimeInterval> standardWorkingSlots =
Set.of(new LocalTimeInterval(LocalTime.MIN, LocalTime.MAX));
workingTime.put(DayOfWeek.MONDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.TUESDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.WEDNESDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.THURSDAY, standardWorkingSlots);
workingTime.put(DayOfWeek.FRIDAY, standardWorkingSlots);
return workingTime;
}
}
}

View File

@ -64,6 +64,24 @@ public class ClassificationServiceImpl implements ClassificationService {
this.historyEventManager = kadaiEngine.getHistoryEventManager();
}
private static void validateServiceLevel(Classification classification)
throws MalformedServiceLevelException {
String serviceLevel = classification.getServiceLevel();
Duration duration;
try {
duration = Duration.parse(serviceLevel);
} catch (Exception e) {
throw new MalformedServiceLevelException(
serviceLevel, classification.getKey(), classification.getDomain());
}
if (duration.isNegative()) {
throw new MalformedServiceLevelException(
serviceLevel, classification.getKey(), classification.getDomain());
}
}
@Override
public Classification getClassification(String key, String domain)
throws ClassificationNotFoundException {
@ -309,24 +327,6 @@ public class ClassificationServiceImpl implements ClassificationService {
return classification;
}
private static void validateServiceLevel(Classification classification)
throws MalformedServiceLevelException {
String serviceLevel = classification.getServiceLevel();
Duration duration;
try {
duration = Duration.parse(serviceLevel);
} catch (Exception e) {
throw new MalformedServiceLevelException(
serviceLevel, classification.getKey(), classification.getDomain());
}
if (duration.isNegative()) {
throw new MalformedServiceLevelException(
serviceLevel, classification.getKey(), classification.getDomain());
}
}
private void validateAndPopulateParentInformation(ClassificationImpl classificationImpl)
throws InvalidArgumentException {
try {

View File

@ -19,6 +19,51 @@ import org.apache.ibatis.transaction.TransactionFactory;
public interface KadaiEngine {
String MINIMAL_KADAI_SCHEMA_VERSION = "7.1.0";
/**
* This method creates the {@linkplain KadaiEngine} with {@linkplain
* ConnectionManagementMode#PARTICIPATE}.
*
* @see KadaiEngine#buildKadaiEngine(KadaiConfiguration, ConnectionManagementMode)
*/
@SuppressWarnings("checkstyle:JavadocMethod")
static KadaiEngine buildKadaiEngine(KadaiConfiguration configuration) throws SQLException {
return buildKadaiEngine(configuration, ConnectionManagementMode.PARTICIPATE, null);
}
/**
* Builds an {@linkplain KadaiEngine} based on {@linkplain KadaiConfiguration} and
* SqlConnectionMode.
*
* @param configuration complete kadaiConfig to build the engine
* @param connectionManagementMode connectionMode for the SqlSession
* @return a {@linkplain KadaiEngineImpl}
* @throws SQLException when the db schema could not be initialized
*/
static KadaiEngine buildKadaiEngine(
KadaiConfiguration configuration, ConnectionManagementMode connectionManagementMode)
throws SQLException {
return buildKadaiEngine(configuration, connectionManagementMode, null);
}
/**
* Builds an {@linkplain KadaiEngine} based on {@linkplain KadaiConfiguration}, SqlConnectionMode
* and TransactionFactory.
*
* @param configuration complete kadaiConfig to build the engine
* @param connectionManagementMode connectionMode for the SqlSession
* @param transactionFactory the TransactionFactory
* @return a {@linkplain KadaiEngineImpl}
* @throws SQLException when the db schema could not be initialized
*/
static KadaiEngine buildKadaiEngine(
KadaiConfiguration configuration,
ConnectionManagementMode connectionManagementMode,
TransactionFactory transactionFactory)
throws SQLException {
return KadaiEngineImpl.createKadaiEngine(
configuration, connectionManagementMode, transactionFactory);
}
/**
* Returns a {@linkplain TaskService} initialized with the current KadaiEngine. {@linkplain
* TaskService} can be used for operations on all {@linkplain Task Tasks}.
@ -86,51 +131,6 @@ public interface KadaiEngine {
*/
KadaiConfiguration getConfiguration();
/**
* This method creates the {@linkplain KadaiEngine} with {@linkplain
* ConnectionManagementMode#PARTICIPATE}.
*
* @see KadaiEngine#buildKadaiEngine(KadaiConfiguration, ConnectionManagementMode)
*/
@SuppressWarnings("checkstyle:JavadocMethod")
static KadaiEngine buildKadaiEngine(KadaiConfiguration configuration) throws SQLException {
return buildKadaiEngine(configuration, ConnectionManagementMode.PARTICIPATE, null);
}
/**
* Builds an {@linkplain KadaiEngine} based on {@linkplain KadaiConfiguration} and
* SqlConnectionMode.
*
* @param configuration complete kadaiConfig to build the engine
* @param connectionManagementMode connectionMode for the SqlSession
* @return a {@linkplain KadaiEngineImpl}
* @throws SQLException when the db schema could not be initialized
*/
static KadaiEngine buildKadaiEngine(
KadaiConfiguration configuration, ConnectionManagementMode connectionManagementMode)
throws SQLException {
return buildKadaiEngine(configuration, connectionManagementMode, null);
}
/**
* Builds an {@linkplain KadaiEngine} based on {@linkplain KadaiConfiguration}, SqlConnectionMode
* and TransactionFactory.
*
* @param configuration complete kadaiConfig to build the engine
* @param connectionManagementMode connectionMode for the SqlSession
* @param transactionFactory the TransactionFactory
* @return a {@linkplain KadaiEngineImpl}
* @throws SQLException when the db schema could not be initialized
*/
static KadaiEngine buildKadaiEngine(
KadaiConfiguration configuration,
ConnectionManagementMode connectionManagementMode,
TransactionFactory transactionFactory)
throws SQLException {
return KadaiEngineImpl.createKadaiEngine(
configuration, connectionManagementMode, transactionFactory);
}
/**
* Returns the {@linkplain WorkingTimeCalculator} of the KadaiEngine. The {@linkplain
* WorkingTimeCalculator} is used to add or subtract working time from Instants according to a

View File

@ -49,14 +49,6 @@ public abstract class AbstractKadaiJob implements KadaiJob {
return initKadaiJob(engine, jobClass, txProvider, job);
}
@Override
public final void run() throws KadaiException {
execute();
if (async) {
scheduleNextJob();
}
}
/**
* Initializes the TaskCleanupJob schedule. <br>
* All scheduled cleanup jobs are cancelled/deleted and a new one is scheduled.
@ -76,46 +68,10 @@ public abstract class AbstractKadaiJob implements KadaiJob {
job.scheduleNextJob();
}
public boolean isAsync() {
return async;
}
public Instant getFirstRun() {
return firstRun;
}
public Duration getRunEvery() {
return runEvery;
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getJobLockExpirationPeriod();
}
protected abstract String getType();
protected abstract void execute() throws KadaiException;
protected Instant getNextDueForJob() {
Instant nextRun = firstRun;
if (scheduledJob != null && scheduledJob.getDue() != null) {
nextRun = scheduledJob.getDue();
}
while (nextRun.isBefore(Instant.now())) {
nextRun = nextRun.plus(runEvery);
}
return nextRun;
}
protected void scheduleNextJob() {
ScheduledJob job = new ScheduledJob();
job.setType(getType());
job.setDue(getNextDueForJob());
kadaiEngineImpl.getJobService().createJob(job);
}
private static AbstractKadaiJob initKadaiJob(
KadaiEngine kadaiEngine,
Class<?> jobClass,
@ -160,4 +116,48 @@ public abstract class AbstractKadaiJob implements KadaiJob {
}
return job;
}
@Override
public final void run() throws KadaiException {
execute();
if (async) {
scheduleNextJob();
}
}
public boolean isAsync() {
return async;
}
public Instant getFirstRun() {
return firstRun;
}
public Duration getRunEvery() {
return runEvery;
}
protected abstract String getType();
protected abstract void execute() throws KadaiException;
protected Instant getNextDueForJob() {
Instant nextRun = firstRun;
if (scheduledJob != null && scheduledJob.getDue() != null) {
nextRun = scheduledJob.getDue();
}
while (nextRun.isBefore(Instant.now())) {
nextRun = nextRun.plus(runEvery);
}
return nextRun;
}
protected void scheduleNextJob() {
ScheduledJob job = new ScheduledJob();
job.setType(getType());
job.setDue(getNextDueForJob());
kadaiEngineImpl.getJobService().createJob(job);
}
}

View File

@ -159,6 +159,79 @@ public class TaskServiceImpl implements TaskService {
this.objectReferenceHandler = new ObjectReferenceHandler(objectReferenceMapper);
}
private static Predicate<TaskSummaryImpl> addErrorToBulkLog(
CheckedConsumer<TaskSummaryImpl, KadaiException> checkedConsumer,
BulkOperationResults<String, KadaiException> bulkLog) {
return summary -> {
try {
checkedConsumer.accept(summary);
return true;
} catch (KadaiException e) {
bulkLog.addError(summary.getId(), e);
return false;
}
};
}
private static void terminateCancelCommonActions(TaskImpl task, TaskState targetState) {
Instant now = Instant.now();
task.setModified(now);
task.setCompleted(now);
task.setState(targetState);
}
private static void claimActionsOnTask(
TaskSummaryImpl task, String userId, String userLongName, Instant now) {
task.setOwner(userId);
task.setOwnerLongName(userLongName);
task.setModified(now);
task.setClaimed(now);
task.setRead(true);
if (Set.of(TaskState.READY_FOR_REVIEW, TaskState.IN_REVIEW).contains(task.getState())) {
task.setState(TaskState.IN_REVIEW);
} else {
task.setState(TaskState.CLAIMED);
}
}
private static void cancelClaimActionsOnTask(
TaskSummaryImpl task, Instant now, boolean keepOwner) {
if (!keepOwner) {
task.setOwner(null);
task.setOwnerLongName(null);
}
task.setModified(now);
task.setClaimed(null);
task.setRead(true);
if (task.getState() == TaskState.IN_REVIEW) {
task.setState(TaskState.READY_FOR_REVIEW);
} else {
task.setState(TaskState.READY);
}
}
private static void completeActionsOnTask(TaskSummaryImpl task, String userId, Instant now) {
task.setCompleted(now);
task.setModified(now);
task.setState(TaskState.COMPLETED);
task.setOwner(userId);
}
private static boolean taskIsNotClaimed(TaskSummary task) {
return task.getClaimed() == null
|| (task.getState() != TaskState.CLAIMED && task.getState() != TaskState.IN_REVIEW);
}
private static void checkIfTaskIsTerminatedOrCancelled(TaskSummary task)
throws InvalidTaskStateException {
if (task.getState().in(TaskState.CANCELLED, TaskState.TERMINATED)) {
throw new InvalidTaskStateException(
task.getId(),
task.getState(),
EnumUtil.allValuesExceptFor(TaskState.CANCELLED, TaskState.TERMINATED));
}
}
@Override
public Task claim(String taskId)
throws TaskNotFoundException,
@ -1346,20 +1419,6 @@ public class TaskServiceImpl implements TaskService {
.map(Pair::getRight);
}
private static Predicate<TaskSummaryImpl> addErrorToBulkLog(
CheckedConsumer<TaskSummaryImpl, KadaiException> checkedConsumer,
BulkOperationResults<String, KadaiException> bulkLog) {
return summary -> {
try {
checkedConsumer.accept(summary);
return true;
} catch (KadaiException e) {
bulkLog.addError(summary.getId(), e);
return false;
}
};
}
private void checkConcurrencyAndSetModified(TaskImpl newTaskImpl, TaskImpl oldTaskImpl)
throws ConcurrencyException {
// TODO: not safe to rely only on different timestamps.
@ -1375,13 +1434,6 @@ public class TaskServiceImpl implements TaskService {
newTaskImpl.setModified(Instant.now());
}
private static void terminateCancelCommonActions(TaskImpl task, TaskState targetState) {
Instant now = Instant.now();
task.setModified(now);
task.setCompleted(now);
task.setState(targetState);
}
private Task claim(String taskId, boolean forceClaim)
throws TaskNotFoundException,
InvalidOwnerException,
@ -1532,43 +1584,6 @@ public class TaskServiceImpl implements TaskService {
return task;
}
private static void claimActionsOnTask(
TaskSummaryImpl task, String userId, String userLongName, Instant now) {
task.setOwner(userId);
task.setOwnerLongName(userLongName);
task.setModified(now);
task.setClaimed(now);
task.setRead(true);
if (Set.of(TaskState.READY_FOR_REVIEW, TaskState.IN_REVIEW).contains(task.getState())) {
task.setState(TaskState.IN_REVIEW);
} else {
task.setState(TaskState.CLAIMED);
}
}
private static void cancelClaimActionsOnTask(
TaskSummaryImpl task, Instant now, boolean keepOwner) {
if (!keepOwner) {
task.setOwner(null);
task.setOwnerLongName(null);
}
task.setModified(now);
task.setClaimed(null);
task.setRead(true);
if (task.getState() == TaskState.IN_REVIEW) {
task.setState(TaskState.READY_FOR_REVIEW);
} else {
task.setState(TaskState.READY);
}
}
private static void completeActionsOnTask(TaskSummaryImpl task, String userId, Instant now) {
task.setCompleted(now);
task.setModified(now);
task.setState(TaskState.COMPLETED);
task.setOwner(userId);
}
private void checkPreconditionsForClaimTask(TaskSummary task, boolean forced)
throws InvalidOwnerException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException {
TaskState state = task.getState();
@ -1591,21 +1606,6 @@ public class TaskServiceImpl implements TaskService {
}
}
private static boolean taskIsNotClaimed(TaskSummary task) {
return task.getClaimed() == null
|| (task.getState() != TaskState.CLAIMED && task.getState() != TaskState.IN_REVIEW);
}
private static void checkIfTaskIsTerminatedOrCancelled(TaskSummary task)
throws InvalidTaskStateException {
if (task.getState().in(TaskState.CANCELLED, TaskState.TERMINATED)) {
throw new InvalidTaskStateException(
task.getId(),
task.getState(),
EnumUtil.allValuesExceptFor(TaskState.CANCELLED, TaskState.TERMINATED));
}
}
private void checkPreconditionsForCompleteTask(TaskSummary task)
throws InvalidOwnerException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException {
if (taskIsNotClaimed(task)) {

View File

@ -44,6 +44,10 @@ public class TaskCleanupJob extends AbstractKadaiJob {
kadaiEngine.getConfiguration().isTaskCleanupJobAllCompletedSameParentBusiness();
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getTaskCleanupJobLockExpirationPeriod();
}
@Override
public void execute() {
Instant completedBefore = Instant.now().minus(minimumAge);
@ -62,10 +66,6 @@ public class TaskCleanupJob extends AbstractKadaiJob {
}
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getTaskCleanupJobLockExpirationPeriod();
}
@Override
protected String getType() {
return TaskCleanupJob.class.getName();

View File

@ -32,6 +32,10 @@ public class TaskUpdatePriorityJob extends AbstractKadaiJob {
firstRun = kadaiEngine.getConfiguration().getTaskUpdatePriorityJobFirstRun();
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getTaskUpdatePriorityJobLockExpirationPeriod();
}
@Override
public void execute() {
TaskUpdatePriorityWorker worker = new TaskUpdatePriorityWorker(kadaiEngineImpl);
@ -45,10 +49,6 @@ public class TaskUpdatePriorityJob extends AbstractKadaiJob {
}
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getTaskUpdatePriorityJobLockExpirationPeriod();
}
public int getBatchSize() {
return batchSize;
}

View File

@ -26,6 +26,10 @@ public class TaskUpdatePriorityWorker {
priorityServiceManager = ((KadaiEngineImpl) kadaiEngine).getPriorityServiceManager();
}
public static IntPredicate hasDifferentPriority(TaskSummary taskSummary) {
return prio -> nonNull(taskSummary) && prio != taskSummary.getPriority();
}
public List<String> executeBatch(List<String> taskIds) {
List<String> updatedTaskIds = new ArrayList<>();
sqlConnectionRunner.runWithConnection(
@ -82,8 +86,4 @@ public class TaskUpdatePriorityWorker {
}
return OptionalInt.empty();
}
public static IntPredicate hasDifferentPriority(TaskSummary taskSummary) {
return prio -> nonNull(taskSummary) && prio != taskSummary.getPriority();
}
}

View File

@ -33,6 +33,24 @@ public class ObjectReferenceImpl implements ObjectReference {
value = copyFrom.value;
}
public static void validate(ObjectReference objectReference, String objRefType, String objName)
throws InvalidArgumentException {
// check that all values in the ObjectReference are set correctly
if (objectReference == null) {
throw new InvalidArgumentException(
String.format("%s of %s must not be null.", objRefType, objName));
} else if (objectReference.getCompany() == null || objectReference.getCompany().isEmpty()) {
throw new InvalidArgumentException(
String.format("Company of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getType() == null || objectReference.getType().length() == 0) {
throw new InvalidArgumentException(
String.format("Type of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getValue() == null || objectReference.getValue().length() == 0) {
throw new InvalidArgumentException(
String.format("Value of %s of %s must not be empty", objRefType, objName));
}
}
@Override
public String getId() {
return id;
@ -101,24 +119,6 @@ public class ObjectReferenceImpl implements ObjectReference {
return new ObjectReferenceImpl(this);
}
public static void validate(ObjectReference objectReference, String objRefType, String objName)
throws InvalidArgumentException {
// check that all values in the ObjectReference are set correctly
if (objectReference == null) {
throw new InvalidArgumentException(
String.format("%s of %s must not be null.", objRefType, objName));
} else if (objectReference.getCompany() == null || objectReference.getCompany().isEmpty()) {
throw new InvalidArgumentException(
String.format("Company of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getType() == null || objectReference.getType().length() == 0) {
throw new InvalidArgumentException(
String.format("Type of %s of %s must not be empty", objRefType, objName));
} else if (objectReference.getValue() == null || objectReference.getValue().length() == 0) {
throw new InvalidArgumentException(
String.format("Value of %s of %s must not be empty", objRefType, objName));
}
}
@Override
public int hashCode() {
return Objects.hash(id, taskId, company, system, systemInstance, type, value);

View File

@ -221,6 +221,10 @@ public class TaskSummaryImpl implements TaskSummary {
return this.groupByCount;
}
public void setGroupByCount(Integer n) {
groupByCount = n;
}
@Override
public Instant getDue() {
return due != null ? due.truncatedTo(ChronoUnit.MILLIS) : null;
@ -504,10 +508,6 @@ public class TaskSummaryImpl implements TaskSummary {
setWorkbasketSummary(workbasketSummary);
}
public void setGroupByCount(Integer n) {
groupByCount = n;
}
public void addAttachmentSummary(AttachmentSummary attachmentSummary) {
if (this.attachmentSummaries == null) {
this.attachmentSummaries = new ArrayList<>();

View File

@ -88,6 +88,17 @@ public class WorkbasketQueryImpl implements WorkbasketQuery {
this.callerRolesAndAccessIdsAlreadyHandled = false;
}
public static void lowercaseAccessIds(String[] accessIdArray) {
if (KadaiConfiguration.shouldUseLowerCaseForAccessIds()) {
for (int i = 0; i < accessIdArray.length; i++) {
String id = accessIdArray[i];
if (id != null) {
accessIdArray[i] = id.toLowerCase();
}
}
}
}
@Override
public WorkbasketQuery idIn(String... ids) {
if (ids != null && ids.length != 0) {
@ -644,17 +655,6 @@ public class WorkbasketQueryImpl implements WorkbasketQuery {
this.usedToAugmentTasks = usedToAugmentTasks;
}
public static void lowercaseAccessIds(String[] accessIdArray) {
if (KadaiConfiguration.shouldUseLowerCaseForAccessIds()) {
for (int i = 0; i < accessIdArray.length; i++) {
String id = accessIdArray[i];
if (id != null) {
accessIdArray[i] = id.toLowerCase();
}
}
}
}
private void validateAllTimeIntervals(TimeInterval[] intervals) {
for (TimeInterval ti : intervals) {
if (!ti.isValid()) {

View File

@ -34,6 +34,10 @@ public class WorkbasketCleanupJob extends AbstractKadaiJob {
batchSize = kadaiEngine.getConfiguration().getJobBatchSize();
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getWorkbasketCleanupJobLockExpirationPeriod();
}
@Override
public void execute() throws KadaiException {
LOGGER.info("Running job to delete all workbaskets marked for deletion");
@ -50,10 +54,6 @@ public class WorkbasketCleanupJob extends AbstractKadaiJob {
}
}
public static Duration getLockExpirationPeriod(KadaiConfiguration kadaiConfiguration) {
return kadaiConfiguration.getWorkbasketCleanupJobLockExpirationPeriod();
}
@Override
protected String getType() {
return WorkbasketCleanupJob.class.getName();

View File

@ -62,6 +62,16 @@ class KadaiTransactionIntTest {
@Autowired private JdbcTemplate jdbcTemplate;
@Autowired private KadaiEngine kadaiEngine;
private static ObjectReference createDefaultObjRef() {
ObjectReferenceImpl objRef = new ObjectReferenceImpl();
objRef.setCompany("company");
objRef.setSystem("system");
objRef.setSystemInstance("instance");
objRef.setType("type");
objRef.setValue("value");
return objRef;
}
@BeforeEach
void before() {
@ -231,16 +241,6 @@ class KadaiTransactionIntTest {
.doesNotThrowAnyException();
}
private static ObjectReference createDefaultObjRef() {
ObjectReferenceImpl objRef = new ObjectReferenceImpl();
objRef.setCompany("company");
objRef.setSystem("system");
objRef.setSystemInstance("instance");
objRef.setType("type");
objRef.setValue("value");
return objRef;
}
private void assertQuantities(int workbaskets, int tests) {
assertWorkbaskets(workbaskets);
assertCustomdbTests(tests);

View File

@ -1,5 +1,5 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">

View File

@ -16,6 +16,13 @@ import org.junit.platform.commons.JUnitException;
public class KadaiDependencyInjectionExtension
implements ParameterResolver, TestInstancePostProcessor {
@SuppressWarnings("unchecked")
private static Map<Class<?>, Object> getKadaiEntityMap(ExtensionContext extensionContext) {
return (Map<Class<?>, Object>)
getClassLevelStore(extensionContext)
.get(KadaiInitializationExtension.STORE_KADAI_ENTITY_MAP);
}
@Override
public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
@ -53,11 +60,4 @@ public class KadaiDependencyInjectionExtension
}
}
}
@SuppressWarnings("unchecked")
private static Map<Class<?>, Object> getKadaiEntityMap(ExtensionContext extensionContext) {
return (Map<Class<?>, Object>)
getClassLevelStore(extensionContext)
.get(KadaiInitializationExtension.STORE_KADAI_ENTITY_MAP);
}
}

View File

@ -58,51 +58,6 @@ public class KadaiInitializationExtension
public static final String STORE_KADAI_ENTITY_MAP = "kadaiEntityMap";
@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context)
throws Exception {
Class<?> testClass = testInstance.getClass();
if (isTopLevelClass(testClass)
|| isAnnotated(testClass, CleanKadaiContext.class)
|| isAnnotated(testClass, WithServiceProvider.class)
|| isAnnotated(testClass, WithServiceProviders.class)
|| testInstance instanceof KadaiConfigurationModifier) {
Store store = getClassLevelStore(context);
KadaiConfiguration.Builder kadaiConfigurationBuilder =
createDefaultKadaiConfigurationBuilder(store);
if (testInstance instanceof KadaiConfigurationModifier) {
KadaiConfigurationModifier modifier = (KadaiConfigurationModifier) testInstance;
kadaiConfigurationBuilder = modifier.modify(kadaiConfigurationBuilder);
}
KadaiEngine kadaiEngine;
try (MockedStatic<SpiLoader> staticMock = Mockito.mockStatic(SpiLoader.class)) {
ServiceProviderExtractor.extractServiceProviders(
testClass, extractEnclosingTestInstances(testInstance))
.forEach(
(spi, serviceProviders) ->
staticMock.when(() -> SpiLoader.load(spi)).thenReturn(serviceProviders));
kadaiEngine =
KadaiEngine.buildKadaiEngine(
kadaiConfigurationBuilder.build(), ConnectionManagementMode.AUTOCOMMIT);
}
store.put(STORE_KADAI_ENTITY_MAP, generateKadaiEntityMap(kadaiEngine));
}
}
@SuppressWarnings("unchecked")
@Override
public void preDestroyTestInstance(ExtensionContext context) {
if (isTopLevelClass(context.getRequiredTestClass())) {
Map<Class<?>, Object> entityMap =
(Map<Class<?>, Object>) getClassLevelStore(context).get(STORE_KADAI_ENTITY_MAP);
KadaiEngineImpl kadaiEngineImpl = (KadaiEngineImpl) entityMap.get(KadaiEngineImpl.class);
Optional.ofNullable(kadaiEngineImpl.getJobScheduler()).ifPresent(JobScheduler::stop);
}
}
private static Map<Class<?>, Object> extractEnclosingTestInstances(Object instance) {
HashMap<Class<?>, Object> instanceByClass = new HashMap<>();
while (instance != null) {
@ -175,4 +130,49 @@ public class KadaiInitializationExtension
return sqlSessionManager.getMapper(JobMapper.class);
}
@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context)
throws Exception {
Class<?> testClass = testInstance.getClass();
if (isTopLevelClass(testClass)
|| isAnnotated(testClass, CleanKadaiContext.class)
|| isAnnotated(testClass, WithServiceProvider.class)
|| isAnnotated(testClass, WithServiceProviders.class)
|| testInstance instanceof KadaiConfigurationModifier) {
Store store = getClassLevelStore(context);
KadaiConfiguration.Builder kadaiConfigurationBuilder =
createDefaultKadaiConfigurationBuilder(store);
if (testInstance instanceof KadaiConfigurationModifier) {
KadaiConfigurationModifier modifier = (KadaiConfigurationModifier) testInstance;
kadaiConfigurationBuilder = modifier.modify(kadaiConfigurationBuilder);
}
KadaiEngine kadaiEngine;
try (MockedStatic<SpiLoader> staticMock = Mockito.mockStatic(SpiLoader.class)) {
ServiceProviderExtractor.extractServiceProviders(
testClass, extractEnclosingTestInstances(testInstance))
.forEach(
(spi, serviceProviders) ->
staticMock.when(() -> SpiLoader.load(spi)).thenReturn(serviceProviders));
kadaiEngine =
KadaiEngine.buildKadaiEngine(
kadaiConfigurationBuilder.build(), ConnectionManagementMode.AUTOCOMMIT);
}
store.put(STORE_KADAI_ENTITY_MAP, generateKadaiEntityMap(kadaiEngine));
}
}
@SuppressWarnings("unchecked")
@Override
public void preDestroyTestInstance(ExtensionContext context) {
if (isTopLevelClass(context.getRequiredTestClass())) {
Map<Class<?>, Object> entityMap =
(Map<Class<?>, Object>) getClassLevelStore(context).get(STORE_KADAI_ENTITY_MAP);
KadaiEngineImpl kadaiEngineImpl = (KadaiEngineImpl) entityMap.get(KadaiEngineImpl.class);
Optional.ofNullable(kadaiEngineImpl.getJobScheduler()).ifPresent(JobScheduler::stop);
}
}
}

View File

@ -41,35 +41,6 @@ public class TestContainerExtension implements InvocationInterceptor {
}
}
@Override
public <T> T interceptTestClassConstructor(
Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext,
ExtensionContext extensionContext)
throws Throwable {
Class<?> testClass = extensionContext.getRequiredTestClass();
if (isTopLevelClass(testClass) || isAnnotated(testClass, CleanKadaiContext.class)) {
Store store = getClassLevelStore(extensionContext);
String schemaName = determineSchemaName();
store.put(STORE_SCHEMA_NAME, schemaName);
store.put(STORE_DATA_SOURCE, DATA_SOURCE);
if (DB.ORACLE == EXECUTION_DATABASE) {
initOracleSchema(DATA_SOURCE, schemaName);
}
} else if (KadaiConfigurationModifier.class.isAssignableFrom(testClass)
|| isAnnotated(testClass, WithServiceProvider.class)) {
// since the implementation of KadaiConfigurationModifier implies the generation of a
// new KadaiEngine, we have to copy the schema name and datasource from the enclosing class'
// store to the testClass store.
// This allows the following extensions to generate a new KadaiEngine for the testClass.
Store parentStore = getClassLevelStore(extensionContext, testClass.getEnclosingClass());
Store store = getClassLevelStore(extensionContext);
copyValue(TestContainerExtension.STORE_SCHEMA_NAME, parentStore, store);
copyValue(TestContainerExtension.STORE_DATA_SOURCE, parentStore, store);
}
return invocation.proceed();
}
public static DataSource createDataSourceForH2() {
PooledDataSource ds =
new PooledDataSource(
@ -113,4 +84,33 @@ public class TestContainerExtension implements InvocationInterceptor {
}
return db;
}
@Override
public <T> T interceptTestClassConstructor(
Invocation<T> invocation,
ReflectiveInvocationContext<Constructor<T>> invocationContext,
ExtensionContext extensionContext)
throws Throwable {
Class<?> testClass = extensionContext.getRequiredTestClass();
if (isTopLevelClass(testClass) || isAnnotated(testClass, CleanKadaiContext.class)) {
Store store = getClassLevelStore(extensionContext);
String schemaName = determineSchemaName();
store.put(STORE_SCHEMA_NAME, schemaName);
store.put(STORE_DATA_SOURCE, DATA_SOURCE);
if (DB.ORACLE == EXECUTION_DATABASE) {
initOracleSchema(DATA_SOURCE, schemaName);
}
} else if (KadaiConfigurationModifier.class.isAssignableFrom(testClass)
|| isAnnotated(testClass, WithServiceProvider.class)) {
// since the implementation of KadaiConfigurationModifier implies the generation of a
// new KadaiEngine, we have to copy the schema name and datasource from the enclosing class'
// store to the testClass store.
// This allows the following extensions to generate a new KadaiEngine for the testClass.
Store parentStore = getClassLevelStore(extensionContext, testClass.getEnclosingClass());
Store store = getClassLevelStore(extensionContext);
copyValue(TestContainerExtension.STORE_SCHEMA_NAME, parentStore, store);
copyValue(TestContainerExtension.STORE_DATA_SOURCE, parentStore, store);
}
return invocation.proceed();
}
}

View File

@ -48,6 +48,64 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
// region InvocationInterceptor
private static void persistDynamicContainerChildren(
Iterable<DynamicNode> nodes, Map<String, List<DynamicNode>> childrenMap) {
nodes.forEach(
node -> {
if (node instanceof DynamicContainer container) {
List<DynamicNode> children = container.getChildren().collect(Collectors.toList());
childrenMap.put(container.hashCode() + container.getDisplayName(), children);
persistDynamicContainerChildren(children, childrenMap);
}
});
}
private static DynamicNode duplicateDynamicNode(
DynamicNode node, Map<String, List<DynamicNode>> lookupMap) {
if (node instanceof DynamicContainer container) {
Stream<DynamicNode> children =
lookupMap.get(node.hashCode() + node.getDisplayName()).stream()
.map(x -> duplicateDynamicNode(x, lookupMap));
return DynamicContainer.dynamicContainer(container.getDisplayName(), children);
}
return node;
}
private static <T> T extractAccessIdAndPerformInvocation(
Invocation<T> invocation, AnnotatedElement executable) {
return performInvocationWithAccessId(invocation, executable.getAnnotation(WithAccessId.class));
}
private static <T> T performInvocationWithAccessId(
Invocation<T> invocation, WithAccessId withAccessId) {
Subject subject = new Subject();
subject.getPrincipals().addAll(getPrincipals(withAccessId));
Function<Invocation<T>, T> proceedInvocation =
wrapExceptFor(Invocation::proceed, TestAbortedException.class);
PrivilegedAction<T> performInvocation = () -> proceedInvocation.apply(invocation);
return Subject.doAs(subject, performInvocation);
}
private static List<Principal> getPrincipals(WithAccessId withAccessId) {
if (withAccessId != null) {
return Stream.concat(
Stream.of(withAccessId.user()).map(UserPrincipal::new),
Arrays.stream(withAccessId.groups()).map(GroupPrincipal::new))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
private static Store getMethodLevelStore(ExtensionContext context) {
return context.getStore(
Namespace.create(context.getRequiredTestClass(), context.getRequiredTestMethod()));
}
private static String getDisplayNameForAccessId(WithAccessId withAccessId) {
return String.format("for user '%s'", withAccessId.user());
}
@Override
public <T> T interceptTestClassConstructor(
Invocation<T> invocation,
@ -64,6 +122,10 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
// region TestTemplateInvocationContextProvider
@Override
public void interceptBeforeEachMethod(
Invocation<Void> invocation,
@ -83,6 +145,8 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
@Override
@SuppressWarnings("unchecked")
public <T> T interceptTestFactoryMethod(
@ -190,10 +254,6 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
extractAccessIdAndPerformInvocation(invocation, invocationContext.getExecutable());
}
// endregion
// region TestTemplateInvocationContextProvider
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return isAnnotated(context.getElement(), WithAccessIds.class)
@ -211,57 +271,6 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
.map(JaasExtensionInvocationContext::new);
}
// endregion
private static void persistDynamicContainerChildren(
Iterable<DynamicNode> nodes, Map<String, List<DynamicNode>> childrenMap) {
nodes.forEach(
node -> {
if (node instanceof DynamicContainer container) {
List<DynamicNode> children = container.getChildren().collect(Collectors.toList());
childrenMap.put(container.hashCode() + container.getDisplayName(), children);
persistDynamicContainerChildren(children, childrenMap);
}
});
}
private static DynamicNode duplicateDynamicNode(
DynamicNode node, Map<String, List<DynamicNode>> lookupMap) {
if (node instanceof DynamicContainer container) {
Stream<DynamicNode> children =
lookupMap.get(node.hashCode() + node.getDisplayName()).stream()
.map(x -> duplicateDynamicNode(x, lookupMap));
return DynamicContainer.dynamicContainer(container.getDisplayName(), children);
}
return node;
}
private static <T> T extractAccessIdAndPerformInvocation(
Invocation<T> invocation, AnnotatedElement executable) {
return performInvocationWithAccessId(invocation, executable.getAnnotation(WithAccessId.class));
}
private static <T> T performInvocationWithAccessId(
Invocation<T> invocation, WithAccessId withAccessId) {
Subject subject = new Subject();
subject.getPrincipals().addAll(getPrincipals(withAccessId));
Function<Invocation<T>, T> proceedInvocation =
wrapExceptFor(Invocation::proceed, TestAbortedException.class);
PrivilegedAction<T> performInvocation = () -> proceedInvocation.apply(invocation);
return Subject.doAs(subject, performInvocation);
}
private static List<Principal> getPrincipals(WithAccessId withAccessId) {
if (withAccessId != null) {
return Stream.concat(
Stream.of(withAccessId.user()).map(UserPrincipal::new),
Arrays.stream(withAccessId.groups()).map(GroupPrincipal::new))
.collect(Collectors.toList());
}
return Collections.emptyList();
}
private ExtensionContext getParentMethodExtensionContent(ExtensionContext extensionContext) {
Optional<ExtensionContext> parent = extensionContext.getParent();
// the class MethodExtensionContext is part of junit-jupiter-engine and has only a
@ -280,15 +289,6 @@ public class JaasExtension implements InvocationInterceptor, TestTemplateInvocat
"Test '%s' does not have a parent method", extensionContext.getUniqueId())));
}
private static Store getMethodLevelStore(ExtensionContext context) {
return context.getStore(
Namespace.create(context.getRequiredTestClass(), context.getRequiredTestMethod()));
}
private static String getDisplayNameForAccessId(WithAccessId withAccessId) {
return String.format("for user '%s'", withAccessId.user());
}
private static class JaasExtensionInvocationContext implements TestTemplateInvocationContext {
private final WithAccessId withAccessId;

View File

@ -65,6 +65,28 @@ class JaasExtensionTest {
// region JaasExtension#interceptBeforeEachMethod
@AfterAll
static void should_NotSetJaasSubject_When_AnnotationIsMissing_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
@WithAccessId(user = "afterall")
@AfterAll
static void should_SetJaasSubject_When_AnnotationExists_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("afterall");
}
@WithAccessId(user = "afterall")
@WithAccessId(user = "afterall2")
@AfterAll
static void should_NotSetJaasSubject_When_MultipleAnnotationsExist_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
// endregion
// region JaasExtension#interceptAfterEachMethod
@BeforeEach
void should_NotSetJaasSubject_When_AnnotationIsMissing_On_BeforeEach() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
@ -85,7 +107,7 @@ class JaasExtensionTest {
// endregion
// region JaasExtension#interceptAfterEachMethod
// region JaasExtension#interceptAfterAllMethod
@AfterEach
void should_NotSetJaasSubject_When_AnnotationIsMissing_On_AfterEach() {
@ -107,28 +129,6 @@ class JaasExtensionTest {
// endregion
// region JaasExtension#interceptAfterAllMethod
@AfterAll
static void should_NotSetJaasSubject_When_AnnotationIsMissing_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
@WithAccessId(user = "afterall")
@AfterAll
static void should_SetJaasSubject_When_AnnotationExists_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isEqualTo("afterall");
}
@WithAccessId(user = "afterall")
@WithAccessId(user = "afterall2")
@AfterAll
static void should_NotSetJaasSubject_When_MultipleAnnotationsExist_On_AfterAll() {
assertThat(CURRENT_USER_CONTEXT.getUserid()).isNull();
}
// endregion
// region JaasExtension#interceptTestMethod
@Test

View File

@ -45,7 +45,7 @@
<!-- build dependencies -->
<version.checkstyle>10.17.0</version.checkstyle>
<version.google-java-format>1.20.0</version.google-java-format>
<version.google-java-format>1.23.0</version.google-java-format>
<version.maven.checkstyle>3.4.0</version.maven.checkstyle>
<version.maven.jar>3.4.2</version.maven.jar>
<version.maven.war>3.4.0</version.maven.war>

View File

@ -43,8 +43,7 @@ public class ExampleRestConfiguration {
@Bean
@DependsOn("generateSampleData")
public KadaiEngine getKadaiEngine(KadaiConfiguration kadaiConfiguration)
throws SQLException {
public KadaiEngine getKadaiEngine(KadaiConfiguration kadaiConfiguration) throws SQLException {
return SpringKadaiEngine.buildKadaiEngine(kadaiConfiguration);
}

View File

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<link rel="icon" type="image/x-icon" th:href="@{/img/logo.png}">
<link rel="icon" th:href="@{/img/logo.png}" type="image/x-icon">
<title>Kadai login</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap/4.1.3/bootstrap.min.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/main.css}"/>
<link rel="stylesheet" th:href="@{/css/bootstrap/4.1.3/bootstrap.min.css}" type="text/css"/>
<link rel="stylesheet" th:href="@{/css/main.css}" type="text/css"/>
</head>
<body>
@ -12,12 +12,12 @@
<h1 class="row justify-content-center">Welcome to Kadai</h1>
<div class="row justify-content-center">
<div>
<img th:src="@{/img/logo.png}" class="logo" alt="memorynotfound logo"/>
<img alt="memorynotfound logo" class="logo" th:src="@{/img/logo.png}"/>
</div>
</div>
<div class="row justify-content-center align-items-center">
<div class="col-xs-12 col-md-6">
<form th:action="@{/login}" method="post">
<form method="post" th:action="@{/login}">
<div th:if="${param.error}">
<div class="alert alert-danger">
Invalid username or password.
@ -30,28 +30,28 @@
</div>
<div class="form-group">
<label for="username">Username</label>:
<input type="text"
<input autofocus="autofocus"
class="form-control"
id="username"
name="username"
class="form-control"
autofocus="autofocus"
placeholder="Username">
placeholder="Username"
type="text">
</div>
<div class="form-group">
<label for="password">Password</label>:
<input type="password"
<input class="form-control"
id="password"
name="password"
class="form-control"
placeholder="Password">
placeholder="Password"
type="password">
</div>
<div class="form-group">
<div class="row justify-content-center">
<div class="col-sm-6 col-sm-offset-3">
<input type="submit"
name="login-submit"
<input class="form-control btn btn-info"
id="login-submit"
class="form-control btn btn-info"
name="login-submit"
type="submit"
value="Log In">
</div>
</div>

View File

@ -13,8 +13,7 @@ import org.springframework.test.context.TestPropertySource;
@KadaiSpringBootTest
@TestPropertySource(properties = "kadai.ldap.useDnForGroups=false")
@ActiveProfiles({"emptySearchRoots"})
class LdapEmptySearchRootsForUseDnForGroupsDisabledTest
extends LdapForUseDnForGroupsDisabledTest {
class LdapEmptySearchRootsForUseDnForGroupsDisabledTest extends LdapForUseDnForGroupsDisabledTest {
@Test
void should_FindGroupsForUser_When_UserIdIsProvided() throws Exception {
@ -22,8 +21,7 @@ class LdapEmptySearchRootsForUseDnForGroupsDisabledTest
ldapClient.searchGroupsAccessIdIsMemberOf("user-2-2");
assertThat(groups)
.extracting(AccessIdRepresentationModel::getAccessId)
.containsExactlyInAnyOrder(
"ksc-users", "organisationseinheit ksc 2");
.containsExactlyInAnyOrder("ksc-users", "organisationseinheit ksc 2");
}
@Test
@ -32,8 +30,8 @@ class LdapEmptySearchRootsForUseDnForGroupsDisabledTest
ldapClient.searchPermissionsAccessIdHas("user-1-2");
assertThat(permissions)
.extracting(AccessIdRepresentationModel::getAccessId)
.containsExactlyInAnyOrder("kadai:callcenter:ab:ab/a:callcenter",
"kadai:callcenter:ab:ab/a:callcenter-vip");
.containsExactlyInAnyOrder(
"kadai:callcenter:ab:ab/a:callcenter", "kadai:callcenter:ab:ab/a:callcenter-vip");
}
@Test
@ -48,4 +46,3 @@ class LdapEmptySearchRootsForUseDnForGroupsDisabledTest
assertThat(dn).isEqualTo("cn=g02,cn=groups,ou=test,o=kadai");
}
}

View File

@ -54,12 +54,12 @@ class LdapTest {
ldapClient.searchPermissionsAccessIdHas("user-1-2");
assertThat(permissions)
.extracting(AccessIdRepresentationModel::getAccessId)
.containsExactlyInAnyOrder("kadai:callcenter:ab:ab/a:callcenter-vip",
"kadai:callcenter:ab:ab/a:callcenter");
.containsExactlyInAnyOrder(
"kadai:callcenter:ab:ab/a:callcenter-vip", "kadai:callcenter:ab:ab/a:callcenter");
assertThat(permissions)
.extracting(AccessIdRepresentationModel::getName)
.containsExactlyInAnyOrder("Kadai:CallCenter:AB:AB/A:CallCenter-vip",
"Kadai:CallCenter:AB:AB/A:CallCenter");
.containsExactlyInAnyOrder(
"Kadai:CallCenter:AB:AB/A:CallCenter-vip", "Kadai:CallCenter:AB:AB/A:CallCenter");
}
@Test

View File

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<link rel="icon" type="image/x-icon" th:href="@{/img/logo.png}">
<link rel="icon" th:href="@{/img/logo.png}" type="image/x-icon">
<title>Kadai login</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap/4.1.3/bootstrap.min.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/main.css}"/>
<link rel="stylesheet" th:href="@{/css/bootstrap/4.1.3/bootstrap.min.css}" type="text/css"/>
<link rel="stylesheet" th:href="@{/css/main.css}" type="text/css"/>
</head>
<body>
@ -12,7 +12,7 @@
<h1 class="row justify-content-center">Welcome to Kadai</h1>
<div class="row justify-content-center">
<div>
<img th:src="@{/img/logo.png}" class="logo" alt="memorynotfound logo"/>
<img alt="memorynotfound logo" class="logo" th:src="@{/img/logo.png}"/>
</div>
</div>
<div class="row justify-content-center align-items-center">
@ -30,28 +30,28 @@
</div>
<div class="form-group">
<label for="username">Username</label>:
<input type="text"
<input autofocus="autofocus"
class="form-control"
id="username"
name="j_username"
class="form-control"
autofocus="autofocus"
placeholder="Username">
placeholder="Username"
type="text">
</div>
<div class="form-group">
<label for="password">Password</label>:
<input type="password"
<input class="form-control"
id="password"
name="j_password"
class="form-control"
placeholder="Password">
placeholder="Password"
type="password">
</div>
<div class="form-group">
<div class="row justify-content-center">
<div class="col-sm-6 col-sm-offset-3">
<input type="submit"
name="login-submit"
<input class="form-control btn btn-info"
id="login-submit"
class="form-control btn btn-info"
name="login-submit"
type="submit"
value="Log In">
</div>
</div>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web version="7.2"
<jboss-web xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="7.2"
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_7_2.xsd">
<context-root>/kadai</context-root>
<security-domain>kadaiApplicationDomain</security-domain>

View File

@ -1,6 +1,6 @@
<web-app version="3.1"
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

View File

@ -38,16 +38,6 @@ public class RestHelper {
this.port = port;
}
public String toUrl(String relativeUrl, Object... uriVariables) {
return UriComponentsBuilder.fromPath(relativeUrl)
.scheme("http")
.host("127.0.0.1")
.port(getPort())
.build(false)
.expand(uriVariables)
.toString();
}
public static HttpHeaders generateHeadersForUser(String user) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", encodeUserAndPasswordAsBasicAuth(user));
@ -60,12 +50,6 @@ public class RestHelper {
return "Basic " + Base64.getEncoder().encodeToString(toEncode.getBytes(StandardCharsets.UTF_8));
}
private int getPort() {
return Optional.ofNullable(environment)
.map(e -> e.getRequiredProperty("local.server.port", int.class))
.orElse(port);
}
/**
* Return a REST template which is capable of dealing with responses in HAL format.
*
@ -89,4 +73,20 @@ public class RestHelper {
template.getMessageConverters().add(0, converter);
return template;
}
public String toUrl(String relativeUrl, Object... uriVariables) {
return UriComponentsBuilder.fromPath(relativeUrl)
.scheme("http")
.host("127.0.0.1")
.port(getPort())
.build(false)
.expand(uriVariables)
.toString();
}
private int getPort() {
return Optional.ofNullable(environment)
.map(e -> e.getRequiredProperty("local.server.port", int.class))
.orElse(port);
}
}

View File

@ -35,61 +35,6 @@ public class AbstractAccTest {
protected RestHelper restHelper = new RestHelper(8080);
protected TaskRepresentationModel getTaskResourceSample() {
ClassificationSummaryRepresentationModel classificationResource =
new ClassificationSummaryRepresentationModel();
classificationResource.setKey("L11010");
WorkbasketSummaryRepresentationModel workbasketSummary =
new WorkbasketSummaryRepresentationModel();
workbasketSummary.setWorkbasketId("WBI:100000000000000000000000000000000004");
ObjectReferenceRepresentationModel objectReference = new ObjectReferenceRepresentationModel();
objectReference.setCompany("MyCompany1");
objectReference.setSystem("MySystem1");
objectReference.setSystemInstance("MyInstance1");
objectReference.setType("MyType1");
objectReference.setValue("00000001");
TaskRepresentationModel taskRepresentationModel = new TaskRepresentationModel();
taskRepresentationModel.setClassificationSummary(classificationResource);
taskRepresentationModel.setWorkbasketSummary(workbasketSummary);
taskRepresentationModel.setPrimaryObjRef(objectReference);
return taskRepresentationModel;
}
protected ResponseEntity<TaskHistoryEventPagedRepresentationModel>
performGetHistoryEventsRestCall() {
return RestHelper.TEMPLATE.exchange(
restHelper.toUrl("/kadai" + HistoryRestEndpoints.URL_HISTORY_EVENTS),
HttpMethod.GET,
new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
}
protected ResponseEntity<TaskRepresentationModel> performCreateTaskRestCall() {
TaskRepresentationModel taskRepresentationModel = getTaskResourceSample();
return RestHelper.TEMPLATE.exchange(
restHelper.toUrl("/kadai" + RestEndpoints.URL_TASKS),
HttpMethod.POST,
new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")),
ParameterizedTypeReference.forType(TaskRepresentationModel.class));
}
protected String parseServerLog() throws Exception {
// TO-DO: make log4j log into rollingFile from log4j.xml
File file = new File("target/wildfly-31.0.1.Final/standalone/log/server.log");
BufferedReader br = new BufferedReader(new FileReader(file));
String str;
StringBuilder stringBuilder = new StringBuilder();
while ((str = br.readLine()) != null) {
stringBuilder.append(str);
}
return stringBuilder.toString();
}
private static void stopPostgresDb() {
try {
boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
@ -148,4 +93,59 @@ public class AbstractAccTest {
+ standardError);
}
}
protected TaskRepresentationModel getTaskResourceSample() {
ClassificationSummaryRepresentationModel classificationResource =
new ClassificationSummaryRepresentationModel();
classificationResource.setKey("L11010");
WorkbasketSummaryRepresentationModel workbasketSummary =
new WorkbasketSummaryRepresentationModel();
workbasketSummary.setWorkbasketId("WBI:100000000000000000000000000000000004");
ObjectReferenceRepresentationModel objectReference = new ObjectReferenceRepresentationModel();
objectReference.setCompany("MyCompany1");
objectReference.setSystem("MySystem1");
objectReference.setSystemInstance("MyInstance1");
objectReference.setType("MyType1");
objectReference.setValue("00000001");
TaskRepresentationModel taskRepresentationModel = new TaskRepresentationModel();
taskRepresentationModel.setClassificationSummary(classificationResource);
taskRepresentationModel.setWorkbasketSummary(workbasketSummary);
taskRepresentationModel.setPrimaryObjRef(objectReference);
return taskRepresentationModel;
}
protected ResponseEntity<TaskHistoryEventPagedRepresentationModel>
performGetHistoryEventsRestCall() {
return RestHelper.TEMPLATE.exchange(
restHelper.toUrl("/kadai" + HistoryRestEndpoints.URL_HISTORY_EVENTS),
HttpMethod.GET,
new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")),
ParameterizedTypeReference.forType(TaskHistoryEventPagedRepresentationModel.class));
}
protected ResponseEntity<TaskRepresentationModel> performCreateTaskRestCall() {
TaskRepresentationModel taskRepresentationModel = getTaskResourceSample();
return RestHelper.TEMPLATE.exchange(
restHelper.toUrl("/kadai" + RestEndpoints.URL_TASKS),
HttpMethod.POST,
new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")),
ParameterizedTypeReference.forType(TaskRepresentationModel.class));
}
protected String parseServerLog() throws Exception {
// TO-DO: make log4j log into rollingFile from log4j.xml
File file = new File("target/wildfly-31.0.1.Final/standalone/log/server.log");
BufferedReader br = new BufferedReader(new FileReader(file));
String str;
StringBuilder stringBuilder = new StringBuilder();
while ((str = br.readLine()) != null) {
stringBuilder.append(str);
}
return stringBuilder.toString();
}
}

View File

@ -102,8 +102,7 @@ public class KadaiWildflyTest extends AbstractAccTest {
ResponseEntity<TaskRepresentationModel> response =
TEMPLATE.exchange(
restHelper.toUrl(
"/kadai" + RestEndpoints.URL_TASKS_ID,
"TKI:000000000000000000000000000000000001"),
"/kadai" + RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000001"),
HttpMethod.GET,
new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")),
ParameterizedTypeReference.forType(TaskRepresentationModel.class));

View File

@ -117,8 +117,7 @@ public class KadaiWildflyWithUserConfigTest extends AbstractAccTest {
ResponseEntity<TaskRepresentationModel> response =
TEMPLATE.exchange(
restHelper.toUrl(
"/kadai" + RestEndpoints.URL_TASKS_ID,
"TKI:000000000000000000000000000000000005"),
"/kadai" + RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000005"),
HttpMethod.GET,
new HttpEntity<>(headers),
ParameterizedTypeReference.forType(TaskRepresentationModel.class));

View File

@ -1,5 +1,5 @@
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<defaultProtocol type="Servlet 6.0"/>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web version="7.2"
<jboss-web xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="7.2"
xmlns="http://www.jboss.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_7_2.xsd">
<context-root>/kadai</context-root>
<security-domain>kadaiApplicationDomain</security-domain>

View File

@ -1,6 +1,6 @@
<web-app version="3.1"
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>kadai-rest-spring-test-lib</artifactId>

View File

@ -38,16 +38,6 @@ public class RestHelper {
this.port = port;
}
public String toUrl(String relativeUrl, Object... uriVariables) {
return UriComponentsBuilder.fromPath(relativeUrl)
.scheme("http")
.host("127.0.0.1")
.port(getPort())
.build(false)
.expand(uriVariables)
.toString();
}
public static HttpHeaders generateHeadersForUser(String user) {
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", encodeUserAndPasswordAsBasicAuth(user));
@ -60,12 +50,6 @@ public class RestHelper {
return "Basic " + Base64.getEncoder().encodeToString(toEncode.getBytes(StandardCharsets.UTF_8));
}
private int getPort() {
return Optional.ofNullable(environment)
.map(e -> e.getRequiredProperty("local.server.port", int.class))
.orElse(port);
}
/**
* Return a REST template which is capable of dealing with responses in HAL format.
*
@ -89,4 +73,20 @@ public class RestHelper {
template.getMessageConverters().add(0, converter);
return template;
}
public String toUrl(String relativeUrl, Object... uriVariables) {
return UriComponentsBuilder.fromPath(relativeUrl)
.scheme("http")
.host("127.0.0.1")
.port(getPort())
.build(false)
.expand(uriVariables)
.toString();
}
private int getPort() {
return Optional.ofNullable(environment)
.map(e -> e.getRequiredProperty("local.server.port", int.class))
.orElse(port);
}
}

View File

@ -16,62 +16,6 @@ import java.util.stream.Stream;
public class ClassificationQueryFilterParameter
implements QueryParameter<ClassificationQuery, Void> {
public String[] getName() {
return name;
}
public String[] getNameLike() {
return nameLike;
}
public String[] getKey() {
return key;
}
public String[] getCategory() {
return category;
}
public String[] getDomain() {
return domain;
}
public String[] getType() {
return type;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom4Like() {
return custom4Like;
}
public String[] getCustom5Like() {
return custom5Like;
}
public String[] getCustom6Like() {
return custom6Like;
}
public String[] getCustom7Like() {
return custom7Like;
}
public String[] getCustom8Like() {
return custom8Like;
}
@Schema(
name = "name",
description = "Filter by the name of the Classification. This is an exact match.")
@ -164,6 +108,7 @@ public class ClassificationQueryFilterParameter
+ "wildcard characters will be resolved correctly.")
@JsonProperty("custom-6-like")
private final String[] custom6Like;
@Schema(
name = "custom-7-like",
description =
@ -234,6 +179,62 @@ public class ClassificationQueryFilterParameter
this.custom8Like = custom8Like;
}
public String[] getName() {
return name;
}
public String[] getNameLike() {
return nameLike;
}
public String[] getKey() {
return key;
}
public String[] getCategory() {
return category;
}
public String[] getDomain() {
return domain;
}
public String[] getType() {
return type;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom4Like() {
return custom4Like;
}
public String[] getCustom5Like() {
return custom5Like;
}
public String[] getCustom6Like() {
return custom6Like;
}
public String[] getCustom7Like() {
return custom7Like;
}
public String[] getCustom8Like() {
return custom8Like;
}
@Override
public Void apply(ClassificationQuery query) {
Optional.ofNullable(name).ifPresent(query::nameIn);

View File

@ -12,16 +12,18 @@ public class ClassificationRepresentationModel extends ClassificationSummaryRepr
name = "isValidInDomain",
description = "True, if this classification to objects in this domain.")
private Boolean isValidInDomain;
@Schema(
name = "created",
description =
"The creation timestamp of the classification in the system.<p>The format is ISO-8601.")
private Instant created;
@Schema(
name = "modified",
description = "The timestamp of the last modification.<p>The format is ISO-8601."
)
description = "The timestamp of the last modification.<p>The format is ISO-8601.")
private Instant modified;
@Schema(name = "description", description = "The description of the classification.")
private String description;

View File

@ -122,17 +122,14 @@ public class KadaiRestExceptionHandler extends ResponseEntityExceptionHandler {
MaxUploadSizeExceededException ex,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request
) {
WebRequest request) {
return buildResponse(
ErrorCode.of(ERROR_KEY_PAYLOAD),
ex,
request,
HTTP_STATUS_BY_ERROR_CODE_KEY.getOrDefault(
ERROR_KEY_PAYLOAD, HttpStatus.INTERNAL_SERVER_ERROR
)
);
ERROR_KEY_PAYLOAD, HttpStatus.INTERNAL_SERVER_ERROR));
}
@ExceptionHandler(BeanInstantiationException.class)

View File

@ -12,14 +12,6 @@ import java.util.List;
public class QueryPagingParameter<T, Q extends BaseQuery<T, ?>>
implements QueryParameter<Q, List<T>> {
public Integer getPage() {
return page;
}
public Integer getPageSize() {
return pageSize;
}
@Schema(
name = "page",
description = "Request a specific page. Requires the definition of the 'page-size'.")
@ -46,6 +38,14 @@ public class QueryPagingParameter<T, Q extends BaseQuery<T, ?>>
this.pageSize = pageSize;
}
public Integer getPage() {
return page;
}
public Integer getPageSize() {
return pageSize;
}
public PageMetadata getPageMetadata() {
return pageMetadata;
}

View File

@ -38,18 +38,6 @@ public class QuerySortParameter<Q extends BaseQuery<?, ?>, S extends QuerySortBy
verifyAmountOfSortByAndOrderByMatches(sortBy, order);
}
@Override
public Void apply(Q query) {
if (sortBy != null) {
for (int i = 0; i < sortBy.size(); i++) {
SortDirection sortDirection =
order == null || order.isEmpty() ? SortDirection.ASCENDING : order.get(i);
sortBy.get(i).applySortByForQuery(query, sortDirection);
}
}
return null;
}
// this method is only static because there exists no query for the task comment entity
public static <T> void verifyAmountOfSortByAndOrderByMatches(
List<T> sortBy, List<SortDirection> order) throws InvalidArgumentException {
@ -69,6 +57,18 @@ public class QuerySortParameter<Q extends BaseQuery<?, ?>, S extends QuerySortBy
}
}
@Override
public Void apply(Q query) {
if (sortBy != null) {
for (int i = 0; i < sortBy.size(); i++) {
SortDirection sortDirection =
order == null || order.isEmpty() ? SortDirection.ASCENDING : order.get(i);
sortBy.get(i).applySortByForQuery(query, sortDirection);
}
}
return null;
}
@JsonProperty("sort-by")
public List<S> getSortBy() {
return sortBy;

View File

@ -72,8 +72,7 @@ public class RestConfiguration {
@Bean
@ConditionalOnMissingBean(KadaiEngine.class)
public KadaiEngine getKadaiEngine(KadaiConfiguration kadaiConfiguration)
throws SQLException {
public KadaiEngine getKadaiEngine(KadaiConfiguration kadaiConfiguration) throws SQLException {
return SpringKadaiEngine.buildKadaiEngine(kadaiConfiguration);
}

View File

@ -243,8 +243,7 @@ public class LdapClient {
List<AccessIdRepresentationModel> permissions = new ArrayList<>();
List<String> accessIdsOfPermissions = new ArrayList<>();
for (String groupOrPermission : dns) {
accessIdsOfGroupsAndPermissions.add(searchAccessIdByDn(groupOrPermission)
.getAccessId());
accessIdsOfGroupsAndPermissions.add(searchAccessIdByDn(groupOrPermission).getAccessId());
}
for (String groupOrPermission : accessIdsOfGroupsAndPermissions) {
permissions.addAll(searchPermissionsByName(groupOrPermission));
@ -266,8 +265,8 @@ public class LdapClient {
testMinSearchForLength(name);
final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getPermissionSearchFilterName(),
getPermissionSearchFilterValue()));
andFilter.and(
new EqualsFilter(getPermissionSearchFilterName(), getPermissionSearchFilterValue()));
final OrFilter orFilter = new OrFilter();
orFilter.or(new WhitespaceWildcardsFilter(getUserPermissionsAttribute(), name));
if (!CN.equals(getUserPermissionsAttribute())) {
@ -356,8 +355,8 @@ public class LdapClient {
}
final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getPermissionSearchFilterName(),
getPermissionSearchFilterValue()));
andFilter.and(
new EqualsFilter(getPermissionSearchFilterName(), getPermissionSearchFilterValue()));
final OrFilter orFilter = new OrFilter();
if (!"DN".equalsIgnoreCase(getPermissionsOfUserType())) {
orFilter.or(new EqualsFilter(getPermissionsOfUserName(), accessId));
@ -451,8 +450,8 @@ public class LdapClient {
private List<String> searchDnForPermissionAccessId(String accessId) {
final AndFilter andFilter = new AndFilter();
andFilter.and(new EqualsFilter(getPermissionSearchFilterName(),
getPermissionSearchFilterValue()));
andFilter.and(
new EqualsFilter(getPermissionSearchFilterName(), getPermissionSearchFilterValue()));
final OrFilter orFilter = new OrFilter();
orFilter.or(new EqualsFilter(getUserPermissionsAttribute(), accessId));
final AndFilter andFilterPermission2 = new AndFilter();
@ -652,8 +651,7 @@ public class LdapClient {
}
public boolean useDnForGroups() {
String envValue =
LdapSettings.KADAI_LDAP_USE_DN_FOR_GROUPS.getValueFromEnv(env);
String envValue = LdapSettings.KADAI_LDAP_USE_DN_FOR_GROUPS.getValueFromEnv(env);
if (envValue == null || envValue.isEmpty()) {
return true;
}
@ -738,18 +736,15 @@ public class LdapClient {
}
String[] getLookUpPermissionAttributesToReturn() {
return new String[] {
getUserPermissionsAttribute(),
getPermissionSearchFilterName()
};
return new String[] {getUserPermissionsAttribute(), getPermissionSearchFilterName()};
}
String[] getLookUpUserAndGroupAndPermissionAttributesToReturn() {
return Stream.concat(Stream.concat(
return Stream.concat(
Stream.concat(
Arrays.stream(getLookUpUserAttributesToReturn()),
Arrays.stream(getLookUpGroupAttributesToReturn())),
Arrays.stream(getLookUpPermissionAttributesToReturn())
)
Arrays.stream(getLookUpPermissionAttributesToReturn()))
.toArray(String[]::new);
}

View File

@ -11,21 +11,14 @@ import org.springframework.lang.NonNull;
public class KadaiUserInfoRepresentationModel
extends RepresentationModel<KadaiUserInfoRepresentationModel> {
@Schema(
name = "userId",
description = "The user Id of the current user."
)
@Schema(name = "userId", description = "The user Id of the current user.")
private String userId;
@Schema(
name = "groupIds",
description = "All groups the current user is a member of."
)
@Schema(name = "groupIds", description = "All groups the current user is a member of.")
private List<String> groupIds = new ArrayList<>();
/** All permissions the current user has. */
@Schema(
name = "roles",
description = "All permissions the current user has."
)
@Schema(name = "roles", description = "All permissions the current user has.")
private List<KadaiRole> roles = new ArrayList<>();
public String getUserId() {

View File

@ -6,226 +6,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
import java.beans.ConstructorProperties;
public class ReportFilterParameter {
public Boolean getInWorkingDays() {
return inWorkingDays;
}
public String[] getWorkbasketId() {
return workbasketId;
}
public TaskState[] getState() {
return state;
}
public String[] getClassificationCategory() {
return classificationCategory;
}
public String[] getDomain() {
return domain;
}
public String[] getClassificationId() {
return classificationId;
}
public String[] getExcludedClassificationId() {
return excludedClassificationId;
}
public String[] getCustom1() {
return custom1;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom1NotIn() {
return custom1NotIn;
}
public String[] getCustom2() {
return custom2;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom2NotIn() {
return custom2NotIn;
}
public String[] getCustom3() {
return custom3;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom3NotIn() {
return custom3NotIn;
}
public String[] getCustom4() {
return custom4;
}
public String[] getCustom4Like() {
return custom4Like;
}
public String[] getCustom4NotIn() {
return custom4NotIn;
}
public String[] getCustom5() {
return custom5;
}
public String[] getCustom5Like() {
return custom5Like;
}
public String[] getCustom5NotIn() {
return custom5NotIn;
}
public String[] getCustom6() {
return custom6;
}
public String[] getCustom6Like() {
return custom6Like;
}
public String[] getCustom6NotIn() {
return custom6NotIn;
}
public String[] getCustom7() {
return custom7;
}
public String[] getCustom7Like() {
return custom7Like;
}
public String[] getCustom7NotIn() {
return custom7NotIn;
}
public String[] getCustom8() {
return custom8;
}
public String[] getCustom8Like() {
return custom8Like;
}
public String[] getCustom8NotIn() {
return custom8NotIn;
}
public String[] getCustom9() {
return custom9;
}
public String[] getCustom9Like() {
return custom9Like;
}
public String[] getCustom9NotIn() {
return custom9NotIn;
}
public String[] getCustom10() {
return custom10;
}
public String[] getCustom10Like() {
return custom10Like;
}
public String[] getCustom10NotIn() {
return custom10NotIn;
}
public String[] getCustom11() {
return custom11;
}
public String[] getCustom11Like() {
return custom11Like;
}
public String[] getCustom11NotIn() {
return custom11NotIn;
}
public String[] getCustom12() {
return custom12;
}
public String[] getCustom12Like() {
return custom12Like;
}
public String[] getCustom12NotIn() {
return custom12NotIn;
}
public String[] getCustom13() {
return custom13;
}
public String[] getCustom13Like() {
return custom13Like;
}
public String[] getCustom13NotIn() {
return custom13NotIn;
}
public String[] getCustom14() {
return custom14;
}
public String[] getCustom14Like() {
return custom14Like;
}
public String[] getCustom14NotIn() {
return custom14NotIn;
}
public String[] getCustom15() {
return custom15;
}
public String[] getCustom15Like() {
return custom15Like;
}
public String[] getCustom15NotIn() {
return custom15NotIn;
}
public String[] getCustom16() {
return custom16;
}
public String[] getCustom16Like() {
return custom16Like;
}
public String[] getCustom16NotIn() {
return custom16NotIn;
}
@Schema(
name = "in-working-days",
description =
@ -793,4 +573,224 @@ public class ReportFilterParameter {
this.custom16Like = custom16Like;
this.custom16NotIn = custom16NotIn;
}
public Boolean getInWorkingDays() {
return inWorkingDays;
}
public String[] getWorkbasketId() {
return workbasketId;
}
public TaskState[] getState() {
return state;
}
public String[] getClassificationCategory() {
return classificationCategory;
}
public String[] getDomain() {
return domain;
}
public String[] getClassificationId() {
return classificationId;
}
public String[] getExcludedClassificationId() {
return excludedClassificationId;
}
public String[] getCustom1() {
return custom1;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom1NotIn() {
return custom1NotIn;
}
public String[] getCustom2() {
return custom2;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom2NotIn() {
return custom2NotIn;
}
public String[] getCustom3() {
return custom3;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom3NotIn() {
return custom3NotIn;
}
public String[] getCustom4() {
return custom4;
}
public String[] getCustom4Like() {
return custom4Like;
}
public String[] getCustom4NotIn() {
return custom4NotIn;
}
public String[] getCustom5() {
return custom5;
}
public String[] getCustom5Like() {
return custom5Like;
}
public String[] getCustom5NotIn() {
return custom5NotIn;
}
public String[] getCustom6() {
return custom6;
}
public String[] getCustom6Like() {
return custom6Like;
}
public String[] getCustom6NotIn() {
return custom6NotIn;
}
public String[] getCustom7() {
return custom7;
}
public String[] getCustom7Like() {
return custom7Like;
}
public String[] getCustom7NotIn() {
return custom7NotIn;
}
public String[] getCustom8() {
return custom8;
}
public String[] getCustom8Like() {
return custom8Like;
}
public String[] getCustom8NotIn() {
return custom8NotIn;
}
public String[] getCustom9() {
return custom9;
}
public String[] getCustom9Like() {
return custom9Like;
}
public String[] getCustom9NotIn() {
return custom9NotIn;
}
public String[] getCustom10() {
return custom10;
}
public String[] getCustom10Like() {
return custom10Like;
}
public String[] getCustom10NotIn() {
return custom10NotIn;
}
public String[] getCustom11() {
return custom11;
}
public String[] getCustom11Like() {
return custom11Like;
}
public String[] getCustom11NotIn() {
return custom11NotIn;
}
public String[] getCustom12() {
return custom12;
}
public String[] getCustom12Like() {
return custom12Like;
}
public String[] getCustom12NotIn() {
return custom12NotIn;
}
public String[] getCustom13() {
return custom13;
}
public String[] getCustom13Like() {
return custom13Like;
}
public String[] getCustom13NotIn() {
return custom13NotIn;
}
public String[] getCustom14() {
return custom14;
}
public String[] getCustom14Like() {
return custom14Like;
}
public String[] getCustom14NotIn() {
return custom14NotIn;
}
public String[] getCustom15() {
return custom15;
}
public String[] getCustom15Like() {
return custom15Like;
}
public String[] getCustom15NotIn() {
return custom15NotIn;
}
public String[] getCustom16() {
return custom16;
}
public String[] getCustom16Like() {
return custom16Like;
}
public String[] getCustom16NotIn() {
return custom16NotIn;
}
}

View File

@ -13,8 +13,10 @@ public class ReportRepresentationModel extends RepresentationModel<ReportReprese
@Schema(name = "meta", description = "Object holding meta info on the report.")
private final MetaInformation meta;
@Schema(name = "rows", description = "Array holding the rows of the report.")
private final List<RowRepresentationModel> rows;
@Schema(name = "sumRow", description = "Array holding the sums in the columns over all rows.")
private final List<RowRepresentationModel> sumRow;
@ -46,15 +48,19 @@ public class ReportRepresentationModel extends RepresentationModel<ReportReprese
@Schema(name = "cells", description = "Array holding all the cell values of the given row.")
private final int[] cells;
@Schema(name = "cells", description = "Sum of all values of the given row.")
private final int total;
@Schema(
name = "depth",
description =
"Depth of the row. If the depth is > 0, then this row is a sub-row of a prior row")
private final int depth;
@Schema(name = "desc", description = "Array containing description of the row.")
private final String[] desc;
@Schema(
name = "display",
description = "Boolean identifying if the given row should be initially displayed or not.")
@ -111,12 +117,16 @@ public class ReportRepresentationModel extends RepresentationModel<ReportReprese
@Schema(name = "name", description = "Name of the report.")
private final String name;
@Schema(name = "date", description = "Date of the report creation.")
private final Instant date;
@Schema(name = "header", description = "Column headers of the report.")
private final String[] header;
@Schema(name = "rowDesc", description = "Descriptions for the rows of the report.")
private final String[] rowDesc;
@Schema(name = "sumRowDesc", description = "Description for the sum column.")
private final String sumRowDesc;

View File

@ -1373,8 +1373,7 @@ public class TaskController {
List<String> taskIdsToDelete = taskSummaries.stream().map(TaskSummary::getId).toList();
BulkOperationResults<String, KadaiException> result =
taskService.deleteTasks(taskIdsToDelete);
BulkOperationResults<String, KadaiException> result = taskService.deleteTasks(taskIdsToDelete);
Set<String> failedIds = new HashSet<>(result.getFailedIds());
List<TaskSummary> successfullyDeletedTaskSummaries =

View File

@ -29,262 +29,6 @@ import java.util.Optional;
import java.util.stream.Stream;
public class TaskQueryFilterCustomFields implements QueryParameter<TaskQuery, Void> {
public String[] getCustom1In() {
return custom1In;
}
public String[] getCustom1NotIn() {
return custom1NotIn;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom1NotLike() {
return custom1NotLike;
}
public String[] getCustom2In() {
return custom2In;
}
public String[] getCustom2NotIn() {
return custom2NotIn;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom2NotLike() {
return custom2NotLike;
}
public String[] getCustom3In() {
return custom3In;
}
public String[] getCustom3NotIn() {
return custom3NotIn;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom3NotLike() {
return custom3NotLike;
}
public String[] getCustom4In() {
return custom4In;
}
public String[] getCustom4NotIn() {
return custom4NotIn;
}
public String[] getCustom4Like() {
return custom4Like;
}
public String[] getCustom4NotLike() {
return custom4NotLike;
}
public String[] getCustom5In() {
return custom5In;
}
public String[] getCustom5NotIn() {
return custom5NotIn;
}
public String[] getCustom5Like() {
return custom5Like;
}
public String[] getCustom5NotLike() {
return custom5NotLike;
}
public String[] getCustom6In() {
return custom6In;
}
public String[] getCustom6NotIn() {
return custom6NotIn;
}
public String[] getCustom6Like() {
return custom6Like;
}
public String[] getCustom6NotLike() {
return custom6NotLike;
}
public String[] getCustom7In() {
return custom7In;
}
public String[] getCustom7NotIn() {
return custom7NotIn;
}
public String[] getCustom7Like() {
return custom7Like;
}
public String[] getCustom7NotLike() {
return custom7NotLike;
}
public String[] getCustom8In() {
return custom8In;
}
public String[] getCustom8NotIn() {
return custom8NotIn;
}
public String[] getCustom8Like() {
return custom8Like;
}
public String[] getCustom8NotLike() {
return custom8NotLike;
}
public String[] getCustom9In() {
return custom9In;
}
public String[] getCustom9NotIn() {
return custom9NotIn;
}
public String[] getCustom9Like() {
return custom9Like;
}
public String[] getCustom9NotLike() {
return custom9NotLike;
}
public String[] getCustom10In() {
return custom10In;
}
public String[] getCustom10NotIn() {
return custom10NotIn;
}
public String[] getCustom10Like() {
return custom10Like;
}
public String[] getCustom10NotLike() {
return custom10NotLike;
}
public String[] getCustom11In() {
return custom11In;
}
public String[] getCustom11NotIn() {
return custom11NotIn;
}
public String[] getCustom11Like() {
return custom11Like;
}
public String[] getCustom11NotLike() {
return custom11NotLike;
}
public String[] getCustom12In() {
return custom12In;
}
public String[] getCustom12NotIn() {
return custom12NotIn;
}
public String[] getCustom12Like() {
return custom12Like;
}
public String[] getCustom12NotLike() {
return custom12NotLike;
}
public String[] getCustom13In() {
return custom13In;
}
public String[] getCustom13NotIn() {
return custom13NotIn;
}
public String[] getCustom13Like() {
return custom13Like;
}
public String[] getCustom13NotLike() {
return custom13NotLike;
}
public String[] getCustom14In() {
return custom14In;
}
public String[] getCustom14NotIn() {
return custom14NotIn;
}
public String[] getCustom14Like() {
return custom14Like;
}
public String[] getCustom14NotLike() {
return custom14NotLike;
}
public String[] getCustom15In() {
return custom15In;
}
public String[] getCustom15NotIn() {
return custom15NotIn;
}
public String[] getCustom15Like() {
return custom15Like;
}
public String[] getCustom15NotLike() {
return custom15NotLike;
}
public String[] getCustom16In() {
return custom16In;
}
public String[] getCustom16NotIn() {
return custom16NotIn;
}
public String[] getCustom16Like() {
return custom16Like;
}
public String[] getCustom16NotLike() {
return custom16NotLike;
}
@Schema(
name = "custom-1",
description = "Filter by the value of the field custom1 of the Task. This is an exact match.")
@ -982,6 +726,262 @@ public class TaskQueryFilterCustomFields implements QueryParameter<TaskQuery, Vo
this.custom16NotLike = custom16NotLike;
}
public String[] getCustom1In() {
return custom1In;
}
public String[] getCustom1NotIn() {
return custom1NotIn;
}
public String[] getCustom1Like() {
return custom1Like;
}
public String[] getCustom1NotLike() {
return custom1NotLike;
}
public String[] getCustom2In() {
return custom2In;
}
public String[] getCustom2NotIn() {
return custom2NotIn;
}
public String[] getCustom2Like() {
return custom2Like;
}
public String[] getCustom2NotLike() {
return custom2NotLike;
}
public String[] getCustom3In() {
return custom3In;
}
public String[] getCustom3NotIn() {
return custom3NotIn;
}
public String[] getCustom3Like() {
return custom3Like;
}
public String[] getCustom3NotLike() {
return custom3NotLike;
}
public String[] getCustom4In() {
return custom4In;
}
public String[] getCustom4NotIn() {
return custom4NotIn;
}
public String[] getCustom4Like() {
return custom4Like;
}
public String[] getCustom4NotLike() {
return custom4NotLike;
}
public String[] getCustom5In() {
return custom5In;
}
public String[] getCustom5NotIn() {
return custom5NotIn;
}
public String[] getCustom5Like() {
return custom5Like;
}
public String[] getCustom5NotLike() {
return custom5NotLike;
}
public String[] getCustom6In() {
return custom6In;
}
public String[] getCustom6NotIn() {
return custom6NotIn;
}
public String[] getCustom6Like() {
return custom6Like;
}
public String[] getCustom6NotLike() {
return custom6NotLike;
}
public String[] getCustom7In() {
return custom7In;
}
public String[] getCustom7NotIn() {
return custom7NotIn;
}
public String[] getCustom7Like() {
return custom7Like;
}
public String[] getCustom7NotLike() {
return custom7NotLike;
}
public String[] getCustom8In() {
return custom8In;
}
public String[] getCustom8NotIn() {
return custom8NotIn;
}
public String[] getCustom8Like() {
return custom8Like;
}
public String[] getCustom8NotLike() {
return custom8NotLike;
}
public String[] getCustom9In() {
return custom9In;
}
public String[] getCustom9NotIn() {
return custom9NotIn;
}
public String[] getCustom9Like() {
return custom9Like;
}
public String[] getCustom9NotLike() {
return custom9NotLike;
}
public String[] getCustom10In() {
return custom10In;
}
public String[] getCustom10NotIn() {
return custom10NotIn;
}
public String[] getCustom10Like() {
return custom10Like;
}
public String[] getCustom10NotLike() {
return custom10NotLike;
}
public String[] getCustom11In() {
return custom11In;
}
public String[] getCustom11NotIn() {
return custom11NotIn;
}
public String[] getCustom11Like() {
return custom11Like;
}
public String[] getCustom11NotLike() {
return custom11NotLike;
}
public String[] getCustom12In() {
return custom12In;
}
public String[] getCustom12NotIn() {
return custom12NotIn;
}
public String[] getCustom12Like() {
return custom12Like;
}
public String[] getCustom12NotLike() {
return custom12NotLike;
}
public String[] getCustom13In() {
return custom13In;
}
public String[] getCustom13NotIn() {
return custom13NotIn;
}
public String[] getCustom13Like() {
return custom13Like;
}
public String[] getCustom13NotLike() {
return custom13NotLike;
}
public String[] getCustom14In() {
return custom14In;
}
public String[] getCustom14NotIn() {
return custom14NotIn;
}
public String[] getCustom14Like() {
return custom14Like;
}
public String[] getCustom14NotLike() {
return custom14NotLike;
}
public String[] getCustom15In() {
return custom15In;
}
public String[] getCustom15NotIn() {
return custom15NotIn;
}
public String[] getCustom15Like() {
return custom15Like;
}
public String[] getCustom15NotLike() {
return custom15NotLike;
}
public String[] getCustom16In() {
return custom16In;
}
public String[] getCustom16NotIn() {
return custom16NotIn;
}
public String[] getCustom16Like() {
return custom16Like;
}
public String[] getCustom16NotLike() {
return custom16NotLike;
}
@Override
public Void apply(TaskQuery query) {
Stream.of(

View File

@ -10,6 +10,54 @@ import java.util.Optional;
import java.util.function.Consumer;
public class TaskQueryGroupByParameter implements QueryParameter<TaskQuery, Void> {
// region groupBy
@JsonProperty("group-by")
@Schema(name = "group-by")
private final TaskQueryGroupBy groupByPor;
@JsonProperty("group-by-sor")
@Schema(name = "group-by-sor")
private final String groupBySor;
@ConstructorProperties({"group-by", "group-by-sor"})
public TaskQueryGroupByParameter(TaskQueryGroupBy groupBy, String groupBySor)
throws InvalidArgumentException {
this.groupByPor = groupBy;
this.groupBySor = groupBySor;
validateGroupByParameters();
}
public String getGroupBySor() {
return groupBySor;
}
public TaskQueryGroupBy getGroupByPor() {
return groupByPor;
}
// endregion
// region constructor
@Override
public Void apply(TaskQuery query) {
Optional.ofNullable(groupBySor).ifPresent(query::groupBySor);
Optional.ofNullable(groupByPor)
.ifPresent(taskQueryGroupBy -> taskQueryGroupBy.applyGroupByForQuery(query));
return null;
}
// endregion
private void validateGroupByParameters() throws InvalidArgumentException {
if (groupByPor != null && groupBySor != null) {
throw new InvalidArgumentException(
"Only one of the following can be provided: Either group-by or group-by-sor");
}
}
public enum TaskQueryGroupBy {
POR_VALUE(TaskQuery::groupByPor);
private final Consumer<TaskQuery> consumer;
@ -22,55 +70,4 @@ public class TaskQueryGroupByParameter implements QueryParameter<TaskQuery, Void
consumer.accept(query);
}
}
public String getGroupBySor() {
return groupBySor;
}
public TaskQueryGroupBy getGroupByPor() {
return groupByPor;
}
// region groupBy
@JsonProperty("group-by")
@Schema(
name = "group-by"
)
private final TaskQueryGroupBy groupByPor;
@JsonProperty("group-by-sor")
@Schema(
name = "group-by-sor"
)
private final String groupBySor;
// endregion
// region constructor
@ConstructorProperties({"group-by", "group-by-sor"})
public TaskQueryGroupByParameter(TaskQueryGroupBy groupBy, String groupBySor)
throws InvalidArgumentException {
this.groupByPor = groupBy;
this.groupBySor = groupBySor;
validateGroupByParameters();
}
// endregion
@Override
public Void apply(TaskQuery query) {
Optional.ofNullable(groupBySor).ifPresent(query::groupBySor);
Optional.ofNullable(groupByPor)
.ifPresent(taskQueryGroupBy -> taskQueryGroupBy.applyGroupByForQuery(query));
return null;
}
private void validateGroupByParameters() throws InvalidArgumentException {
if (groupByPor != null && groupBySor != null) {
throw new InvalidArgumentException(
"Only one of the following can be provided: Either group-by or group-by-sor");
}
}
}

View File

@ -13,8 +13,7 @@ import org.springframework.stereotype.Component;
@Component
public class BulkOperationResultsRepresentationModelAssembler
implements RepresentationModelAssembler<
BulkOperationResults<String, KadaiException>,
BulkOperationResultsRepresentationModel> {
BulkOperationResults<String, KadaiException>, BulkOperationResultsRepresentationModel> {
@NonNull
@Override

View File

@ -11,18 +11,25 @@ public class AttachmentSummaryRepresentationModel
@Schema(name = "attachmentId", description = "Unique Id.")
protected String attachmentId;
@Schema(name = "taskId", description = "The referenced task id.")
protected String taskId;
@Schema(name = "created", description = "The creation timestamp in the system.")
protected Instant created;
@Schema(name = "modified", description = "The timestamp of the last modification.")
protected Instant modified;
@Schema(name = "received", description = "The timestamp of the entry date.")
protected Instant received;
@Schema(name = "classificationSummary", description = "The classification of this attachment.")
protected ClassificationSummaryRepresentationModel classificationSummary;
@Schema(name = "objectReference", description = "The Objects primary ObjectReference.")
protected ObjectReferenceRepresentationModel objectReference;
@Schema(
name = "channel",
description = "Determines on which channel this attachment was received.")

Some files were not shown because too many files have changed in this diff Show More